diff --git a/Docs/Generated/Oxide.Ext.Discord.md b/Docs/Generated/Oxide.Ext.Discord.md index ba7015da7..e10dcb18d 100644 --- a/Docs/Generated/Oxide.Ext.Discord.md +++ b/Docs/Generated/Oxide.Ext.Discord.md @@ -42,7 +42,7 @@ | class [MessageComponentBuilder](./Oxide.Ext.Discord/Builders/MessageComponentBuilder.md) | Builder for Message Components | | [Flags] enum [PlayerDisplayNameMode](./Oxide.Ext.Discord/Builders/PlayerDisplayNameMode.md) | Player Name Formatting options for [`PlayerNameFormatter`](./Oxide.Ext.Discord/Builders/PlayerNameFormatter.md) | | class [PlayerNameFormatter](./Oxide.Ext.Discord/Builders/PlayerNameFormatter.md) | Formatter for player names | -| class [QueryStringBuilder](./Oxide.Ext.Discord/Builders/QueryStringBuilder.md) | Builder used to build query strings for urls | +| struct [QueryStringBuilder](./Oxide.Ext.Discord/Builders/QueryStringBuilder.md) | Builder used to build query strings for urls | | class [SelectMenuComponentBuilder](./Oxide.Ext.Discord/Builders/SelectMenuComponentBuilder.md) | Builder for Select Menus | | class [WebhookMessageBuilder](./Oxide.Ext.Discord/Builders/WebhookMessageBuilder.md) | Represents a builder for [`WebhookMessageBuilder`](./Oxide.Ext.Discord/Builders/WebhookMessageBuilder.md) | @@ -79,8 +79,10 @@ | public type | description | | --- | --- | -| class [BotClient](./Oxide.Ext.Discord/Clients/BotClient.md) | Represents a bot that is connected to discord | -| class [DiscordClient](./Oxide.Ext.Discord/Clients/DiscordClient.md) | Represents the object a plugin uses to connects to discord | +| abstract class [BaseClient](./Oxide.Ext.Discord/Clients/BaseClient.md) | BaseClient that can connect to discord | +| class [BotClient](./Oxide.Ext.Discord/Clients/BotClient.md) | Represents a bot connected to discord | +| class [DiscordClient](./Oxide.Ext.Discord/Clients/DiscordClient.md) | Represents the object a plugin uses to connect to discord | +| class [WebhookClient](./Oxide.Ext.Discord/Clients/WebhookClient.md) | A client that can connect to a webhook | ## Oxide.Ext.Discord.Connections namespace @@ -88,6 +90,7 @@ | --- | --- | | class [BotConnection](./Oxide.Ext.Discord/Connections/BotConnection.md) | Bot Connection Settings | | class [BotTokenData](./Oxide.Ext.Discord/Connections/BotTokenData.md) | Represents the parsed Bot Token data | +| class [WebhookConnection](./Oxide.Ext.Discord/Connections/WebhookConnection.md) | Connection for a webhook | ## Oxide.Ext.Discord.Constants namespace @@ -113,7 +116,12 @@ | class [AllowedMentions](./Oxide.Ext.Discord/Entities/AllowedMentions.md) | Represents a [Allowed Mention Types](https://discord.com/developers/docs/resources/channel#allowed-mentions-object) | | enum [AllowedMentionTypes](./Oxide.Ext.Discord/Entities/AllowedMentionTypes.md) | Represents a [Allowed Mention Types](https://discord.com/developers/docs/resources/channel#allowed-mentions-object-allowed-mention-types) for a message | | enum [ApplicationCommandType](./Oxide.Ext.Discord/Entities/ApplicationCommandType.md) | Represents [Application Command Type](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-types) | +| class [ApplicationEmojiCreate](./Oxide.Ext.Discord/Entities/ApplicationEmojiCreate.md) | Represents [Application Emoji Create Structure](https://discord.com/developers/docs/resources/emoji#create-application-emoji-json-params) | +| class [ApplicationEmojis](./Oxide.Ext.Discord/Entities/ApplicationEmojis.md) | Represents [Application Emojis](https://discord.com/developers/docs/resources/emoji#list-application-emojis) | +| class [ApplicationEmojiUpdate](./Oxide.Ext.Discord/Entities/ApplicationEmojiUpdate.md) | Represents [Emoji Update Structure](https://discord.com/developers/docs/resources/emoji#modify-guild-emoji-json-params) | | [Flags] enum [ApplicationFlags](./Oxide.Ext.Discord/Entities/ApplicationFlags.md) | Represents [Application Flags](https://discord.com/developers/docs/resources/application#application-object-application-flags) | +| enum [ApplicationIntegrationType](./Oxide.Ext.Discord/Entities/ApplicationIntegrationType.md) | Represents a [Application Integration Types](https://discord.com/developers/docs/resources/application#application-object-application-integration-types) | +| class [ApplicationIntegrationTypeConfiguration](./Oxide.Ext.Discord/Entities/ApplicationIntegrationTypeConfiguration.md) | Represents a [Application Integration Type Configuration](https://discord.com/developers/docs/resources/application#application-object-application-integration-type-configuration-object) | | class [ApplicationRoleConnectionMetadata](./Oxide.Ext.Discord/Entities/ApplicationRoleConnectionMetadata.md) | Represents [Application Role Connection Metadata Structure](https://discord.com/developers/docs/resources/application-role-connection-metadata#application-role-connection-metadata-object-application-role-connection-metadata-structure) | | enum [ApplicationRoleConnectionMetadataType](./Oxide.Ext.Discord/Entities/ApplicationRoleConnectionMetadataType.md) | Represents [Application Role Connection Metadata Type](Application Role Connection Metadata Structure) | | class [ApplicationUpdate](./Oxide.Ext.Discord/Entities/ApplicationUpdate.md) | Represents [Edit Application Structure](https://discord.com/developers/docs/resources/application#edit-current-application-json-params) | @@ -129,6 +137,7 @@ | class [AutoModRuleModify](./Oxide.Ext.Discord/Entities/AutoModRuleModify.md) | Represents [Auto Mod Rule Modify](https://discord.com/developers/docs/resources/auto-moderation#modify-auto-moderation-rule-json-params) | | class [AutoModTriggerMetadata](./Oxide.Ext.Discord/Entities/AutoModTriggerMetadata.md) | Represents [Auto Mod Trigger Metadata](https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata) | | enum [AutoModTriggerType](./Oxide.Ext.Discord/Entities/AutoModTriggerType.md) | Represents [Auto Mod Trigger Types](https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types) | +| class [AvatarDecorationData](./Oxide.Ext.Discord/Entities/AvatarDecorationData.md) | Represents [Avatar Decoration Structure](https://discord.com/developers/docs/resources/user#avatar-decoration-data-object-avatar-decoration-data-structure) | | abstract class [BaseComponent](./Oxide.Ext.Discord/Entities/BaseComponent.md) | Represents [Message Component](https://discord.com/developers/docs/interactions/message-components#component-object) within discord | | abstract class [BaseInteractableComponent](./Oxide.Ext.Discord/Entities/BaseInteractableComponent.md) | Represent a MessageComponent that can be interacted with | | abstract class [BaseInteractionMessage](./Oxide.Ext.Discord/Entities/BaseInteractionMessage.md) | Represents a Base Message for an interaction | @@ -182,6 +191,7 @@ | class [DiscordInteraction](./Oxide.Ext.Discord/Entities/DiscordInteraction.md) | Represents [Interaction Structure](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-structure) | | class [DiscordInvite](./Oxide.Ext.Discord/Entities/DiscordInvite.md) | Represents an [Invite Structure](https://discord.com/developers/docs/resources/invite#invite-object) that when used, adds a user to a guild or group DM channel. | | class [DiscordMessage](./Oxide.Ext.Discord/Entities/DiscordMessage.md) | Represents a [Message Structure](https://discord.com/developers/docs/resources/channel#message-object) sent in a channel within Discord.. | +| class [DiscordPoll](./Oxide.Ext.Discord/Entities/DiscordPoll.md) | Represents a [Discord Poll](https://discord.com/developers/docs/resources/poll#poll-object-poll-object-structure) | | class [DiscordRole](./Oxide.Ext.Discord/Entities/DiscordRole.md) | Represents [Role Structure](https://discord.com/developers/docs/topics/permissions#role-object) | | class [DiscordSku](./Oxide.Ext.Discord/Entities/DiscordSku.md) | Represents a [SKU Structure](https://discord.com/developers/docs/monetization/skus#sku-object-sku-structure) | | enum [DiscordSkuType](./Oxide.Ext.Discord/Entities/DiscordSkuType.md) | Represents a [Discord SKU Types](https://discord.com/developers/docs/monetization/skus#sku-object-sku-types) | @@ -213,6 +223,8 @@ | class [GatewayReadyEvent](./Oxide.Ext.Discord/Entities/GatewayReadyEvent.md) | Represents [Ready](https://discord.com/developers/docs/topics/gateway#ready) The ready event is dispatched when a client has completed the initial handshake with the gateway (for new sessions) | | class [GatewayResumedEvent](./Oxide.Ext.Discord/Entities/GatewayResumedEvent.md) | Represents [Resumed](https://discord.com/developers/docs/topics/gateway#resumed) The resumed event is dispatched when a client has sent a resume payload to the gateway (for resuming existing sessions). | | class [GetEntitlements](./Oxide.Ext.Discord/Entities/GetEntitlements.md) | Get Entitlements Query String Builder | +| class [GetPollAnswerResponse](./Oxide.Ext.Discord/Entities/GetPollAnswerResponse.md) | Represents a [Get Poll Answers Response](https://discord.com/developers/docs/resources/poll#get-answer-voters-response-body) | +| class [GetPollAnswerVoters](./Oxide.Ext.Discord/Entities/GetPollAnswerVoters.md) | Represents a [Get Answer Voters Query String Params](https://discord.com/developers/docs/resources/poll#get-answer-voters-query-string-params) | | class [GetThreadMember](./Oxide.Ext.Discord/Entities/GetThreadMember.md) | Represents [Get Thread Member Query String Params](https://discord.com/developers/docs/resources/channel#get-thread-member-query-string-params) | | class [GroupDmChannelUpdate](./Oxide.Ext.Discord/Entities/GroupDmChannelUpdate.md) | Represents a [Group DM Channel Update Structure](https://discord.com/developers/docs/resources/channel#modify-channel-json-params-group-dm) | | class [GuildBan](./Oxide.Ext.Discord/Entities/GuildBan.md) | Represents [Guild Ban Structure](https://discord.com/developers/docs/resources/guild#ban-object-ban-structure) | @@ -282,6 +294,7 @@ | class [InteractionAutoCompleteMessage](./Oxide.Ext.Discord/Entities/InteractionAutoCompleteMessage.md) | Interaction Auto Complete Response Message | | class [InteractionAutoCompleteResponse](./Oxide.Ext.Discord/Entities/InteractionAutoCompleteResponse.md) | Represents an Auto Complete response in Discord | | class [InteractionCallbackData](./Oxide.Ext.Discord/Entities/InteractionCallbackData.md) | Represents [Interaction Application Command Callback Data Structure](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-data-structure) | +| enum [InteractionContextTypes](./Oxide.Ext.Discord/Entities/InteractionContextTypes.md) | Represents a [Interaction Context Types](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-context-types) | | class [InteractionData](./Oxide.Ext.Discord/Entities/InteractionData.md) | Represents [ApplicationCommandInteractionData](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-data) | | class [InteractionDataArgs](./Oxide.Ext.Discord/Entities/InteractionDataArgs.md) | Args supplied for the interaction | | class [InteractionDataOption](./Oxide.Ext.Discord/Entities/InteractionDataOption.md) | Represents [Application Command Interaction Data Option](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-interaction-data-option-structure) | @@ -289,8 +302,6 @@ | class [InteractionDataResolved](./Oxide.Ext.Discord/Entities/InteractionDataResolved.md) | Represents [Application Command Interaction Data Option](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-resolved-data-structure) | | class [InteractionModalMessage](./Oxide.Ext.Discord/Entities/InteractionModalMessage.md) | Represents an Interaction Modal Message | | class [InteractionModalResponse](./Oxide.Ext.Discord/Entities/InteractionModalResponse.md) | Represents an Interaction Modal Response | -| class [InteractionPremiumRequiredMessage](./Oxide.Ext.Discord/Entities/InteractionPremiumRequiredMessage.md) | Message for Premium Required | -| class [InteractionPremiumRequiredResponse](./Oxide.Ext.Discord/Entities/InteractionPremiumRequiredResponse.md) | Response for premium Required | | class [InteractionResponse](./Oxide.Ext.Discord/Entities/InteractionResponse.md) | Represents [Interaction Response](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object) | | enum [InteractionResponseType](./Oxide.Ext.Discord/Entities/InteractionResponseType.md) | Represents [InteractionResponseType](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type) | | enum [InteractionType](./Oxide.Ext.Discord/Entities/InteractionType.md) | Represents [InteractionType](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-type) | @@ -299,24 +310,31 @@ | class [InviteLookup](./Oxide.Ext.Discord/Entities/InviteLookup.md) | Represents a [Scheduled Event Lookup Structure](https://discord.com/developers/docs/resources/guild-scheduled-event#list-scheduled-events-for-guild-query-string-params) within Discord. | | class [InviteMetadata](./Oxide.Ext.Discord/Entities/InviteMetadata.md) | Represents [Invite Metadata Structure](https://discord.com/developers/docs/resources/invite#invite-metadata-object-invite-metadata-structure) | | class [InviteStageInstance](./Oxide.Ext.Discord/Entities/InviteStageInstance.md) | Represents an [Invite Stage Instance](https://discord.com/developers/docs/resources/invite#invite-stage-instance-object) | +| enum [InviteType](./Oxide.Ext.Discord/Entities/InviteType.md) | Represents [Invite Types](https://discord.com/developers/docs/resources/invite#invite-types) | | class [ListThreadMembers](./Oxide.Ext.Discord/Entities/ListThreadMembers.md) | Represents [List Thread Member Query String Params](https://discord.com/developers/docs/resources/channel#list-thread-members-query-string-params) | | class [MentionableSelectComponent](./Oxide.Ext.Discord/Entities/MentionableSelectComponent.md) | Represents a [Select Menus Component](https://discord.com/developers/docs/interactions/message-components#select-menus) within discord. | | class [MessageActivity](./Oxide.Ext.Discord/Entities/MessageActivity.md) | Represents a [Message Activity Structure](https://discord.com/developers/docs/resources/channel#message-object-message-activity-structure) | | enum [MessageActivityType](./Oxide.Ext.Discord/Entities/MessageActivityType.md) | Represents a [Message Activity Types](https://discord.com/developers/docs/resources/channel#message-object-message-activity-types) | | class [MessageAttachment](./Oxide.Ext.Discord/Entities/MessageAttachment.md) | Represents a message [Attachment Structure](https://discord.com/developers/docs/resources/channel#attachment-object) | | class [MessageBulkDeletedEvent](./Oxide.Ext.Discord/Entities/MessageBulkDeletedEvent.md) | Represents [Message Delete Bulk](https://discord.com/developers/docs/topics/gateway#message-delete-bulk) | +| class [MessageCall](./Oxide.Ext.Discord/Entities/MessageCall.md) | Represents a [Message Call Structure](https://discord.com/developers/docs/resources/channel#message-call-object) | | enum [MessageComponentType](./Oxide.Ext.Discord/Entities/MessageComponentType.md) | Represents a [Message Component Type](https://discord.com/developers/docs/interactions/message-components#component-types) within Discord.. | | class [MessageCreate](./Oxide.Ext.Discord/Entities/MessageCreate.md) | Represents a [Message Create Structure](https://discord.com/developers/docs/resources/channel#create-message-jsonform-params) to be created in discord | | class [MessageDeletedEvent](./Oxide.Ext.Discord/Entities/MessageDeletedEvent.md) | Represents [Message Delete](https://discord.com/developers/docs/topics/gateway#message-delete) | | class [MessageFileAttachment](./Oxide.Ext.Discord/Entities/MessageFileAttachment.md) | Represents a file attachment for a discord message | | [Flags] enum [MessageFlags](./Oxide.Ext.Discord/Entities/MessageFlags.md) | Represents [Message Flags](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a message | | class [MessageInteraction](./Oxide.Ext.Discord/Entities/MessageInteraction.md) | Represents a [Message Interaction Structure](https://discord.com/developers/docs/interactions/receiving-and-responding#message-interaction-object) within Discord. | +| class [MessageInteractionMetadata](./Oxide.Ext.Discord/Entities/MessageInteractionMetadata.md) | Represents a [Message Interaction Metadata Structure](https://discord.com/developers/docs/resources/channel#message-interaction-metadata-object-message-interaction-metadata-structure) within Discord. | +| class [MessagePollVoteAddedEvent](./Oxide.Ext.Discord/Entities/MessagePollVoteAddedEvent.md) | Represents [Message Poll Vote Added Event](https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-add) | +| class [MessagePollVoteRemovedEvent](./Oxide.Ext.Discord/Entities/MessagePollVoteRemovedEvent.md) | Represents [Message Poll Vote Removed Event](https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-remove) | | class [MessageReaction](./Oxide.Ext.Discord/Entities/MessageReaction.md) | Represents a [Reaction Structure](https://discord.com/developers/docs/resources/channel#reaction-object) | | class [MessageReactionAddedEvent](./Oxide.Ext.Discord/Entities/MessageReactionAddedEvent.md) | Represents [Message Reaction Add](https://discord.com/developers/docs/topics/gateway#message-reaction-add) | | class [MessageReactionRemovedAllEmojiEvent](./Oxide.Ext.Discord/Entities/MessageReactionRemovedAllEmojiEvent.md) | Represents [Message Reaction Remove All](https://discord.com/developers/docs/topics/gateway#message-reaction-remove-emoji-message-reaction-remove-emoji) | | class [MessageReactionRemovedAllEvent](./Oxide.Ext.Discord/Entities/MessageReactionRemovedAllEvent.md) | Represents [Message Reaction Remove All](https://discord.com/developers/docs/topics/gateway#message-reaction-remove-all) | | class [MessageReactionRemovedEvent](./Oxide.Ext.Discord/Entities/MessageReactionRemovedEvent.md) | Represents [Message Reaction Remove](https://discord.com/developers/docs/topics/gateway#message-reaction-remove) | | class [MessageReference](./Oxide.Ext.Discord/Entities/MessageReference.md) | Represents a [Message Reference Structure](https://discord.com/developers/docs/resources/channel#message-reference-object-message-reference-structure) for a message | +| enum [MessageReferenceType](./Oxide.Ext.Discord/Entities/MessageReferenceType.md) | Represents [Message Reference Type](https://discord.com/developers/docs/resources/channel#message-reference-types) | +| class [MessageSnapshot](./Oxide.Ext.Discord/Entities/MessageSnapshot.md) | Represents a [Message Snapshot](https://discord.com/developers/docs/resources/channel#message-snapshot-object) | | enum [MessageType](./Oxide.Ext.Discord/Entities/MessageType.md) | Represents [Message Types](https://discord.com/developers/docs/resources/channel#message-object-message-types) | | class [MessageUpdate](./Oxide.Ext.Discord/Entities/MessageUpdate.md) | Represents a [Message Update Structure](https://discord.com/developers/docs/resources/channel#edit-message-jsonform-params) sent in a channel within Discord.. | | class [OnboardingPrompt](./Oxide.Ext.Discord/Entities/OnboardingPrompt.md) | Represents [Onboarding Prompt Structure](https://discord.com/developers/docs/resources/guild#guild-onboarding-object-onboarding-prompt-structure) | @@ -324,11 +342,18 @@ | enum [OnboardingPromptType](./Oxide.Ext.Discord/Entities/OnboardingPromptType.md) | Represents [Prompt Types](https://discord.com/developers/docs/resources/guild#guild-onboarding-object-prompt-types) | | class [Overwrite](./Oxide.Ext.Discord/Entities/Overwrite.md) | Represents a [Overwrite Structure](https://discord.com/developers/docs/resources/channel#overwrite-object-overwrite-structure) | | [Flags] enum [PermissionFlags](./Oxide.Ext.Discord/Entities/PermissionFlags.md) | Represents [Permission Flags](https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags) for user or role | -| enum [PermissionType](./Oxide.Ext.Discord/Entities/PermissionType.md) | Represents the type of a permission | +| enum [PermissionType](./Oxide.Ext.Discord/Entities/PermissionType.md) | Represents the type of permission | +| class [PollAnswerCount](./Oxide.Ext.Discord/Entities/PollAnswerCount.md) | Represents a [Discord Poll Answer Count](https://discord.com/developers/docs/resources/poll#poll-results-object-poll-answer-count-object-structure) | +| class [PollAnswers](./Oxide.Ext.Discord/Entities/PollAnswers.md) | Represents a [Discord Poll Answers](https://discord.com/developers/docs/resources/poll#poll-answer-object) | +| class [PollCreate](./Oxide.Ext.Discord/Entities/PollCreate.md) | Represents a [Discord Poll Create](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) | +| enum [PollLayoutType](./Oxide.Ext.Discord/Entities/PollLayoutType.md) | Represents a [Discord Poll Layout Type](https://discord.com/developers/docs/resources/poll#layout-type) | +| class [PollMedia](./Oxide.Ext.Discord/Entities/PollMedia.md) | Represents a [Discord Poll Media](https://discord.com/developers/docs/resources/poll#poll-media-object) | +| class [PollResults](./Oxide.Ext.Discord/Entities/PollResults.md) | Represents a [Discord Poll Results](https://discord.com/developers/docs/resources/poll#poll-results-object) | | class [PresenceUpdatedEvent](./Oxide.Ext.Discord/Entities/PresenceUpdatedEvent.md) | Represents [Presence Update](https://discord.com/developers/docs/topics/gateway#presence-update) | | enum [PrivacyLevel](./Oxide.Ext.Discord/Entities/PrivacyLevel.md) | Represents a [Stage Privacy Level](https://discord.com/developers/docs/resources/stage-instance#stage-instance-object-privacy-level) within Discord. | | class [RateLimitResponse](./Oxide.Ext.Discord/Entities/RateLimitResponse.md) | Represents a rate limit response from an API request | | class [ReactionCountDetails](./Oxide.Ext.Discord/Entities/ReactionCountDetails.md) | Represents a [Reaction Count Details Structure](https://discord.com/developers/docs/resources/channel#reaction-count-details-object) | +| enum [ReactionType](./Oxide.Ext.Discord/Entities/ReactionType.md) | Represents a [Discord Reaction Type](https://discord.com/developers/docs/resources/channel#get-reactions-reaction-types) | | enum [RequestErrorType](./Oxide.Ext.Discord/Entities/RequestErrorType.md) | Represents a Discord Request Error Type | | class [RequestResponse](./Oxide.Ext.Discord/Entities/RequestResponse.md) | Represents a REST response from discord | | class [ResponseError](./Oxide.Ext.Discord/Entities/ResponseError.md) | Error object that is returned to the caller when a request fails | @@ -412,6 +437,7 @@ | class [DiscordApplicationException](./Oxide.Ext.Discord/Exceptions/DiscordApplicationException.md) | Exceptions for [`DiscordApplication`](./Oxide.Ext.Discord/Entities/DiscordApplication.md) | | class [DiscordClientException](./Oxide.Ext.Discord/Exceptions/DiscordClientException.md) | Exceptions for the [`DiscordClient`](./Oxide.Ext.Discord/Clients/DiscordClient.md) | | class [DiscordLocaleNotFoundException](./Oxide.Ext.Discord/Exceptions/DiscordLocaleNotFoundException.md) | Exception thrown when Discord Locale is not found | +| class [DiscordLoggerException](./Oxide.Ext.Discord/Exceptions/DiscordLoggerException.md) | Exceptions for the [`DiscordClient`](./Oxide.Ext.Discord/Clients/DiscordClient.md) | | class [DiscordTemplateException](./Oxide.Ext.Discord/Exceptions/DiscordTemplateException.md) | Exception for Discord Templates | | class [DiscordWebSocketException](./Oxide.Ext.Discord/Exceptions/DiscordWebSocketException.md) | Represents an exception that occured with the websocket | | class [DuplicateTemplateException](./Oxide.Ext.Discord/Exceptions/DuplicateTemplateException.md) | Thrown when duplicate templates have been registered for the same type, plugin, and name | @@ -527,18 +553,18 @@ | public type | description | | --- | --- | | class [DiscordColorConverter](./Oxide.Ext.Discord/Json/DiscordColorConverter.md) | Handles the JSON Serialization / Deserialization for DiscordColor | -| class [DiscordEnumConverter](./Oxide.Ext.Discord/Json/DiscordEnumConverter.md) | Handles deserializing JSON values as strings. If the value doesn't exist return the default value. | +| class [DiscordEnumConverter](./Oxide.Ext.Discord/Json/DiscordEnumConverter.md) | Handles deserializing JSON values as strings. If the value doesn't exist, return the default value. | | class [DiscordImageDataConverter](./Oxide.Ext.Discord/Json/DiscordImageDataConverter.md) | Represents the JsonConverter for [`DiscordImageData`](./Oxide.Ext.Discord/Entities/DiscordImageData.md) | | class [DiscordJsonReader](./Oxide.Ext.Discord/Json/DiscordJsonReader.md) | This is a pooled JSON reader that can read as string, deserialize object, or populate a given object async | | class [DiscordJsonWriter](./Oxide.Ext.Discord/Json/DiscordJsonWriter.md) | This is a pooled JSON writer that can write JSON to a stream | | class [EventPayloadConverter](./Oxide.Ext.Discord/Json/EventPayloadConverter.md) | JSON converter for [`EventPayload`](./Oxide.Ext.Discord/Entities/EventPayload.md) | | class [HashListConverter<TValue>](./Oxide.Ext.Discord/Json/HashListConverter%7BTValue%7D.md) | Converts to and from a list in JSON to a hash | -| class [MessageComponentsConverter](./Oxide.Ext.Discord/Json/MessageComponentsConverter.md) | Converter for list of message components | +| class [MessageComponentsConverter](./Oxide.Ext.Discord/Json/MessageComponentsConverter.md) | Converter for a list of message components | | class [PermissionFlagsStringConverter](./Oxide.Ext.Discord/Json/PermissionFlagsStringConverter.md) | Converts Permission Flags to and from a JSON string | | class [RoleTagsConverter](./Oxide.Ext.Discord/Json/RoleTagsConverter.md) | Handles converting [`RoleTags`](./Oxide.Ext.Discord/Entities/RoleTags.md) This type contains special deserialization types | -| class [SnowflakeConverter](./Oxide.Ext.Discord/Json/SnowflakeConverter.md) | Converts a snowflake to and from it's JSON string value | -| class [TemplateComponentsConverter](./Oxide.Ext.Discord/Json/TemplateComponentsConverter.md) | Converter for list of message components | -| class [TemplateKeyConverter](./Oxide.Ext.Discord/Json/TemplateKeyConverter.md) | Json Template Key Converter | +| class [SnowflakeConverter](./Oxide.Ext.Discord/Json/SnowflakeConverter.md) | Converts a snowflake to and from its JSON string value | +| class [TemplateComponentsConverter](./Oxide.Ext.Discord/Json/TemplateComponentsConverter.md) | Converter for a list of message components | +| class [TemplateKeyConverter](./Oxide.Ext.Discord/Json/TemplateKeyConverter.md) | JSON Template Key Converter | | class [UnixDateTimeConverter](./Oxide.Ext.Discord/Json/UnixDateTimeConverter.md) | Converts a DateTimeOffset to and from a json long | ## Oxide.Ext.Discord.Libraries namespace @@ -676,13 +702,14 @@ | interface [IPool<T>](./Oxide.Ext.Discord/Types/IPool%7BT%7D.md) | Represents a pool of type T | | class [PoolSettings](./Oxide.Ext.Discord/Types/PoolSettings.md) | Settings for the pools | | struct [PoolSize](./Oxide.Ext.Discord/Types/PoolSize.md) | Represents size constraints for a pool | -| class [Promise](./Oxide.Ext.Discord/Types/Promise.md) | Implements a non-generic C# promise, this is a promise that simply resolves without delivering a value. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise | +| class [Promise](./Oxide.Ext.Discord/Types/Promise.md) | Implements a non-generic C# promise; this is a promise that simply resolves without delivering a value. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise | | class [Promise<TPromised>](./Oxide.Ext.Discord/Types/Promise%7BTPromised%7D.md) | Implements a C# promise. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise | | enum [PromiseState](./Oxide.Ext.Discord/Types/PromiseState.md) | Specifies the state of a promise. | | struct [RejectHandler](./Oxide.Ext.Discord/Types/RejectHandler.md) | Represents a handler invoked when the promise is rejected. | | class [RestRateLimit](./Oxide.Ext.Discord/Types/RestRateLimit.md) | Represents a rate limit for rest requests | | abstract class [Singleton<T>](./Oxide.Ext.Discord/Types/Singleton%7BT%7D.md) | Represents a singleton of type {T} | | class [UkkonenTrie<T>](./Oxide.Ext.Discord/Types/UkkonenTrie%7BT%7D.md) | A Ukkonen Suffix Trie | +| struct [ValueStringBuilder](./Oxide.Ext.Discord/Types/ValueStringBuilder.md) | | | class [WebsocketRateLimit](./Oxide.Ext.Discord/Types/WebsocketRateLimit.md) | Represents a WebSocket Rate Limit | ## Oxide.Ext.Discord.WebSockets namespace diff --git a/Docs/Generated/Oxide.Ext.Discord/Builders/ApplicationCommandOptionBuilder.md b/Docs/Generated/Oxide.Ext.Discord/Builders/ApplicationCommandOptionBuilder.md index c3dddeb50..6e9a27c9c 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Builders/ApplicationCommandOptionBuilder.md +++ b/Docs/Generated/Oxide.Ext.Discord/Builders/ApplicationCommandOptionBuilder.md @@ -160,7 +160,7 @@ public ApplicationCommandOptionBuilder AutoComplete(bool autoComplete = true) | parameter | description | | --- | --- | -| autoComplete | If the option support auto complete (Default: true) | +| autoComplete | If the option supports auto complete (Default: true) | ## Return Value @@ -366,7 +366,7 @@ This | exception | condition | | --- | --- | -| Exception | Thrown if option type is not double | +| Exception | Thrown if the option type is not double | ## See Also @@ -399,7 +399,7 @@ This | exception | condition | | --- | --- | -| Exception | Thrown if option type is not int | +| Exception | Thrown if the option type is not int | ## See Also @@ -432,7 +432,7 @@ This | exception | condition | | --- | --- | -| Exception | Thrown if option type is not string | +| Exception | Thrown if the option type is not string | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Builders/BaseMessageBuilder{TMessage,TBuilder}.md b/Docs/Generated/Oxide.Ext.Discord/Builders/BaseMessageBuilder{TMessage,TBuilder}.md index e97611bc9..20014fb68 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Builders/BaseMessageBuilder{TMessage,TBuilder}.md +++ b/Docs/Generated/Oxide.Ext.Discord/Builders/BaseMessageBuilder{TMessage,TBuilder}.md @@ -285,7 +285,7 @@ Adds an attachment to the message ```csharp public virtual TBuilder AddAttachment(string filename, byte[] data, string contentType, - string description = null) + string description = null, string title = null) ``` | parameter | description | @@ -294,6 +294,7 @@ public virtual TBuilder AddAttachment(string filename, byte[] data, string conte | data | byte[] of the attachment | | contentType | Attachment content type | | description | Description for the attachment | +| title | Title of the attachment | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Builders/BuildersNamespace.md b/Docs/Generated/Oxide.Ext.Discord/Builders/BuildersNamespace.md index c3fe7c369..81f658b34 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Builders/BuildersNamespace.md +++ b/Docs/Generated/Oxide.Ext.Discord/Builders/BuildersNamespace.md @@ -20,7 +20,7 @@ | class [MessageComponentBuilder](./MessageComponentBuilder.md) | Builder for Message Components | | [Flags] enum [PlayerDisplayNameMode](./PlayerDisplayNameMode.md) | Player Name Formatting options for [`PlayerNameFormatter`](./Oxide.Ext.Discord/Builders/PlayerNameFormatter.md) | | class [PlayerNameFormatter](./PlayerNameFormatter.md) | Formatter for player names | -| class [QueryStringBuilder](./QueryStringBuilder.md) | Builder used to build query strings for urls | +| struct [QueryStringBuilder](./QueryStringBuilder.md) | Builder used to build query strings for urls | | class [SelectMenuComponentBuilder](./SelectMenuComponentBuilder.md) | Builder for Select Menus | | class [WebhookMessageBuilder](./WebhookMessageBuilder.md) | Represents a builder for [`WebhookMessageBuilder`](./Oxide.Ext.Discord/Builders/WebhookMessageBuilder.md) | diff --git a/Docs/Generated/Oxide.Ext.Discord/Builders/DiscordEmbedBuilder.md b/Docs/Generated/Oxide.Ext.Discord/Builders/DiscordEmbedBuilder.md index feb7cc43f..6422a7148 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Builders/DiscordEmbedBuilder.md +++ b/Docs/Generated/Oxide.Ext.Discord/Builders/DiscordEmbedBuilder.md @@ -13,15 +13,15 @@ public class DiscordEmbedBuilder | [DiscordEmbedBuilder](#discordembedbuilder-constructor)() | Constructor for the builder creating a new embed | | [DiscordEmbedBuilder](#discordembedbuilder-constructor)(…) | Constructor for the builder using an existing embed | | [AddAuthor](#addauthor-method)(…) | Adds an author to the embed message. The author will appear above the title | -| [AddBlankField](#addblankfield-method)(…) | Adds a blank field. If inline it will add a blank column. If not inline will add a blank row | +| [AddBlankField](#addblankfield-method)(…) | Adds a blank field. If inline, it will add a blank column. If not, inline will add a blank row | | [AddColor](#addcolor-method-1-of-7)(…) | Adds a Discord Color to the embed (7 methods) | | [AddDescription](#adddescription-method)(…) | Adds a description to the embed message | -| [AddField](#addfield-method)(…) | Adds a new field with the name as the title and value as the value. If inline will add a new column. If row will add in a new row. | +| [AddField](#addfield-method)(…) | Adds a new field with the name as the title and value as the value. If inline add a new column. If row adds in a new row. | | [AddFooter](#addfooter-method)(…) | Adds a footer to the embed message | -| [AddImage](#addimage-method)(…) | Adds an image to the embed. The url should point to the url of the image. If using attachment image you can make the url: "attachment://{image name}.{image extension} | +| [AddImage](#addimage-method)(…) | Adds an image to the embed. The url should point to the url of the image. If using attachment image, you can make the url: "attachment://{image name}.{image extension} | | [AddNowTimestamp](#addnowtimestamp-method)() | Adds a timestamp to an embed with the current time | | [AddProvider](#addprovider-method)(…) | Adds a provider to the embed | -| [AddThumbnail](#addthumbnail-method)(…) | Adds a thumbnail in the top right corner of the embed If using attachment image you can make the url: "attachment://{image name}.{image extension} | +| [AddThumbnail](#addthumbnail-method)(…) | Adds a thumbnail in the top right corner of the embed, If using attachment image, you can make the url: "attachment://{image name}.{image extension} | | [AddTimestamp](#addtimestamp-method)(…) | Adds a timestamp to an embed with the given time | | [AddTitle](#addtitle-method)(…) | Adds a title to the embed message | | [AddUrl](#addurl-method)(…) | Adds a url to the embed message | @@ -117,7 +117,7 @@ public DiscordEmbedBuilder AddAuthor(string name, string url = null, string icon | parameter | description | | --- | --- | | name | Name of the author | -| url | Url to go to when the authors name is clicked on | +| url | Url to go to when the author's name is clicked on | | iconUrl | Icon Url to use for the author | | proxyIconUrl | Backup icon url. Can be left null if you only have one icon url | @@ -272,9 +272,9 @@ public DiscordEmbedBuilder AddColor(double red, double green, double blue) | parameter | description | | --- | --- | -| red | Red value between 0 - 1 | -| green | Green value between 0 - 1 | -| blue | Blue value between 0 - 1 | +| red | Red value between 0-1 | +| green | Green value between 0-1 | +| blue | Blue value between 0-1 | ## Return Value @@ -304,9 +304,9 @@ public DiscordEmbedBuilder AddColor(float red, float green, float blue) | parameter | description | | --- | --- | -| red | Red value between 0 - 1 | -| green | Green value between 0 - 1 | -| blue | Blue value between 0 - 1 | +| red | Red value between 0-1 | +| green | Green value between 0-1 | +| blue | Blue value between 0-1 | ## Return Value @@ -336,9 +336,9 @@ public DiscordEmbedBuilder AddColor(int red, int green, int blue) | parameter | description | | --- | --- | -| red | Red value between 0 - 255 | -| green | Green value between 0 - 255 | -| blue | Blue value between 0 - 255 | +| red | Red value between 0-255 | +| green | Green value between 0-255 | +| blue | Blue value between 0-255 | ## Return Value @@ -401,7 +401,7 @@ This   # AddBlankField method -Adds a blank field. If inline it will add a blank column. If not inline will add a blank row +Adds a blank field. If inline, it will add a blank column. If not, inline will add a blank row ```csharp public DiscordEmbedBuilder AddBlankField(bool inline) @@ -424,7 +424,7 @@ This   # AddField method -Adds a new field with the name as the title and value as the value. If inline will add a new column. If row will add in a new row. +Adds a new field with the name as the title and value as the value. If inline add a new column. If row adds in a new row. ```csharp public DiscordEmbedBuilder AddField(string name, string value, bool inline) @@ -449,7 +449,7 @@ This   # AddImage method -Adds an image to the embed. The url should point to the url of the image. If using attachment image you can make the url: "attachment://{image name}.{image extension} +Adds an image to the embed. The url should point to the url of the image. If using attachment image, you can make the url: "attachment://{image name}.{image extension} ```csharp public DiscordEmbedBuilder AddImage(string url, int? width = null, int? height = null, @@ -476,7 +476,7 @@ This   # AddThumbnail method -Adds a thumbnail in the top right corner of the embed If using attachment image you can make the url: "attachment://{image name}.{image extension} +Adds a thumbnail in the top right corner of the embed, If using attachment image, you can make the url: "attachment://{image name}.{image extension} ```csharp public DiscordEmbedBuilder AddThumbnail(string url, int? width = null, int? height = null, diff --git a/Docs/Generated/Oxide.Ext.Discord/Builders/DiscordMessageBuilder.md b/Docs/Generated/Oxide.Ext.Discord/Builders/DiscordMessageBuilder.md index 583853879..304de3321 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Builders/DiscordMessageBuilder.md +++ b/Docs/Generated/Oxide.Ext.Discord/Builders/DiscordMessageBuilder.md @@ -11,7 +11,7 @@ public class DiscordMessageBuilder : BaseChannelMessageBuilder list, PlayerNameFo   # AddByPlayerId method -Adds a player by player Id to the list +Adds a player by player ID to the list ```csharp public void AddByPlayerId(string playerId, PlayerNameFormatter formatter = null) diff --git a/Docs/Generated/Oxide.Ext.Discord/Builders/MessageComponentBuilder.md b/Docs/Generated/Oxide.Ext.Discord/Builders/MessageComponentBuilder.md index 5ba88b566..a920f98d5 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Builders/MessageComponentBuilder.md +++ b/Docs/Generated/Oxide.Ext.Discord/Builders/MessageComponentBuilder.md @@ -51,7 +51,7 @@ public MessageComponentBuilder AddActionButton(ButtonStyle style, string label, | exception | condition | | --- | --- | -| Exception | Throw if the button style is link or if the button goes outside the max number of action rows | +| Exception | Throw if the button style is a link or if the button goes outside the max number of action rows | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Builders/PlayerNameFormatter.md b/Docs/Generated/Oxide.Ext.Discord/Builders/PlayerNameFormatter.md index 6c684578b..37aea7128 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Builders/PlayerNameFormatter.md +++ b/Docs/Generated/Oxide.Ext.Discord/Builders/PlayerNameFormatter.md @@ -13,7 +13,7 @@ public class PlayerNameFormatter | static readonly [All](#all-field) | Include all name options in the player name | | static readonly [ClanName](#clanname-field) | Include clan name in the player name | | static readonly [Default](#default-field) | Default Player Name Formatter | -| static readonly [PlayerId](#playerid-field) | Include Player Id in the player name | +| static readonly [PlayerId](#playerid-field) | Include Player ID in the player name | | static [Create](#create-method)(…) | Create a new Player Name formatter with the given Custom Name Function | | [Format](#format-method)(…) | Formats the player name | @@ -102,7 +102,7 @@ public static readonly PlayerNameFormatter ClanName;   # PlayerId field -Include Player Id in the player name +Include Player ID in the player name ```csharp public static readonly PlayerNameFormatter PlayerId; diff --git a/Docs/Generated/Oxide.Ext.Discord/Builders/QueryStringBuilder.md b/Docs/Generated/Oxide.Ext.Discord/Builders/QueryStringBuilder.md index 8814bf192..f9b279e08 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Builders/QueryStringBuilder.md +++ b/Docs/Generated/Oxide.Ext.Discord/Builders/QueryStringBuilder.md @@ -1,9 +1,10 @@ -# QueryStringBuilder class +# QueryStringBuilder structure Builder used to build query strings for urls ```csharp -public class QueryStringBuilder : BasePoolable +[Obsolete("Types with embedded references are not supported in this version of your compiler.")] +public struct QueryStringBuilder ``` ## Public Members @@ -11,47 +12,17 @@ public class QueryStringBuilder : BasePoolable | name | description | | --- | --- | | [QueryStringBuilder](#querystringbuilder-constructor)() | The default constructor. | -| static [Create](#create-method)(…) | Creates a pooled [`QueryStringBuilder`](./QueryStringBuilder.md) | | [Add](#add-method)(…) | Add a key value pair to the query string | | [AddList<T>](#addlist&lt;t&gt;-method)(…) | Add a list of values with the specified separator | | override [ToString](#tostring-method)() | Returns the query string as a string. | -| [ToStringAndFree](#tostringandfree-method)() | Returns the query string and returns the builder back to the pool | - -## Protected Members - -| name | description | -| --- | --- | -| override [EnterPool](#enterpool-method)() | | -| override [LeavePool](#leavepool-method)() | | ## See Also -* class [BasePoolable](../Types/BasePoolable.md) * namespace [Oxide.Ext.Discord.Builders](./BuildersNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) * [QueryStringBuilder.cs](../../../../Oxide.Ext.Discord/Builders/QueryStringBuilder.cs)     -# Create method - -Creates a pooled [`QueryStringBuilder`](./QueryStringBuilder.md) - -```csharp -public static QueryStringBuilder Create(DiscordPluginPool pool) -``` - -## Return Value - -[`QueryStringBuilder`](./QueryStringBuilder.md) - -## See Also - -* class [DiscordPluginPool](../Types/DiscordPluginPool.md) -* class [QueryStringBuilder](./QueryStringBuilder.md) -* namespace [Oxide.Ext.Discord.Builders](./BuildersNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  # Add method Add a key value pair to the query string @@ -67,7 +38,7 @@ public void Add(string key, string value) ## See Also -* class [QueryStringBuilder](./QueryStringBuilder.md) +* struct [QueryStringBuilder](./QueryStringBuilder.md) * namespace [Oxide.Ext.Discord.Builders](./BuildersNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)   @@ -89,7 +60,7 @@ public void AddList(string key, List list, string separator) ## See Also -* class [QueryStringBuilder](./QueryStringBuilder.md) +* struct [QueryStringBuilder](./QueryStringBuilder.md) * namespace [Oxide.Ext.Discord.Builders](./BuildersNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)   @@ -104,48 +75,7 @@ public override string ToString() ## See Also -* class [QueryStringBuilder](./QueryStringBuilder.md) -* namespace [Oxide.Ext.Discord.Builders](./BuildersNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# ToStringAndFree method - -Returns the query string and returns the builder back to the pool - -```csharp -public string ToStringAndFree() -``` - -## See Also - -* class [QueryStringBuilder](./QueryStringBuilder.md) -* namespace [Oxide.Ext.Discord.Builders](./BuildersNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# EnterPool method - -```csharp -protected override void EnterPool() -``` - -## See Also - -* class [QueryStringBuilder](./QueryStringBuilder.md) -* namespace [Oxide.Ext.Discord.Builders](./BuildersNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# LeavePool method - -```csharp -protected override void LeavePool() -``` - -## See Also - -* class [QueryStringBuilder](./QueryStringBuilder.md) +* struct [QueryStringBuilder](./QueryStringBuilder.md) * namespace [Oxide.Ext.Discord.Builders](./BuildersNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)   @@ -160,7 +90,7 @@ public QueryStringBuilder() ## See Also -* class [QueryStringBuilder](./QueryStringBuilder.md) +* struct [QueryStringBuilder](./QueryStringBuilder.md) * namespace [Oxide.Ext.Discord.Builders](./BuildersNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Cache/DiscordPluginCache.md b/Docs/Generated/Oxide.Ext.Discord/Cache/DiscordPluginCache.md index 50363c25a..7241a88c4 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Cache/DiscordPluginCache.md +++ b/Docs/Generated/Oxide.Ext.Discord/Cache/DiscordPluginCache.md @@ -10,6 +10,7 @@ public sealed class DiscordPluginCache : Singleton | name | description | | --- | --- | +| [GetAllPlugins](#getallplugins-method)() | Returns a list of all plugins in the plugin folder | | [GetLoadablePlugins](#getloadableplugins-method)() | Returns a list of plugins that can be loaded by oxide Already loaded plugins are excluded from the list | | [GetLoadedPlugins](#getloadedplugins-method)() | Returns a list of plugins loaded by oxide | @@ -46,6 +47,21 @@ public IReadOnlyList GetLoadablePlugins() ## See Also +* class [DiscordPluginCache](./DiscordPluginCache.md) +* namespace [Oxide.Ext.Discord.Cache](./CacheNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GetAllPlugins method + +Returns a list of all plugins in the plugin folder + +```csharp +public IReadOnlyList GetAllPlugins() +``` + +## See Also + * class [DiscordPluginCache](./DiscordPluginCache.md) * namespace [Oxide.Ext.Discord.Cache](./CacheNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Cache/EmojiCache.md b/Docs/Generated/Oxide.Ext.Discord/Cache/EmojiCache.md index fd8c7118a..a70ee5bef 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Cache/EmojiCache.md +++ b/Docs/Generated/Oxide.Ext.Discord/Cache/EmojiCache.md @@ -10,9 +10,13 @@ public sealed class EmojiCache : Singleton | name | description | | --- | --- | -| [EmojiToText](#emojitotext-method)(…) | Convert an emoji character to emoji string text | -| [ReplaceEmojiWithText](#replaceemojiwithtext-method)(…) | Replaces emoji character with emoji string characters | -| [ReplaceTextWithEmoji](#replacetextwithemoji-method)(…) | Replaces emoji string text with emoji characters | +| readonly [EmojiRegex](#emojiregex-field) | | +| readonly [EmojiToTextOrDefault](#emojitotextordefault-field) | | +| readonly [TextRegex](#textregex-field) | | +| readonly [TextToEmojiOrDefault](#texttoemojiordefault-field) | | +| [EmojiToText](#emojitotext-method)(…) | Convert an emoji character to the emoji string text | +| [ReplaceEmojiWithText](#replaceemojiwithtext-method-1-of-3)(…) | Replaces emoji character with emoji string characters (3 methods) | +| [ReplaceTextWithEmoji](#replacetextwithemoji-method-1-of-3)(…) | Replaces emoji string text with emoji characters (3 methods) | | [TextToEmoji](#texttoemoji-method)(…) | Convert emoji string text to an emoji character | ## See Also @@ -25,7 +29,7 @@ public sealed class EmojiCache : Singleton   # EmojiToText method -Convert an emoji character to emoji string text +Convert an emoji character to the emoji string text ```csharp public string EmojiToText(string emoji) @@ -61,18 +65,59 @@ public string TextToEmoji(string text) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     -# ReplaceEmojiWithText method +# ReplaceEmojiWithText method (1 of 3) + +Replaces emoji character with emoji string characters If no match is found then the original text is used + +```csharp +public string ReplaceEmojiWithText(string text) +``` + +| parameter | description | +| --- | --- | +| text | Text to replace | + +## See Also + +* class [EmojiCache](./EmojiCache.md) +* namespace [Oxide.Ext.Discord.Cache](./CacheNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# ReplaceEmojiWithText method (2 of 3) Replaces emoji character with emoji string characters ```csharp -public string ReplaceEmojiWithText(string text, string nonMatchReplacement = "") +public string ReplaceEmojiWithText(string text, MatchEvaluator evaluator) ``` | parameter | description | | --- | --- | -| text | | -| nonMatchReplacement | | +| text | Text to replace | +| evaluator | Replacement Evaluator function | + +## See Also + +* class [EmojiCache](./EmojiCache.md) +* namespace [Oxide.Ext.Discord.Cache](./CacheNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# ReplaceEmojiWithText method (3 of 3) + +Replaces emoji character with emoji string characters + +```csharp +public string ReplaceEmojiWithText(string text, string nonMatchReplacement) +``` + +| parameter | description | +| --- | --- | +| text | Text to replace | +| nonMatchReplacement | Replacement Text to use if non-matching | ## See Also @@ -81,18 +126,111 @@ public string ReplaceEmojiWithText(string text, string nonMatchReplacement = "") * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     -# ReplaceTextWithEmoji method +# ReplaceTextWithEmoji method (1 of 3) + +Replaces emoji string text with emoji characters If no match is found then the original text is used + +```csharp +public string ReplaceTextWithEmoji(string text) +``` + +| parameter | description | +| --- | --- | +| text | Text to replace | + +## See Also + +* class [EmojiCache](./EmojiCache.md) +* namespace [Oxide.Ext.Discord.Cache](./CacheNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# ReplaceTextWithEmoji method (2 of 3) Replaces emoji string text with emoji characters ```csharp -public string ReplaceTextWithEmoji(string text, string nonMatchReplacement = "") +public string ReplaceTextWithEmoji(string text, MatchEvaluator evaluator) ``` | parameter | description | | --- | --- | -| text | | -| nonMatchReplacement | | +| text | Text to replace | +| evaluator | Replacement Evaluator function | + +## See Also + +* class [EmojiCache](./EmojiCache.md) +* namespace [Oxide.Ext.Discord.Cache](./CacheNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# ReplaceTextWithEmoji method (3 of 3) + +Replaces emoji string text with emoji characters + +```csharp +public string ReplaceTextWithEmoji(string text, string nonMatchReplacement) +``` + +| parameter | description | +| --- | --- | +| text | Text to replace | +| nonMatchReplacement | Replacement Text to use if non-matching | + +## See Also + +* class [EmojiCache](./EmojiCache.md) +* namespace [Oxide.Ext.Discord.Cache](./CacheNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# EmojiRegex field + +```csharp +public readonly Regex EmojiRegex; +``` + +## See Also + +* class [EmojiCache](./EmojiCache.md) +* namespace [Oxide.Ext.Discord.Cache](./CacheNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# TextRegex field + +```csharp +public readonly Regex TextRegex; +``` + +## See Also + +* class [EmojiCache](./EmojiCache.md) +* namespace [Oxide.Ext.Discord.Cache](./CacheNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# EmojiToTextOrDefault field + +```csharp +public readonly MatchEvaluator EmojiToTextOrDefault; +``` + +## See Also + +* class [EmojiCache](./EmojiCache.md) +* namespace [Oxide.Ext.Discord.Cache](./CacheNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# TextToEmojiOrDefault field + +```csharp +public readonly MatchEvaluator TextToEmojiOrDefault; +``` ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Cache/EntityCache{T}.md b/Docs/Generated/Oxide.Ext.Discord/Cache/EntityCache{T}.md index 807e04484..e781ddaf4 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Cache/EntityCache{T}.md +++ b/Docs/Generated/Oxide.Ext.Discord/Cache/EntityCache{T}.md @@ -13,7 +13,7 @@ public sealed class EntityCache : Singleton | --- | --- | | readonly [Cache](#cache-field) | Readonly Cache of [`DiscordUser`](../Entities/DiscordUser.md) | | [Get](#get-method)(…) | Returns the cached entity with the given ID; default(T) otherwise | -| [GetOrCreate](#getorcreate-method)(…) | Returns a cached for the given user ID or creates a new with that ID | +| [GetOrCreate](#getorcreate-method)(…) | Returns a cached {T} for the given user ID or creates a new {T} with that ID | | [Update](#update-method)(…) | Updates the cached entity | ## See Also @@ -47,7 +47,7 @@ public T Get(Snowflake id)   # GetOrCreate method -Returns a cached for the given user ID or creates a new with that ID +Returns a cached {T} for the given user ID or creates a new {T} with that ID ```csharp public T GetOrCreate(Snowflake id) diff --git a/Docs/Generated/Oxide.Ext.Discord/Cache/EnumCache{T}.md b/Docs/Generated/Oxide.Ext.Discord/Cache/EnumCache{T}.md index 4d24249a8..9c48645eb 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Cache/EnumCache{T}.md +++ b/Docs/Generated/Oxide.Ext.Discord/Cache/EnumCache{T}.md @@ -16,7 +16,7 @@ public sealed class EnumCache : Singleton | name | description | | --- | --- | | readonly [Values](#values-field) | Readonly Collection of Enum Values | -| [Next](#next-method)(…) | Returns the next enum values. If the value is the last value it will start from the beginning | +| [Next](#next-method)(…) | Returns the next enum values. If the value is the last value, it will start from the beginning | | [Previous](#previous-method)(…) | Returns the previous enum values. | | [ToLower](#tolower-method)(…) | Returns the lowered string representation of the enum | | [ToNumber](#tonumber-method)(…) | Converts the enum to it's number form as a string | @@ -97,7 +97,7 @@ public string ToNumber(T value)   # Next method -Returns the next enum values. If the value is the last value it will start from the beginning +Returns the next enum values. If the value is the last value, it will start from the beginning ```csharp public T Next(T value) diff --git a/Docs/Generated/Oxide.Ext.Discord/Cache/StringCache{T}.md b/Docs/Generated/Oxide.Ext.Discord/Cache/StringCache{T}.md index 50c8c28b6..44579cc12 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Cache/StringCache{T}.md +++ b/Docs/Generated/Oxide.Ext.Discord/Cache/StringCache{T}.md @@ -14,8 +14,8 @@ public sealed class StringCache : Singleton | name | description | | --- | --- | -| [ToLower](#tolower-method)(…) | Returns the lowered string representation of type {T} | -| [ToString](#tostring-method)(…) | Returns a cached ToString call of type {T} | +| [ToLower](#tolower-method)(…) | Returns the lowered string representation of the type {T} | +| [ToString](#tostring-method)(…) | Returns a cached ToString call of the type {T} | ## See Also @@ -27,7 +27,7 @@ public sealed class StringCache : Singleton   # ToString method -Returns a cached ToString call of type {T} +Returns a cached ToString call of the type {T} ```csharp public string ToString(T value) @@ -46,7 +46,7 @@ public string ToString(T value)   # ToLower method -Returns the lowered string representation of type {T} +Returns the lowered string representation of the type {T} ```csharp public string ToLower(T value) diff --git a/Docs/Generated/Oxide.Ext.Discord/Clients/BaseClient.md b/Docs/Generated/Oxide.Ext.Discord/Clients/BaseClient.md new file mode 100644 index 000000000..e887fda28 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Clients/BaseClient.md @@ -0,0 +1,180 @@ +# BaseClient class + +BaseClient that can connect to discord + +```csharp +public abstract class BaseClient +``` + +## Public Members + +| name | description | +| --- | --- | +| [Initialized](#initialized-property) { get; protected set; } | If the connection is initialized and not disconnected | +| [Rest](#rest-property) { get; protected set; } | Rest handler for all discord API calls | +| readonly [Clients](#clients-field) | List of all clients that are using this bot client | +| virtual [AddClient](#addclient-method)(…) | Add a [`DiscordClient`](./DiscordClient.md) to this bot / webhook client | +| [GetClientPluginList](#getclientpluginlist-method)() | Returns the list of plugins for this bot | +| virtual [RemoveClient](#removeclient-method)(…) | Removes the [`DiscordClient`](./DiscordClient.md) from this bot / webhook client | + +## Protected Members + +| name | description | +| --- | --- | +| [BaseClient](#baseclient-constructor)() | Constructor | +| readonly [_clients](#_clients-field) | List of all clients using this client | + +## See Also + +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [BaseClient.cs](../../../../Oxide.Ext.Discord/Clients/BaseClient.cs) +  +  +# GetClientPluginList method + +Returns the list of plugins for this bot + +```csharp +public string GetClientPluginList() +``` + +## See Also + +* class [BaseClient](./BaseClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AddClient method + +Add a [`DiscordClient`](./DiscordClient.md) to this bot / webhook client + +```csharp +public virtual void AddClient(DiscordClient client) +``` + +| parameter | description | +| --- | --- | +| client | Client to add | + +## Return Value + +True if this is the initial setup of the client; false otherwise + +## Exceptions + +| exception | condition | +| --- | --- | +| Exception | Thrown if [`DiscordClient`](./DiscordClient.md) already has been added to this bot / webhook client | + +## See Also + +* class [DiscordClient](./DiscordClient.md) +* class [BaseClient](./BaseClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# RemoveClient method + +Removes the [`DiscordClient`](./DiscordClient.md) from this bot / webhook client + +```csharp +public virtual bool RemoveClient(DiscordClient client) +``` + +| parameter | description | +| --- | --- | +| client | Client to remove | + +## Return Value + +returns true if the client is shutting down; false otherwise + +## See Also + +* class [DiscordClient](./DiscordClient.md) +* class [BaseClient](./BaseClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# BaseClient constructor + +Constructor + +```csharp +protected BaseClient() +``` + +## See Also + +* class [BaseClient](./BaseClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Rest property + +Rest handler for all discord API calls + +```csharp +public RestHandler Rest { get; protected set; } +``` + +## See Also + +* class [RestHandler](../Rest/RestHandler.md) +* class [BaseClient](./BaseClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Initialized property + +If the connection is initialized and not disconnected + +```csharp +public bool Initialized { get; protected set; } +``` + +## See Also + +* class [BaseClient](./BaseClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# _clients field + +List of all clients using this client + +```csharp +protected readonly List _clients; +``` + +## See Also + +* class [DiscordClient](./DiscordClient.md) +* class [BaseClient](./BaseClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Clients field + +List of all clients that are using this bot client + +```csharp +public readonly IReadOnlyList Clients; +``` + +## See Also + +* class [DiscordClient](./DiscordClient.md) +* class [BaseClient](./BaseClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Clients/BotClient.md b/Docs/Generated/Oxide.Ext.Discord/Clients/BotClient.md index 95deebab1..ac745b62c 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Clients/BotClient.md +++ b/Docs/Generated/Oxide.Ext.Discord/Clients/BotClient.md @@ -1,9 +1,9 @@ # BotClient class -Represents a bot that is connected to discord +Represents a bot connected to discord ```csharp -public class BotClient : IDebugLoggable +public class BotClient : BaseClient, IDebugLoggable ``` ## Public Members @@ -13,51 +13,32 @@ public class BotClient : IDebugLoggable | [BotClient](#botclient-constructor)(…) | Connection settings to use for the bot | | [Application](#application-property) { get; } | Application reference for this bot | | [BotUser](#botuser-property) { get; } | Bot User | -| [Initialized](#initialized-property) { get; } | If the connection is initialized and not disconnected | | [IsFullyLoaded](#isfullyloaded-property) { get; } | Returns if the bot has fully loaded. All guilds are loaded and if GuildMembers is specified all guild members have been loaded | | [IsReady](#isready-property) { get; } | Returns if ReadyData is set | -| [Rest](#rest-property) { get; } | Rest handler for all discord API calls | -| readonly [Clients](#clients-field) | List of all clients that are using this bot client | -| readonly [DirectMessagesByChannelId](#directmessagesbychannelid-field) | All the direct messages that we have seen by channel Id | +| readonly [DirectMessagesByChannelId](#directmessagesbychannelid-field) | All the direct messages that we have seen by channel ID | | readonly [DirectMessagesByUserId](#directmessagesbyuserid-field) | All the direct messages that we have seen by User ID | | readonly [Servers](#servers-field) | All the servers that this bot is in | -| [AddClient](#addclient-method)(…) | Add a client to this bot client | +| override [AddClient](#addclient-method)(…) | | | [AddDirectChannel](#adddirectchannel-method)(…) | Adds a Direct Message Channel to the bot cache | | [AddGuild](#addguild-method)(…) | Adds a guild to the list of servers a bot is in | | [AddGuildOrUpdate](#addguildorupdate-method)(…) | Adds a guild if it does not exist or updates the guild with | -| [ConnectWebSocket](#connectwebsocket-method)() | Connects the websocket to discord. Should only be called if the websocket is disconnected | | [DisconnectWebsocket](#disconnectwebsocket-method)(…) | Close the websocket with discord | -| [GetChannel](#getchannel-method)(…) | Returns the channel for the given channel ID. If guild ID is null it will search for a direct message channel If guild ID is not null it will search for a guild channel | -| [GetClientPluginList](#getclientpluginlist-method)() | Returns the list of plugins for this bot | +| [GetChannel](#getchannel-method)(…) | Returns the channel for the given channel ID. If guild ID is null, it will search for a direct message channel If guild ID is not null, it will search for a guild channel | | [GetGuild](#getguild-method)(…) | Returns a guild for the specific ID | | [LogDebug](#logdebug-method)(…) | | -| [RemoveClient](#removeclient-method)(…) | Remove a client from the bot client If not clients are left bot will shutdown | +| override [RemoveClient](#removeclient-method)(…) | | | [RemoveDirectMessageChannel](#removedirectmessagechannel-method)(…) | Removes a direct message channel if it exists | | [SendWebSocketCommand](#sendwebsocketcommand-method)(…) | Sends a websocket command | ## See Also +* class [BaseClient](./BaseClient.md) * interface [IDebugLoggable](../Interfaces/IDebugLoggable.md) * namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) * [BotClient.cs](../../../../Oxide.Ext.Discord/Clients/BotClient.cs)     -# ConnectWebSocket method - -Connects the websocket to discord. Should only be called if the websocket is disconnected - -```csharp -public void ConnectWebSocket() -``` - -## See Also - -* class [BotClient](./BotClient.md) -* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  # DisconnectWebsocket method Close the websocket with discord @@ -80,21 +61,13 @@ public void DisconnectWebsocket(bool reconnect = false, bool resume = false)   # AddClient method -Add a client to this bot client - ```csharp -public void AddClient(DiscordClient client, PluginSetup setup) +public override void AddClient(DiscordClient client) ``` -| parameter | description | -| --- | --- | -| client | Client to add to the bot | -| setup | Setup data for the plugin | - ## See Also * class [DiscordClient](./DiscordClient.md) -* class [PluginSetup](../Plugins/PluginSetup.md) * class [BotClient](./BotClient.md) * namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) @@ -102,34 +75,13 @@ public void AddClient(DiscordClient client, PluginSetup setup)   # RemoveClient method -Remove a client from the bot client If not clients are left bot will shutdown - ```csharp -public void RemoveClient(DiscordClient client) +public override bool RemoveClient(DiscordClient client) ``` -| parameter | description | -| --- | --- | -| client | Client to remove from bot client | - ## See Also * class [DiscordClient](./DiscordClient.md) -* class [BotClient](./BotClient.md) -* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# GetClientPluginList method - -Returns the list of plugins for this bot - -```csharp -public string GetClientPluginList() -``` - -## See Also - * class [BotClient](./BotClient.md) * namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) @@ -185,7 +137,7 @@ Guild with the specified ID   # GetChannel method -Returns the channel for the given channel ID. If guild ID is null it will search for a direct message channel If guild ID is not null it will search for a guild channel +Returns the channel for the given channel ID. If guild ID is null, it will search for a direct message channel If guild ID is not null, it will search for a guild channel ```csharp public DiscordChannel GetChannel(Snowflake channelId, Snowflake? guildId) @@ -314,21 +266,6 @@ public BotClient(BotConnection connection) ## See Also * class [BotConnection](../Connections/BotConnection.md) -* class [BotClient](./BotClient.md) -* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# Initialized property - -If the connection is initialized and not disconnected - -```csharp -public bool Initialized { get; } -``` - -## See Also - * class [BotClient](./BotClient.md) * namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) @@ -366,22 +303,6 @@ public DiscordUser BotUser { get; } * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     -# Rest property - -Rest handler for all discord API calls - -```csharp -public RestHandler Rest { get; } -``` - -## See Also - -* class [RestHandler](../Rest/RestHandler.md) -* class [BotClient](./BotClient.md) -* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  # IsFullyLoaded property Returns if the bot has fully loaded. All guilds are loaded and if GuildMembers is specified all guild members have been loaded @@ -431,7 +352,7 @@ public readonly Hash Servers;   # DirectMessagesByChannelId field -All the direct messages that we have seen by channel Id +All the direct messages that we have seen by channel ID ```csharp public readonly Hash DirectMessagesByChannelId; @@ -461,21 +382,5 @@ public readonly Hash DirectMessagesByUserId; * class [BotClient](./BotClient.md) * namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# Clients field - -List of all clients that are using this bot client - -```csharp -public readonly IReadOnlyList Clients; -``` - -## See Also - -* class [DiscordClient](./DiscordClient.md) -* class [BotClient](./BotClient.md) -* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Clients/ClientsNamespace.md b/Docs/Generated/Oxide.Ext.Discord/Clients/ClientsNamespace.md index d202f942c..5bb2cea16 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Clients/ClientsNamespace.md +++ b/Docs/Generated/Oxide.Ext.Discord/Clients/ClientsNamespace.md @@ -2,7 +2,9 @@ | public type | description | | --- | --- | -| class [BotClient](./BotClient.md) | Represents a bot that is connected to discord | -| class [DiscordClient](./DiscordClient.md) | Represents the object a plugin uses to connects to discord | +| abstract class [BaseClient](./BaseClient.md) | BaseClient that can connect to discord | +| class [BotClient](./BotClient.md) | Represents a bot connected to discord | +| class [DiscordClient](./DiscordClient.md) | Represents the object a plugin uses to connect to discord | +| class [WebhookClient](./WebhookClient.md) | A client that can connect to a webhook | diff --git a/Docs/Generated/Oxide.Ext.Discord/Clients/DiscordClient.md b/Docs/Generated/Oxide.Ext.Discord/Clients/DiscordClient.md index 0ddd6f624..45a780c8e 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Clients/DiscordClient.md +++ b/Docs/Generated/Oxide.Ext.Discord/Clients/DiscordClient.md @@ -1,6 +1,6 @@ # DiscordClient class -Represents the object a plugin uses to connects to discord +Represents the object a plugin uses to connect to discord ```csharp public class DiscordClient @@ -11,14 +11,16 @@ public class DiscordClient | name | description | | --- | --- | | [Bot](#bot-property) { get; } | The bot client that is unique to the Token used | +| [JsonSettings](#jsonsettings-property) { get; } | | | [Plugin](#plugin-property) { get; } | Which plugin is the owner of this client | | readonly [PluginId](#pluginid-field) | The ID of the plugin | | readonly [PluginName](#pluginname-field) | The full plugin name including author and version | -| [Connect](#connect-method-1-of-2)(…) | Starts a connection to discord with the given apiKey and intents (2 methods) | +| readonly [Webhooks](#webhooks-field) | Webhook clients for this DiscordClient | +| [Connect](#connect-method-1-of-4)(…) | Starts a connection to discord with the given apiKey and intents (4 methods) | | [Disconnect](#disconnect-method)() | Disconnects this client from discord | -| [IsConnected](#isconnected-method)() | Returns if the client is connected to a bot and if the bot is initialized | +| [IsConnected](#isconnected-method)() | Returns if the client is connected to a bot / webhook and if the bot / webhook is initialized | | [RequestGuildMembers](#requestguildmembers-method)(…) | Used to request guild members from discord for a specific guild | -| [UpdateStatus](#updatestatus-method)(…) | Used to update the bots status in discord | +| [UpdateStatus](#updatestatus-method)(…) | Used to update the bot status in discord | | [UpdateVoiceState](#updatevoicestate-method)(…) | Used to update the voice state for the bot | ## See Also @@ -28,7 +30,7 @@ public class DiscordClient * [DiscordClient.cs](../../../../Oxide.Ext.Discord/Clients/DiscordClient.cs)     -# Connect method (1 of 2) +# Connect method (1 of 4) Starts a connection to discord with the given discord settings @@ -49,7 +51,50 @@ public void Connect(BotConnection connection) --- -# Connect method (2 of 2) +# Connect method (2 of 4) + +Connect to the webhook + +```csharp +public WebhookClient Connect(string webhookUrl) +``` + +| parameter | description | +| --- | --- | +| webhookUrl | Webhook URL to connect to | + +## See Also + +* class [WebhookClient](./WebhookClient.md) +* class [DiscordClient](./DiscordClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Connect method (3 of 4) + +Connect to the webhook + +```csharp +public WebhookClient Connect(WebhookConnection connection) +``` + +| parameter | description | +| --- | --- | +| connection | Webhook connection to connect to | + +## See Also + +* class [WebhookClient](./WebhookClient.md) +* class [WebhookConnection](../Connections/WebhookConnection.md) +* class [DiscordClient](./DiscordClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Connect method (4 of 4) Starts a connection to discord with the given apiKey and intents @@ -60,7 +105,7 @@ public void Connect(string apiKey, GatewayIntents intents) | parameter | description | | --- | --- | | apiKey | API key for the connecting bot | -| intents | Intents the bot needs in order to function | +| intents | Intents the bot needs to function | ## See Also @@ -87,7 +132,7 @@ public void Disconnect()   # IsConnected method -Returns if the client is connected to a bot and if the bot is initialized +Returns if the client is connected to a bot / webhook and if the bot / webhook is initialized ```csharp public bool IsConnected() @@ -142,7 +187,7 @@ public void UpdateVoiceState(UpdateVoiceStatusCommand voiceState)   # UpdateStatus method -Used to update the bots status in discord +Used to update the bot status in discord ```csharp public void UpdateStatus(UpdatePresenceCommand presenceUpdate) @@ -186,6 +231,19 @@ public BotClient Bot { get; } ## See Also * class [BotClient](./BotClient.md) +* class [DiscordClient](./DiscordClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# JsonSettings property + +```csharp +public JsonSerializerSettings JsonSettings { get; } +``` + +## See Also + * class [DiscordClient](./DiscordClient.md) * namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) @@ -217,6 +275,22 @@ public readonly string PluginName; ## See Also +* class [DiscordClient](./DiscordClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Webhooks field + +Webhook clients for this DiscordClient + +```csharp +public readonly IReadOnlyList Webhooks; +``` + +## See Also + +* class [WebhookClient](./WebhookClient.md) * class [DiscordClient](./DiscordClient.md) * namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Clients/WebhookClient.md b/Docs/Generated/Oxide.Ext.Discord/Clients/WebhookClient.md new file mode 100644 index 000000000..8695a6359 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Clients/WebhookClient.md @@ -0,0 +1,90 @@ +# WebhookClient class + +A client that can connect to a webhook + +```csharp +public class WebhookClient : BaseClient, IDebugLoggable +``` + +## Public Members + +| name | description | +| --- | --- | +| [WebhookClient](#webhookclient-constructor)(…) | Constructor | +| [Webhook](#webhook-property) { get; } | Webhook that has been connected to | +| override [AddClient](#addclient-method)(…) | | +| [LogDebug](#logdebug-method)(…) | | + +## See Also + +* class [BaseClient](./BaseClient.md) +* interface [IDebugLoggable](../Interfaces/IDebugLoggable.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [WebhookClient.cs](../../../../Oxide.Ext.Discord/Clients/WebhookClient.cs) +  +  +# AddClient method + +```csharp +public override void AddClient(DiscordClient client) +``` + +## See Also + +* class [DiscordClient](./DiscordClient.md) +* class [WebhookClient](./WebhookClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# LogDebug method + +```csharp +public void LogDebug(DebugLogger logger) +``` + +## See Also + +* class [DebugLogger](../Logging/DebugLogger.md) +* class [WebhookClient](./WebhookClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# WebhookClient constructor + +Constructor + +```csharp +public WebhookClient(WebhookConnection connection) +``` + +| parameter | description | +| --- | --- | +| connection | Connection for the webhook | + +## See Also + +* class [WebhookConnection](../Connections/WebhookConnection.md) +* class [WebhookClient](./WebhookClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Webhook property + +Webhook that has been connected to + +```csharp +public DiscordWebhook Webhook { get; } +``` + +## See Also + +* class [DiscordWebhook](../Entities/DiscordWebhook.md) +* class [WebhookClient](./WebhookClient.md) +* namespace [Oxide.Ext.Discord.Clients](./ClientsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Connections/BotConnection.md b/Docs/Generated/Oxide.Ext.Discord/Connections/BotConnection.md index a7203b487..55d95c8a5 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Connections/BotConnection.md +++ b/Docs/Generated/Oxide.Ext.Discord/Connections/BotConnection.md @@ -17,8 +17,8 @@ public class BotConnection | [HiddenToken](#hiddentoken-property) { get; } | Hidden Bot Token. Used when needing to display the token. | | [Intents](#intents-property) { get; set; } | Intents that your bot needs to work See [`GatewayIntents`](../Entities/GatewayIntents.md) | | [LogLevel](#loglevel-property) { get; set; } | Discord Extension Logging Level. See [`DiscordLogLevel`](../Logging/DiscordLogLevel.md) | -| [HasAnyIntent](#hasanyintent-method)(…) | Returns if the settings has any intent specified | -| [HasIntents](#hasintents-method)(…) | Returns if the settings has the given intents | +| [HasAnyIntent](#hasanyintent-method)(…) | Returns if the settings have any intent specified | +| [HasIntents](#hasintents-method)(…) | Returns if the settings have the given intents | ## See Also @@ -29,7 +29,7 @@ public class BotConnection   # HasIntents method -Returns if the settings has the given intents +Returns if the settings have the given intents ```csharp public bool HasIntents(GatewayIntents intents) @@ -41,7 +41,7 @@ public bool HasIntents(GatewayIntents intents) ## Return Value -True if settings has the given intents; False otherwise +True if settings have the given intents; False otherwise ## See Also @@ -53,7 +53,7 @@ True if settings has the given intents; False otherwise   # HasAnyIntent method -Returns if the settings has any intent specified +Returns if the settings have any intent specified ```csharp public bool HasAnyIntent(GatewayIntents intents) @@ -65,7 +65,7 @@ public bool HasAnyIntent(GatewayIntents intents) ## Return Value -True if settings has at least one of the given intents +True if settings have at least one of the given intents ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Connections/ConnectionsNamespace.md b/Docs/Generated/Oxide.Ext.Discord/Connections/ConnectionsNamespace.md index b4eb1aff6..f079ad5d2 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Connections/ConnectionsNamespace.md +++ b/Docs/Generated/Oxide.Ext.Discord/Connections/ConnectionsNamespace.md @@ -4,5 +4,6 @@ | --- | --- | | class [BotConnection](./BotConnection.md) | Bot Connection Settings | | class [BotTokenData](./BotTokenData.md) | Represents the parsed Bot Token data | +| class [WebhookConnection](./WebhookConnection.md) | Connection for a webhook | diff --git a/Docs/Generated/Oxide.Ext.Discord/Connections/WebhookConnection.md b/Docs/Generated/Oxide.Ext.Discord/Connections/WebhookConnection.md new file mode 100644 index 000000000..70568076b --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Connections/WebhookConnection.md @@ -0,0 +1,106 @@ +# WebhookConnection class + +Connection for a webhook + +```csharp +public class WebhookConnection +``` + +## Public Members + +| name | description | +| --- | --- | +| [WebhookConnection](#webhookconnection-constructor)(…) | Constructor for a webhook connection | +| [LogLevel](#loglevel-property) { get; set; } | Discord Extension Logging Level. See [`DiscordLogLevel`](../Logging/DiscordLogLevel.md) | +| readonly [WebhookId](#webhookid-field) | API token for the bot | +| readonly [WebhookToken](#webhooktoken-field) | Token for the webhook | +| readonly [WebhookUrl](#webhookurl-field) | | + +## See Also + +* namespace [Oxide.Ext.Discord.Connections](./ConnectionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [WebhookConnection.cs](../../../../Oxide.Ext.Discord/Connections/WebhookConnection.cs) +  +  +# WebhookConnection constructor + +Constructor for a webhook connection + +```csharp +public WebhookConnection(string webhookUrl, DiscordLogLevel logLevel = DiscordLogLevel.Info) +``` + +| parameter | description | +| --- | --- | +| webhookUrl | URL of the webhook | +| logLevel | Log level for the webhook | + +## See Also + +* enum [DiscordLogLevel](../Logging/DiscordLogLevel.md) +* class [WebhookConnection](./WebhookConnection.md) +* namespace [Oxide.Ext.Discord.Connections](./ConnectionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# LogLevel property + +Discord Extension Logging Level. See [`DiscordLogLevel`](../Logging/DiscordLogLevel.md) + +```csharp +public DiscordLogLevel LogLevel { get; set; } +``` + +## See Also + +* enum [DiscordLogLevel](../Logging/DiscordLogLevel.md) +* class [WebhookConnection](./WebhookConnection.md) +* namespace [Oxide.Ext.Discord.Connections](./ConnectionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# WebhookId field + +API token for the bot + +```csharp +public readonly Snowflake WebhookId; +``` + +## See Also + +* struct [Snowflake](../Entities/Snowflake.md) +* class [WebhookConnection](./WebhookConnection.md) +* namespace [Oxide.Ext.Discord.Connections](./ConnectionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# WebhookToken field + +Token for the webhook + +```csharp +public readonly string WebhookToken; +``` + +## See Also + +* class [WebhookConnection](./WebhookConnection.md) +* namespace [Oxide.Ext.Discord.Connections](./ConnectionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# WebhookUrl field + +```csharp +public readonly string WebhookUrl; +``` + +## See Also + +* class [WebhookConnection](./WebhookConnection.md) +* namespace [Oxide.Ext.Discord.Connections](./ConnectionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Constants/DiscordExtHooks.md b/Docs/Generated/Oxide.Ext.Discord/Constants/DiscordExtHooks.md index 2cfafe3dd..bc7278770 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Constants/DiscordExtHooks.md +++ b/Docs/Generated/Oxide.Ext.Discord/Constants/DiscordExtHooks.md @@ -108,11 +108,13 @@ public static class DiscordExtHooks | const [OnDiscordPlayerLinked](#ondiscordplayerlinked-field) | These hooks are called when a player is linked or unlinked using discord link. It will be called for every plugins registered to receive hooks. **Note:** If your plugin supports discord link you should not supply any other hooks as the extension provides them for you. **Note:** Discord Link hooks are considered global hooks and will be called on all plugins regardless of bot | | const [OnDiscordPlayerUnlink](#ondiscordplayerunlink-field) | Called when a player is being unlinked from DiscordLink Library This is called before the unlink occurs | | const [OnDiscordPlayerUnlinked](#ondiscordplayerunlinked-field) | Called when a player has unlinked their discord and player together using the DiscordLink library | +| const [OnDiscordPollVoteAdded](#ondiscordpollvoteadded-field) | Called when we receive an event we do not handle yet. If you need this event, you can listen to it using this hook until we support it Please create an issue on uMod if this error ever occurs | +| const [OnDiscordPollVoteRemoved](#ondiscordpollvoteremoved-field) | | | const [OnDiscordSetupHeartbeat](#ondiscordsetupheartbeat-field) | Called when we receive the heartbeat interval from the websocket | | const [OnDiscordStageInstanceCreated](#ondiscordstageinstancecreated-field) | Called when a stage instance is created | | const [OnDiscordStageInstanceDeleted](#ondiscordstageinstancedeleted-field) | Called when a stage instance is deleted | | const [OnDiscordStageInstanceUpdated](#ondiscordstageinstanceupdated-field) | Called when a stage instance is updated | -| const [OnDiscordUnhandledCommand](#ondiscordunhandledcommand-field) | Called when we receive an event we do not handle yet. If you need this event, you can listen to it using this hook until we support it Please create an issue on uMod if this error ever occurs | +| const [OnDiscordUnhandledCommand](#ondiscordunhandledcommand-field) | void OnDiscordUnhandledCommand(EventPayload payload) { Puts("OnDiscordUnhandledCommand Works!"); } | | const [OnDiscordUserUpdated](#ondiscorduserupdated-field) | Called when a discord user is updated | | const [OnDiscordWebsocketClosed](#ondiscordwebsocketclosed-field) | Called when the web socket is closed for any reason. | | const [OnDiscordWebsocketErrored](#ondiscordwebsocketerrored-field) | Called when the web socket has an error. | @@ -2513,10 +2515,43 @@ public const string OnDiscordAutoModActionExecuted; * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     -# OnDiscordUnhandledCommand field +# OnDiscordPollVoteAdded field Called when we receive an event we do not handle yet. If you need this event, you can listen to it using this hook until we support it Please create an issue on uMod if this error ever occurs +```csharp +void OnDiscordPollVoteAdded(MessagePollVoteAddedEvent vote, DiscordGuild guild) +{ + Puts("OnDiscordPollVoteAdded Works!"); +} +``` + +```csharp +public const string OnDiscordPollVoteAdded; +``` + +## See Also + +* class [DiscordExtHooks](./DiscordExtHooks.md) +* namespace [Oxide.Ext.Discord.Constants](./ConstantsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# OnDiscordPollVoteRemoved field + +```csharp +public const string OnDiscordPollVoteRemoved; +``` + +## See Also + +* class [DiscordExtHooks](./DiscordExtHooks.md) +* namespace [Oxide.Ext.Discord.Constants](./ConstantsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# OnDiscordUnhandledCommand field + ```csharp void OnDiscordUnhandledCommand(EventPayload payload) { diff --git a/Docs/Generated/Oxide.Ext.Discord/Constants/RateLimitHeaders.md b/Docs/Generated/Oxide.Ext.Discord/Constants/RateLimitHeaders.md index c2e642ccf..90b97681f 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Constants/RateLimitHeaders.md +++ b/Docs/Generated/Oxide.Ext.Discord/Constants/RateLimitHeaders.md @@ -14,7 +14,7 @@ public static class RateLimitHeaders | const [BucketLimit](#bucketlimit-field) | The number of requests that can be made | | const [BucketRemaining](#bucketremaining-field) | The number of remaining requests that can be made | | const [BucketReset](#bucketreset-field) | Epoch time (seconds since 00:00:00 UTC on January 1, 1970) at which the rate limit resets | -| const [BucketResetAfter](#bucketresetafter-field) | Total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond ratelimit precision | +| const [BucketResetAfter](#bucketresetafter-field) | Total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond rate-limit precision | | const [IsGlobal](#isglobal-field) | Returned only on HTTP 429 responses if the rate limit encountered is the global rate limit (not per-route) | | const [RetryAfter](#retryafter-field) | The number of seconds to wait before submitting another request. | | const [Scope](#scope-field) | Scope of the rate limit | @@ -103,7 +103,7 @@ public const string BucketRemaining;   # BucketResetAfter field -Total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond ratelimit precision +Total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond rate-limit precision ```csharp public const string BucketResetAfter; diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ActivityType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ActivityType.md index d47de163b..727a0198d 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/ActivityType.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ActivityType.md @@ -11,6 +11,7 @@ public enum ActivityType : byte | name | value | description | | --- | --- | --- | | Game | `Game` | | +| Playing | `Game` | | | Streaming | `Streaming` | | | Listening | `Listening` | | | Watching | `Watching` | | diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationEmojiCreate.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationEmojiCreate.md new file mode 100644 index 000000000..ecf10778f --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationEmojiCreate.md @@ -0,0 +1,83 @@ +# ApplicationEmojiCreate class + +Represents [Application Emoji Create Structure](https://discord.com/developers/docs/resources/emoji#create-application-emoji-json-params) + +```csharp +public class ApplicationEmojiCreate +``` + +## Public Members + +| name | description | +| --- | --- | +| [ApplicationEmojiCreate](#applicationemojicreate-constructor)() | The default constructor. | +| [ImageData](#imagedata-property) { get; set; } | The 128x128 emoji image Emojis and animated emojis have a maximum file size of 256kb. Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request | +| [Name](#name-property) { get; set; } | Emoji name | +| [Validate](#validate-method)() | | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [ApplicationEmojiCreate.cs](../../../../Oxide.Ext.Discord/Entities/ApplicationEmojiCreate.cs) +  +  +# Validate method + +```csharp +public void Validate() +``` + +## See Also + +* class [ApplicationEmojiCreate](./ApplicationEmojiCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# ApplicationEmojiCreate constructor + +The default constructor. + +```csharp +public ApplicationEmojiCreate() +``` + +## See Also + +* class [ApplicationEmojiCreate](./ApplicationEmojiCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Name property + +Emoji name + +```csharp +public string Name { get; set; } +``` + +## See Also + +* class [ApplicationEmojiCreate](./ApplicationEmojiCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# ImageData property + +The 128x128 emoji image Emojis and animated emojis have a maximum file size of 256kb. Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request + +```csharp +public DiscordImageData ImageData { get; set; } +``` + +## See Also + +* struct [DiscordImageData](./DiscordImageData.md) +* class [ApplicationEmojiCreate](./ApplicationEmojiCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationEmojiUpdate.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationEmojiUpdate.md new file mode 100644 index 000000000..7c95f9a5f --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationEmojiUpdate.md @@ -0,0 +1,66 @@ +# ApplicationEmojiUpdate class + +Represents [Emoji Update Structure](https://discord.com/developers/docs/resources/emoji#modify-guild-emoji-json-params) + +```csharp +public class ApplicationEmojiUpdate +``` + +## Public Members + +| name | description | +| --- | --- | +| [ApplicationEmojiUpdate](#applicationemojiupdate-constructor)() | The default constructor. | +| [Name](#name-property) { get; set; } | Emoji name | +| [Validate](#validate-method)() | | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [ApplicationEmojiUpdate.cs](../../../../Oxide.Ext.Discord/Entities/ApplicationEmojiUpdate.cs) +  +  +# Validate method + +```csharp +public void Validate() +``` + +## See Also + +* class [ApplicationEmojiUpdate](./ApplicationEmojiUpdate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# ApplicationEmojiUpdate constructor + +The default constructor. + +```csharp +public ApplicationEmojiUpdate() +``` + +## See Also + +* class [ApplicationEmojiUpdate](./ApplicationEmojiUpdate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Name property + +Emoji name + +```csharp +public string Name { get; set; } +``` + +## See Also + +* class [ApplicationEmojiUpdate](./ApplicationEmojiUpdate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationEmojis.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationEmojis.md new file mode 100644 index 000000000..0bae21dd3 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationEmojis.md @@ -0,0 +1,53 @@ +# ApplicationEmojis class + +Represents [Application Emojis](https://discord.com/developers/docs/resources/emoji#list-application-emojis) + +```csharp +public class ApplicationEmojis +``` + +## Public Members + +| name | description | +| --- | --- | +| [ApplicationEmojis](#applicationemojis-constructor)() | The default constructor. | +| [Items](#items-property) { get; set; } | List of application emojis | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [ApplicationEmojis.cs](../../../../Oxide.Ext.Discord/Entities/ApplicationEmojis.cs) +  +  +# ApplicationEmojis constructor + +The default constructor. + +```csharp +public ApplicationEmojis() +``` + +## See Also + +* class [ApplicationEmojis](./ApplicationEmojis.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Items property + +List of application emojis + +```csharp +public List Items { get; set; } +``` + +## See Also + +* class [DiscordEmoji](./DiscordEmoji.md) +* class [ApplicationEmojis](./ApplicationEmojis.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationIntegrationType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationIntegrationType.md new file mode 100644 index 000000000..2b1839c90 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationIntegrationType.md @@ -0,0 +1,22 @@ +# ApplicationIntegrationType enumeration + +Represents a [Application Integration Types](https://discord.com/developers/docs/resources/application#application-object-application-integration-types) + +```csharp +public enum ApplicationIntegrationType +``` + +## Values + +| name | value | description | +| --- | --- | --- | +| GuildInstall | `GuildInstall` | App is installable to servers | +| UserInstall | `UserInstall` | App is installable to users | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [ApplicationIntegrationType.cs](../../../../Oxide.Ext.Discord/Entities/ApplicationIntegrationType.cs) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationIntegrationTypeConfiguration.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationIntegrationTypeConfiguration.md new file mode 100644 index 000000000..86fa2fb92 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationIntegrationTypeConfiguration.md @@ -0,0 +1,53 @@ +# ApplicationIntegrationTypeConfiguration class + +Represents a [Application Integration Type Configuration](https://discord.com/developers/docs/resources/application#application-object-application-integration-type-configuration-object) + +```csharp +public class ApplicationIntegrationTypeConfiguration +``` + +## Public Members + +| name | description | +| --- | --- | +| [ApplicationIntegrationTypeConfiguration](#applicationintegrationtypeconfiguration-constructor)() | The default constructor. | +| [Oauth2InstallParams](#oauth2installparams-property) { get; set; } | Install params for each installation context's default in-app authorization link | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [ApplicationIntegrationTypeConfiguration.cs](../../../../Oxide.Ext.Discord/Entities/ApplicationIntegrationTypeConfiguration.cs) +  +  +# ApplicationIntegrationTypeConfiguration constructor + +The default constructor. + +```csharp +public ApplicationIntegrationTypeConfiguration() +``` + +## See Also + +* class [ApplicationIntegrationTypeConfiguration](./ApplicationIntegrationTypeConfiguration.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Oauth2InstallParams property + +Install params for each installation context's default in-app authorization link + +```csharp +public InstallParams Oauth2InstallParams { get; set; } +``` + +## See Also + +* class [InstallParams](./InstallParams.md) +* class [ApplicationIntegrationTypeConfiguration](./ApplicationIntegrationTypeConfiguration.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationUpdate.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationUpdate.md index ac26f2fb1..435a3d93b 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationUpdate.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ApplicationUpdate.md @@ -17,6 +17,7 @@ public class ApplicationUpdate | [Flags](#flags-property) { get; set; } | App's public flags | | [Icon](#icon-property) { get; set; } | Icon for the app | | [InstallParams](#installparams-property) { get; set; } | Settings for the application's default in-app authorization link, if enabled | +| [IntegrationTypesConfig](#integrationtypesconfig-property) { get; set; } | Default scopes and permissions for each supported installation context. | | [InteractionsEndpointUrl](#interactionsendpointurl-property) { get; set; } | Interactions endpoint URL for the app | | [RoleConnectionsVerificationUrl](#roleconnectionsverificationurl-property) { get; set; } | Role connection verification URL for the app | | [Tags](#tags-property) { get; set; } | List of tags describing the content and functionality of the app (max of 20 characters per tag). Max of 5 tags. | @@ -104,6 +105,24 @@ public InstallParams InstallParams { get; set; } * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# IntegrationTypesConfig property + +Default scopes and permissions for each supported installation context. + +```csharp +public Hash + IntegrationTypesConfig { get; set; } +``` + +## See Also + +* enum [ApplicationIntegrationType](./ApplicationIntegrationType.md) +* class [ApplicationIntegrationTypeConfiguration](./ApplicationIntegrationTypeConfiguration.md) +* class [ApplicationUpdate](./ApplicationUpdate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # Flags property App's public flags diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModActionType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModActionType.md index a7e63233d..cb4b776c3 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModActionType.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModActionType.md @@ -13,6 +13,7 @@ public enum AutoModActionType : byte | BlockMessage | `BlockMessage` | Blocks the content of a message according to the rule | | SendAlertMessage | `SendAlertMessage` | Logs user content to a specified channel | | Timeout | `Timeout` | Timeout user for a specified duration A TIMEOUT action can only be setup for KEYWORD rules. MODERATE_MEMBERS permission is required to use the TIMEOUT action type. | +| BlockMemberInteraction | `BlockMemberInteraction` | Prevents a member from using text, voice, or other interactions | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModEventType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModEventType.md index 4c71a7238..3624757bf 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModEventType.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModEventType.md @@ -11,6 +11,7 @@ public enum AutoModEventType : byte | name | value | description | | --- | --- | --- | | MessageSend | `MessageSend` | When a member sends or edits a message in the guild | +| MemberUpdate | `MessageSend` | When a member edits their profile | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModTriggerType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModTriggerType.md index ac41ac318..348269f61 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModTriggerType.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/AutoModTriggerType.md @@ -14,6 +14,7 @@ public enum AutoModTriggerType : byte | Spam | `Spam` | Check if content represents generic spam | | KeywordPreset | `KeywordPreset` | Check if content contains words from internal pre-defined wordsets | | MentionSpam | `MentionSpam` | Check if content contains more unique mentions than allowed | +| MemberProfile | `MemberProfile` | Check if member profile contains words from a user defined list of keywords | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/AvatarDecorationData.md b/Docs/Generated/Oxide.Ext.Discord/Entities/AvatarDecorationData.md new file mode 100644 index 000000000..2c5b6314f --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/AvatarDecorationData.md @@ -0,0 +1,69 @@ +# AvatarDecorationData class + +Represents [Avatar Decoration Structure](https://discord.com/developers/docs/resources/user#avatar-decoration-data-object-avatar-decoration-data-structure) + +```csharp +public class AvatarDecorationData +``` + +## Public Members + +| name | description | +| --- | --- | +| [AvatarDecorationData](#avatardecorationdata-constructor)() | The default constructor. | +| [Asset](#asset-property) { get; set; } | The avatar decoration hash | +| [SkuId](#skuid-property) { get; set; } | Id of the avatar decoration's SKU | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [AvatarDecorationData.cs](../../../../Oxide.Ext.Discord/Entities/AvatarDecorationData.cs) +  +  +# AvatarDecorationData constructor + +The default constructor. + +```csharp +public AvatarDecorationData() +``` + +## See Also + +* class [AvatarDecorationData](./AvatarDecorationData.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Asset property + +The avatar decoration hash + +```csharp +public string Asset { get; set; } +``` + +## See Also + +* class [AvatarDecorationData](./AvatarDecorationData.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# SkuId property + +Id of the avatar decoration's SKU + +```csharp +public Snowflake SkuId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [AvatarDecorationData](./AvatarDecorationData.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/BaseMessageCreate.md b/Docs/Generated/Oxide.Ext.Discord/Entities/BaseMessageCreate.md index 8ace60250..d2c9cd002 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/BaseMessageCreate.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/BaseMessageCreate.md @@ -17,6 +17,7 @@ public abstract class BaseMessageCreate : IDiscordMessageTemplate, IFileAttachme | [Embeds](#embeds-property) { get; set; } | Embeds for the message Embeds are deduplicated by URL. If a message contains multiple embeds with the same URL, only the first is shown. | | [FileAttachments](#fileattachments-property) { get; set; } | Attachments for a discord message | | [Flags](#flags-property) { get; set; } | Attachments for the message | +| [Poll](#poll-property) { get; set; } | Poll Create Request | | [StickerIds](#stickerids-property) { get; set; } | IDs of up to 3 stickers in the server to send in the message | | [Tts](#tts-property) { get; set; } | Whether this was a TTS message | | [AddAttachment](#addattachment-method)(…) | Adds an attachment to the message | @@ -45,7 +46,7 @@ Adds an attachment to the message ```csharp public void AddAttachment(string filename, byte[] data, string contentType, - string description = null) + string description = null, string title = null) ``` | parameter | description | @@ -54,6 +55,7 @@ public void AddAttachment(string filename, byte[] data, string contentType, | data | byte[] of the attachment | | contentType | Attachment content type | | description | Description for the attachment | +| title | Title of the attachment | ## See Also @@ -236,6 +238,22 @@ public MessageFlags? Flags { get; set; } * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# Poll property + +Poll Create Request + +```csharp +public PollCreate Poll { get; set; } +``` + +## See Also + +* class [PollCreate](./PollCreate.md) +* class [BaseMessageCreate](./BaseMessageCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # FileAttachments property Attachments for a discord message diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ButtonComponent.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ButtonComponent.md index 8863a2fd2..27d606aab 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/ButtonComponent.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ButtonComponent.md @@ -14,6 +14,7 @@ public class ButtonComponent : BaseInteractableComponent | [Disabled](#disabled-property) { get; set; } | Whether the button is disabled Default false | | [Emoji](#emoji-property) { get; set; } | Emoji on the component | | [Label](#label-property) { get; set; } | Text that appears on the button Max 80 characters | +| [SkuId](#skuid-property) { get; set; } | Identifier for a purchasable SKU, only available when using premium-style buttons | | [Style](#style-property) { get; set; } | Style for the button component | | [Url](#url-property) { get; set; } | URL for link-style buttons | | override [Validate](#validate-method)() | | @@ -101,6 +102,22 @@ public DiscordEmoji Emoji { get; set; } * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# SkuId property + +Identifier for a purchasable SKU, only available when using premium-style buttons + +```csharp +public Snowflake? SkuId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [ButtonComponent](./ButtonComponent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # Url property URL for link-style buttons diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ButtonStyle.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ButtonStyle.md index 2201eef7f..564445bcc 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/ButtonStyle.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ButtonStyle.md @@ -15,6 +15,7 @@ public enum ButtonStyle : byte | Success | `Success` | Color green Requires CustomId field | | Danger | `Danger` | Color red Requires CustomId field | | Link | `Link` | Color grey Navigates to a URL Requires Url field | +| Premium | `Premium` | Color blurple Navigates to a URL Requires SkuId field | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/CommandCreate.md b/Docs/Generated/Oxide.Ext.Discord/Entities/CommandCreate.md index 961a1b88c..a031b3656 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/CommandCreate.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/CommandCreate.md @@ -12,10 +12,12 @@ public class CommandCreate | --- | --- | | [CommandCreate](#commandcreate-constructor)() | Constructor | | [CommandCreate](#commandcreate-constructor)(…) | Constructor | +| [Contexts](#contexts-property) { get; set; } | Interaction context(s) where the command can be used | | [DefaultMemberPermissions](#defaultmemberpermissions-property) { get; set; } | Set of permissions represented as a bit set | | [Description](#description-property) { get; set; } | Description of the command (1-100 characters) | | [DescriptionLocalizations](#descriptionlocalizations-property) { get; set; } | Localization dictionary for the description field. Values follow the same restrictions as description | | [DmPermission](#dmpermission-property) { get; set; } | Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. | +| [IntegrationTypes](#integrationtypes-property) { get; set; } | Installation context(s) where the command is available | | [Name](#name-property) { get; set; } | 1-32 lowercase character name matching ^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$ | | [NameLocalizations](#namelocalizations-property) { get; set; } | Localization dictionary for the name field. Values follow the same restrictions as name | | [Nsfw](#nsfw-property) { get; set; } | Indicates whether the command is age-restricted | @@ -175,6 +177,7 @@ public PermissionFlags DefaultMemberPermissions { get; set; } Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. ```csharp +[Obsolete("Deprecated (use Contexts instead)")] public bool? DmPermission { get; set; } ``` @@ -185,16 +188,33 @@ public bool? DmPermission { get; set; } * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     -# Nsfw property +# IntegrationTypes property -Indicates whether the command is age-restricted +Installation context(s) where the command is available ```csharp -public bool? Nsfw { get; set; } +public List IntegrationTypes { get; set; } +``` + +## See Also + +* enum [ApplicationIntegrationType](./ApplicationIntegrationType.md) +* class [CommandCreate](./CommandCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Contexts property + +Interaction context(s) where the command can be used + +```csharp +public List Contexts { get; set; } ``` ## See Also +* enum [InteractionContextTypes](./InteractionContextTypes.md) * class [CommandCreate](./CommandCreate.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) @@ -211,6 +231,21 @@ public ApplicationCommandType Type { get; set; } ## See Also * enum [ApplicationCommandType](./ApplicationCommandType.md) +* class [CommandCreate](./CommandCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Nsfw property + +Indicates whether the command is age-restricted + +```csharp +public bool? Nsfw { get; set; } +``` + +## See Also + * class [CommandCreate](./CommandCreate.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/CommandUpdate.md b/Docs/Generated/Oxide.Ext.Discord/Entities/CommandUpdate.md index 50735e8ce..f2a777d6f 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/CommandUpdate.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/CommandUpdate.md @@ -11,11 +11,13 @@ public class CommandUpdate | name | description | | --- | --- | | [CommandUpdate](#commandupdate-constructor)() | The default constructor. | +| [Contexts](#contexts-property) { get; set; } | Interaction context(s) where the command can be used | | [DefaultMemberPermissions](#defaultmemberpermissions-property) { get; set; } | Set of permissions represented as a bit set | | [DefaultPermissions](#defaultpermissions-property) { get; set; } | Whether the command is enabled by default when the app is added to a guild | | [Description](#description-property) { get; set; } | Description of the command (1-100 characters) | | [DescriptionLocalizations](#descriptionlocalizations-property) { get; set; } | Localization dictionary for the description field. Values follow the same restrictions as description | | [DmPermission](#dmpermission-property) { get; set; } | Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. | +| [IntegrationTypes](#integrationtypes-property) { get; set; } | Installation context(s) where the command is available | | [Name](#name-property) { get; set; } | 1-32 lowercase character name matching ^[\w-]{1,32}$ | | [NameLocalizations](#namelocalizations-property) { get; set; } | Localization dictionary for the name field. Values follow the same restrictions as name | | [Nsfw](#nsfw-property) { get; set; } | Indicates whether the command is age-restricted | @@ -140,6 +142,7 @@ public PermissionFlags DefaultMemberPermissions { get; set; } Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. ```csharp +[Obsolete("Deprecated (use Contexts instead)")] public bool? DmPermission { get; set; } ``` @@ -160,6 +163,38 @@ public bool? DefaultPermissions { get; set; } ## See Also +* class [CommandUpdate](./CommandUpdate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# IntegrationTypes property + +Installation context(s) where the command is available + +```csharp +public List IntegrationTypes { get; set; } +``` + +## See Also + +* enum [ApplicationIntegrationType](./ApplicationIntegrationType.md) +* class [CommandUpdate](./CommandUpdate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Contexts property + +Interaction context(s) where the command can be used + +```csharp +public List Contexts { get; set; } +``` + +## See Also + +* enum [InteractionContextTypes](./InteractionContextTypes.md) * class [CommandUpdate](./CommandUpdate.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ConnectionType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ConnectionType.md index a924d5e7e..ebfd470e6 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/ConnectionType.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ConnectionType.md @@ -12,6 +12,8 @@ public enum ConnectionType : byte | --- | --- | --- | | Unknown | `Unknown` | Discord Extension doesn't currently support this connection type | | BattleNet | `BattleNet` | Connection type is Battle.net | +| Bungie | `Bungie` | Connection type is Bungie.net | +| Domain | `Domain` | Connection type is Domain | | eBay | `eBay` | Connection type is Epic Games | | EpicGames | `EpicGames` | Connection type is Epic Games | | Facebook | `Facebook` | Connection type is Facebook | @@ -21,7 +23,8 @@ public enum ConnectionType : byte | LeagueOfLegends | `LeagueOfLegends` | Connection type is League of Legends | | PlayStationNetwork | `PlayStationNetwork` | Connection type is PlayStation Network | | Reddit | `Reddit` | Connection type is Reddit | -| RiotGames | `RiotGames` | Connection type is Reddit | +| RiotGames | `RiotGames` | Connection type is Riot Games | +| Roblox | `Roblox` | Connection type is Roblox | | Spotify | `Spotify` | Connection type is Spotify | | Skype | `Skype` | Connection type is Skype | | Steam | `Steam` | Connection type is Steam | diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordActivity.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordActivity.md index d29e59ecf..4958fee33 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordActivity.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordActivity.md @@ -27,7 +27,7 @@ public class DiscordActivity | [State](#state-property) { get; set; } | The user's current party status | | [Timestamps](#timestamps-property) { get; set; } | Unix timestamps for start and/or end of the game See [`ActivityTimestamps`](./ActivityTimestamps.md) | | [Type](#type-property) { get; set; } | Activity type See [`ActivityType`](./ActivityType.md) | -| [Url](#url-property) { get; set; } | Stream url, is validated when type is 1 | +| [Url](#url-property) { get; set; } | Stream url is validated when type is 1 | ## See Also @@ -84,7 +84,7 @@ public ActivityType Type { get; set; }   # Url property -Stream url, is validated when type is 1 +Stream url is validated when type is 1 ```csharp public string Url { get; set; } @@ -117,7 +117,7 @@ public DateTimeOffset CreatedAt { get; set; } Unix timestamps for start and/or end of the game See [`ActivityTimestamps`](./ActivityTimestamps.md) ```csharp -public List Timestamps { get; set; } +public ActivityTimestamps Timestamps { get; set; } ``` ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordApplication.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordApplication.md index 0fc23ed93..b110284bd 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordApplication.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordApplication.md @@ -26,6 +26,7 @@ public class DiscordApplication : IDebugLoggable | [Icon](#icon-property) { get; set; } | Icon hash of the app | | [Id](#id-property) { get; set; } | ID of the app | | [InstallParams](#installparams-property) { get; set; } | Settings for the application's default in-app authorization link, if enabled | +| [IntegrationTypesConfig](#integrationtypesconfig-property) { get; set; } | Default scopes and permissions for each supported installation context | | [InteractionsEndpointUrl](#interactionsendpointurl-property) { get; set; } | Interactions endpoint URL for the app | | [Name](#name-property) { get; set; } | Name of the app | | [Owner](#owner-property) { get; set; } | Partial user object containing info on the owner of the application | @@ -40,11 +41,15 @@ public class DiscordApplication : IDebugLoggable | [TermsOfServiceUrl](#termsofserviceurl-property) { get; set; } | URL of the app's terms of service | | [Verify](#verify-property) { get; set; } | Hex encoded key for verification in interactions and the GameSDK's GetTicket | | [BulkOverwriteGlobalCommands](#bulkoverwriteglobalcommands-method)(…) | Takes a list of application commands, overwriting existing commands that are registered globally for this application. Updates will be available in all guilds after 1 hour. See [Bulk Overwrite Global Application Commands](https://discord.com/developers/docs/interactions/application-commands#bulk-overwrite-global-application-commands) | +| [CreateApplicationEmoji](#createapplicationemoji-method)(…) | Creates a new application emoji | | [CreateGlobalCommand](#createglobalcommand-method)(…) | Create a new global command. New global commands will be available in all guilds after 1 hour. Note: Creating a command with the same name as an existing command for your application will overwrite the old command. See [Create Global Application Command](https://discord.com/developers/docs/interactions/application-commands#create-global-application-command) | | [CreateGuildCommand](#createguildcommand-method)(…) | Create a new guild command. New guild commands will be available in the guild immediately. See [Create Guild Application Command](https://discord.com/developers/docs/interactions/application-commands#create-guild-application-command) | +| [DeleteApplicationEmoji](#deleteapplicationemoji-method)(…) | Deletes an application emoji | | [Edit](#edit-method)(…) | Edit properties of the app associated with the requesting bot user. Only properties that are passed will be updated. | | [EditRoleConnectionMetadata](#editroleconnectionmetadata-method)(…) | Updates and returns a list of application role connection metadata objects for the given application. See [Update Application Role Connection Metadata Records](https://discord.com/developers/docs/resources/application-role-connection-metadata#update-application-role-connection-metadata-records) | | [GetAllCommands](#getallcommands-method)(…) | Returns all commands registered to this application | +| [GetApplicationEmoji](#getapplicationemoji-method)(…) | Return an application emoji by ID | +| [GetApplicationEmojis](#getapplicationemojis-method)(…) | Returns the list of all application emojis | | [GetGlobalCommand](#getglobalcommand-method)(…) | Fetch global command by ID See [Get Global Application Command](https://discord.com/developers/docs/interactions/application-commands#get-global-application-command) | | [GetGlobalCommands](#getglobalcommands-method)(…) | Fetch all of the global commands for your application. Returns a list of ApplicationCommand. See [Get Global Application Commands](https://discord.com/developers/docs/interactions/application-commands#get-global-application-commands)Client to useInclude Command Localizations | | [GetGuildCommand](#getguildcommand-method)(…) | Get guild command by Id See [Get Guild Application Command](https://discord.com/developers/docs/interactions/application-commands#get-guild-application-command) | @@ -54,6 +59,7 @@ public class DiscordApplication : IDebugLoggable | [HasAnyApplicationFlags](#hasanyapplicationflags-method)(…) | Returns if the given application has any of the passed in application flags If [`Flags`](#flags-property) is null false is returned | | [HasApplicationFlag](#hasapplicationflag-method)(…) | Returns if the given application has the passed in application flag If [`Flags`](#flags-property) is null false is returned | | [LogDebug](#logdebug-method)(…) | | +| [UpdateApplicationEmoji](#updateapplicationemoji-method)(…) | Updates an existing application emoji | | static [Get](#get-method)(…) | Returns the current users application See [Get Current Application]() | ## See Also @@ -421,6 +427,127 @@ public IPromise> EditRoleConnectionMetad * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# GetApplicationEmojis method + +Returns the list of all application emojis + +```csharp +public IPromise GetApplicationEmojis(DiscordClient client) +``` + +| parameter | description | +| --- | --- | +| client | Client to use | + +## See Also + +* interface [IPromise<TPromised>](../Interfaces/IPromise%7BTPromised%7D.md) +* class [ApplicationEmojis](./ApplicationEmojis.md) +* class [DiscordClient](../Clients/DiscordClient.md) +* class [DiscordApplication](./DiscordApplication.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GetApplicationEmoji method + +Return an application emoji by ID + +```csharp +public IPromise GetApplicationEmoji(DiscordClient client, Snowflake emojiId) +``` + +| parameter | description | +| --- | --- | +| client | Client to use | +| emojiId | ID of the emoji | + +## See Also + +* interface [IPromise<TPromised>](../Interfaces/IPromise%7BTPromised%7D.md) +* class [DiscordEmoji](./DiscordEmoji.md) +* class [DiscordClient](../Clients/DiscordClient.md) +* struct [Snowflake](./Snowflake.md) +* class [DiscordApplication](./DiscordApplication.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# CreateApplicationEmoji method + +Creates a new application emoji + +```csharp +public IPromise CreateApplicationEmoji(DiscordClient client, + ApplicationEmojiCreate create) +``` + +| parameter | description | +| --- | --- | +| client | Client to use | +| create | Emoji to create | + +## See Also + +* interface [IPromise<TPromised>](../Interfaces/IPromise%7BTPromised%7D.md) +* class [DiscordEmoji](./DiscordEmoji.md) +* class [DiscordClient](../Clients/DiscordClient.md) +* class [ApplicationEmojiCreate](./ApplicationEmojiCreate.md) +* class [DiscordApplication](./DiscordApplication.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# UpdateApplicationEmoji method + +Updates an existing application emoji + +```csharp +public IPromise UpdateApplicationEmoji(DiscordClient client, Snowflake emojiId, + ApplicationEmojiUpdate update) +``` + +| parameter | description | +| --- | --- | +| client | Client to use | +| emojiId | ID of the emoji to update | +| update | Update to the application emoji | + +## See Also + +* interface [IPromise<TPromised>](../Interfaces/IPromise%7BTPromised%7D.md) +* class [DiscordEmoji](./DiscordEmoji.md) +* class [DiscordClient](../Clients/DiscordClient.md) +* struct [Snowflake](./Snowflake.md) +* class [ApplicationEmojiUpdate](./ApplicationEmojiUpdate.md) +* class [DiscordApplication](./DiscordApplication.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# DeleteApplicationEmoji method + +Deletes an application emoji + +```csharp +public IPromise DeleteApplicationEmoji(DiscordClient client, Snowflake emojiId) +``` + +| parameter | description | +| --- | --- | +| client | Client to use | +| emojiId | ID of the emoji to delete | + +## See Also + +* interface [IPromise](../Interfaces/IPromise.md) +* class [DiscordClient](../Clients/DiscordClient.md) +* struct [Snowflake](./Snowflake.md) +* class [DiscordApplication](./DiscordApplication.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # LogDebug method ```csharp @@ -833,6 +960,24 @@ public InstallParams InstallParams { get; set; } * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# IntegrationTypesConfig property + +Default scopes and permissions for each supported installation context + +```csharp +public Hash + IntegrationTypesConfig { get; set; } +``` + +## See Also + +* enum [ApplicationIntegrationType](./ApplicationIntegrationType.md) +* class [ApplicationIntegrationTypeConfiguration](./ApplicationIntegrationTypeConfiguration.md) +* class [DiscordApplication](./DiscordApplication.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # CustomInstallUrl property The application's default custom authorization link, if enabled diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordApplicationCommand.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordApplicationCommand.md index b4ddce3f0..756bf7bb3 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordApplicationCommand.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordApplicationCommand.md @@ -12,12 +12,14 @@ public class DiscordApplicationCommand | --- | --- | | [DiscordApplicationCommand](#discordapplicationcommand-constructor)() | The default constructor. | | [ApplicationId](#applicationid-property) { get; set; } | ID of the parent application | +| [Contexts](#contexts-property) { get; set; } | Interaction context(s) where the command can be used, only for globally-scoped commands. By default, all interaction context types included for new commands.. | | [DefaultMemberPermissions](#defaultmemberpermissions-property) { get; set; } | Set of permissions represented as a bit set | | [Description](#description-property) { get; set; } | Description of the command (1-100 characters) | | [DescriptionLocalizations](#descriptionlocalizations-property) { get; set; } | Localization dictionary for the description field. Values follow the same restrictions as description | | [DmPermission](#dmpermission-property) { get; set; } | Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. | | [GuildId](#guildid-property) { get; set; } | Guild ID of the command, if not global | | [Id](#id-property) { get; set; } | Unique id of the command | +| [IntegrationTypes](#integrationtypes-property) { get; set; } | Installation context(s) where the command is available, only for globally-scoped commands. Defaults to GUILD_INSTALL (0) | | [Mention](#mention-property) { get; } | Mention the [`DiscordApplicationCommand`](./DiscordApplicationCommand.md) | | [Name](#name-property) { get; set; } | 1-32 lowercase character name matching ^[\w-]{1,32}$ | | [NameLocalizations](#namelocalizations-property) { get; set; } | Localization dictionary for the name field. Values follow the same restrictions as name | @@ -351,6 +353,38 @@ public bool? Nsfw { get; set; } ## See Also +* class [DiscordApplicationCommand](./DiscordApplicationCommand.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# IntegrationTypes property + +Installation context(s) where the command is available, only for globally-scoped commands. Defaults to GUILD_INSTALL (0) + +```csharp +public List IntegrationTypes { get; set; } +``` + +## See Also + +* enum [ApplicationIntegrationType](./ApplicationIntegrationType.md) +* class [DiscordApplicationCommand](./DiscordApplicationCommand.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Contexts property + +Interaction context(s) where the command can be used, only for globally-scoped commands. By default, all interaction context types included for new commands.. + +```csharp +public List Contexts { get; set; } +``` + +## See Also + +* enum [InteractionContextTypes](./InteractionContextTypes.md) * class [DiscordApplicationCommand](./DiscordApplicationCommand.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordColor.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordColor.md index a097f08e0..fe378f7cf 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordColor.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordColor.md @@ -3,7 +3,7 @@ Represents a Discord Color ```csharp -public struct DiscordColor +public struct DiscordColor : IEquatable ``` ## Public Members diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordEmoji.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordEmoji.md index 0c352ed7f..71cfb5c6c 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordEmoji.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordEmoji.md @@ -16,7 +16,7 @@ public class DiscordEmoji : EmojiUpdate, ISnowflakeEntity | [Animated](#animated-property) { get; set; } | Whether this emoji is animated | | [Available](#available-property) { get; set; } | Whether this emoji can be used, may be false due to loss of Server Boosts | | [EmojiId](#emojiid-property) { get; set; } | Emoji id | -| [Id](#id-property) { get; } | The ID for the emoji if it is custom; Otherwise invalid snowflake | +| [Id](#id-property) { get; } | The ID for the emoji if it is custom; Otherwise default snowflake | | [Managed](#managed-property) { get; set; } | Whether this emoji is managed | | [Mention](#mention-property) { get; } | Show the emoji in a message | | [RequireColons](#requirecolons-property) { get; set; } | Whether this emoji must be wrapped in colons | @@ -105,7 +105,7 @@ public DiscordEmoji()   # Id property -The ID for the emoji if it is custom; Otherwise invalid snowflake +The ID for the emoji if it is custom; Otherwise default snowflake ```csharp public Snowflake Id { get; } diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordEntitlement.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordEntitlement.md index dd32fd368..212689fbf 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordEntitlement.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordEntitlement.md @@ -12,6 +12,7 @@ public class DiscordEntitlement | --- | --- | | [DiscordEntitlement](#discordentitlement-constructor)() | The default constructor. | | [ApplicationId](#applicationid-property) { get; set; } | ID of the parent application | +| [Consumed](#consumed-property) { get; set; } | For consumable items, whether the entitlement has been consumed | | [Deleted](#deleted-property) { get; set; } | Entitlement was deleted | | [EndsAt](#endsat-property) { get; set; } | Date at which the entitlement is no longer valid. Not present when using test entitlements. | | [GuildId](#guildid-property) { get; set; } | ID of the guild that is granted access to the entitlement's sku | @@ -20,9 +21,10 @@ public class DiscordEntitlement | [StartsAt](#startsat-property) { get; set; } | Start date at which the entitlement is valid. Not present when using test entitlements. | | [Type](#type-property) { get; set; } | Type of entitlement | | [UserId](#userid-property) { get; set; } | ID of the user that is granted access to the entitlement's sku | -| [CreateTestEntitlement](#createtestentitlement-method)(…) | Creates a test entitlement to a given SKU for a given guild or user. Discord will act as though that user or guild has entitlement to your premium offering. | -| [DeleteTestEntitlement](#deletetestentitlement-method)(…) | Deletes a currently-active test entitlement. Discord will act as though that user or guild no longer has entitlement to your premium offering. | -| static [GetEntitlements](#getentitlements-method)(…) | Returns all entitlements for a given app, active and expired. | +| [ConsumeEntitlement](#consumeentitlement-method)(…) | For One-Time Purchase consumable SKUs, marks a given entitlement for the user as consumed. See [Consume an Entitlement](https://discord.com/developers/docs/monetization/entitlements#consume-an-entitlement) | +| [CreateTestEntitlement](#createtestentitlement-method)(…) | Creates a test entitlement to a given SKU for a given guild or user. Discord will act as though that user or guild has entitlement to your premium offering. See [Create Test Entitlement](https://discord.com/developers/docs/monetization/entitlements#create-test-entitlement) | +| [DeleteTestEntitlement](#deletetestentitlement-method)(…) | Deletes a currently-active test entitlement. Discord will act as though that user or guild no longer has entitlement to your premium offering. See [Delete Test Entitlement](https://discord.com/developers/docs/monetization/entitlements#delete-test-entitlement) | +| static [GetEntitlements](#getentitlements-method)(…) | Returns all entitlements for a given app, active and expired. See [List Entitlements](https://discord.com/developers/docs/monetization/entitlements#list-entitlements) | ## See Also @@ -33,7 +35,7 @@ public class DiscordEntitlement   # GetEntitlements method -Returns all entitlements for a given app, active and expired. +Returns all entitlements for a given app, active and expired. See [List Entitlements](https://discord.com/developers/docs/monetization/entitlements#list-entitlements) ```csharp public static IPromise> GetEntitlements(DiscordClient client, @@ -57,9 +59,30 @@ public static IPromise> GetEntitlements(DiscordClient c * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# ConsumeEntitlement method + +For One-Time Purchase consumable SKUs, marks a given entitlement for the user as consumed. See [Consume an Entitlement](https://discord.com/developers/docs/monetization/entitlements#consume-an-entitlement) + +```csharp +public IPromise ConsumeEntitlement(DiscordClient client) +``` + +| parameter | description | +| --- | --- | +| client | Client to use | + +## See Also + +* interface [IPromise](../Interfaces/IPromise.md) +* class [DiscordClient](../Clients/DiscordClient.md) +* class [DiscordEntitlement](./DiscordEntitlement.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # CreateTestEntitlement method -Creates a test entitlement to a given SKU for a given guild or user. Discord will act as though that user or guild has entitlement to your premium offering. +Creates a test entitlement to a given SKU for a given guild or user. Discord will act as though that user or guild has entitlement to your premium offering. See [Create Test Entitlement](https://discord.com/developers/docs/monetization/entitlements#create-test-entitlement) ```csharp public IPromise CreateTestEntitlement(DiscordClient client, @@ -83,7 +106,7 @@ public IPromise CreateTestEntitlement(DiscordClient client,   # DeleteTestEntitlement method -Deletes a currently-active test entitlement. Discord will act as though that user or guild no longer has entitlement to your premium offering. +Deletes a currently-active test entitlement. Discord will act as though that user or guild no longer has entitlement to your premium offering. See [Delete Test Entitlement](https://discord.com/developers/docs/monetization/entitlements#delete-test-entitlement) ```csharp public IPromise DeleteTestEntitlement(DiscordClient client) @@ -253,6 +276,21 @@ public Snowflake? GuildId { get; set; } ## See Also * struct [Snowflake](./Snowflake.md) +* class [DiscordEntitlement](./DiscordEntitlement.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Consumed property + +For consumable items, whether the entitlement has been consumed + +```csharp +public bool? Consumed { get; set; } +``` + +## See Also + * class [DiscordEntitlement](./DiscordEntitlement.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordGuild.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordGuild.md index 8d0bf2f5a..165f797a2 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordGuild.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordGuild.md @@ -125,8 +125,8 @@ public class DiscordGuild : ISnowflakeEntity | [GetWidgetSettings](#getwidgetsettings-method)(…) | Returns a guild widget object. Requires the MANAGE_GUILD permission. See [Get Guild Widget Settings](https://discord.com/developers/docs/resources/guild#get-guild-widget-settings) | | [ListActiveThreads](#listactivethreads-method)(…) | Returns all active threads in the guild, including public and private threads. Threads are ordered by their id, in descending order. See [List Active Threads](https://discord.com/developers/docs/resources/guild#list-active-threads) | | [ListAutoModRules](#listautomodrules-method)(…) | | -| [Listembers](#listembers-method)(…) | Returns a list of guild member objects that are members of the guild. In the future, this endpoint will be restricted in line with our Privileged Intents | | [ListEmojis](#listemojis-method)(…) | Returns a list of emoji objects for the given guild. See [List Guild Emojis](https://discord.com/developers/docs/resources/emoji#list-guild-emojis) | +| [ListMembers](#listmembers-method)(…) | Returns a list of guild member objects that are members of the guild. In the future, this endpoint will be restricted in line with our Privileged Intents | | [ListStickers](#liststickers-method)(…) | Returns an array of sticker objects for the given guild. Includes user fields if the bot has the MANAGE_EMOJIS_AND_STICKERS permission. See [List Guild Stickers](https://discord.com/developers/docs/resources/sticker#list-guild-stickers) | | [RemoveBan](#removeban-method)(…) | Remove the ban for a user. Requires the BAN_MEMBERS permissions. See [Remove Guild Ban](https://discord.com/developers/docs/resources/guild#remove-guild-ban) | | [RemoveMember](#removemember-method-1-of-2)(…) | Remove a member from a guild. Requires KICK_MEMBERS permission. See [Remove Guild Member](https://discord.com/developers/docs/resources/guild#remove-guild-member) (2 methods) | @@ -620,12 +620,12 @@ public IPromise ListActiveThreads(DiscordClient client) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     -# Listembers method +# ListMembers method Returns a list of guild member objects that are members of the guild. In the future, this endpoint will be restricted in line with our Privileged Intents ```csharp -public IPromise> Listembers(DiscordClient client, GuildListMembers list = null) +public IPromise> ListMembers(DiscordClient client, GuildListMembers list = null) ``` | parameter | description | diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordInteraction.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordInteraction.md index 47052f325..1af56061f 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordInteraction.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordInteraction.md @@ -12,12 +12,15 @@ public class DiscordInteraction | --- | --- | | [DiscordInteraction](#discordinteraction-constructor)() | The default constructor. | | [ApplicationId](#applicationid-property) { get; set; } | ID of the application this interaction is for | -| [AppPermissions](#apppermissions-property) { get; set; } | Bitwise set of permissions the app or bot has within the channel the interaction was sent from | +| [AppPermissions](#apppermissions-property) { get; set; } | Bitwise set of permissions the app has in the source location of the interaction | +| [AuthorizingIntegrationOwners](#authorizingintegrationowners-property) { get; set; } | Mapping of installation contexts that the interaction was authorized for to related user or guild IDs | | [Channel](#channel-property) { get; set; } | Channel that the interaction was sent from | | [ChannelId](#channelid-property) { get; set; } | Channel that the interaction was sent from | +| [Contexts](#contexts-property) { get; set; } | Context where the interaction was triggered from | | [Data](#data-property) { get; set; } | Interaction data payload See [`InteractionData`](./InteractionData.md) | | [Entitlements](#entitlements-property) { get; set; } | For monetized apps, any entitlements for the invoking user, representing access to premium SKUs | | [Focused](#focused-property) { get; } | Returns the Focused option for Auto Complete | +| [Guild](#guild-property) { get; set; } | Guild that the interaction was sent from | | [GuildId](#guildid-property) { get; set; } | Guild that the interaction was sent from | | [GuildLocale](#guildlocale-property) { get; set; } | The guild's preferred locale, if invoked in a guild [Discord Locale Values](https://discord.com/developers/docs/dispatch/field-values#predefined-field-values-accepted-locales) | | [Id](#id-property) { get; set; } | Id of the interaction | @@ -33,7 +36,6 @@ public class DiscordInteraction | [CreateFollowUpMessage](#createfollowupmessage-method-1-of-2)(…) | Create a followup message for an Interaction See [Create Followup Message](https://discord.com/developers/docs/interactions/receiving-and-responding#create-followup-message) (2 methods) | | [CreateFollowUpTemplateResponse](#createfollowuptemplateresponse-method)(…) | Creates a interaction follow up message response from a message template | | [CreateModalResponse](#createmodalresponse-method)(…) | Creates a interaction modal response from a modal template | -| [CreatePremiumRequiredResponse](#createpremiumrequiredresponse-method)(…) | Creates a response indication that the interaction requires premium to be purchased. | | [CreateResponse](#createresponse-method-1-of-7)(…) | Create a response to an Interaction from the gateway. See [Create Interaction Response](https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response) (7 methods) | | [CreateTemplateResponse](#createtemplateresponse-method)(…) | Creates a interaction message response from a message template | | [DefferResponse](#defferresponse-method)(…) | Creates a response indicating that: for application commands there will be an update in the future for message component commands that you have acknowledged the command and there may be an update in the future See [Create Interaction Response](https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response) | @@ -429,27 +431,6 @@ public IPromise DefferResponse(DiscordClient client) ## See Also -* interface [IPromise](../Interfaces/IPromise.md) -* class [DiscordClient](../Clients/DiscordClient.md) -* class [DiscordInteraction](./DiscordInteraction.md) -* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# CreatePremiumRequiredResponse method - -Creates a response indication that the interaction requires premium to be purchased. - -```csharp -public IPromise CreatePremiumRequiredResponse(DiscordClient client) -``` - -| parameter | description | -| --- | --- | -| client | Client to use | - -## See Also - * interface [IPromise](../Interfaces/IPromise.md) * class [DiscordClient](../Clients/DiscordClient.md) * class [DiscordInteraction](./DiscordInteraction.md) @@ -802,6 +783,22 @@ public InteractionData Data { get; set; } * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# Guild property + +Guild that the interaction was sent from + +```csharp +public DiscordGuild Guild { get; set; } +``` + +## See Also + +* class [DiscordGuild](./DiscordGuild.md) +* class [DiscordInteraction](./DiscordInteraction.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # GuildId property Guild that the interaction was sent from @@ -930,7 +927,7 @@ public DiscordMessage Message { get; set; }   # AppPermissions property -Bitwise set of permissions the app or bot has within the channel the interaction was sent from +Bitwise set of permissions the app has in the source location of the interaction ```csharp public PermissionFlags? AppPermissions { get; set; } @@ -992,6 +989,39 @@ public List Entitlements { get; set; } * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# AuthorizingIntegrationOwners property + +Mapping of installation contexts that the interaction was authorized for to related user or guild IDs + +```csharp +public Hash AuthorizingIntegrationOwners { get; set; } +``` + +## See Also + +* enum [ApplicationIntegrationType](./ApplicationIntegrationType.md) +* struct [Snowflake](./Snowflake.md) +* class [DiscordInteraction](./DiscordInteraction.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Contexts property + +Context where the interaction was triggered from + +```csharp +public List Contexts { get; set; } +``` + +## See Also + +* enum [InteractionContextTypes](./InteractionContextTypes.md) +* class [DiscordInteraction](./DiscordInteraction.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # Parsed property Returns the interaction parsed args to make it easier to process that interaction. diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordInvite.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordInvite.md index af2b0e532..5ff73911c 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordInvite.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordInvite.md @@ -21,6 +21,7 @@ public class DiscordInvite | [Inviter](#inviter-property) { get; set; } | The user who created the invite See [`DiscordUser`](./DiscordUser.md) | | [StageInstance](#stageinstance-property) { get; set; } | Stage instance data if there is a public Stage instance in the Stage channel this invite is for | | [TargetUser](#targetuser-property) { get; set; } | The target user for this invite See [`DiscordUser`](./DiscordUser.md) | +| [Type](#type-property) { get; set; } | The type of the invite | | [UserTargetType](#usertargettype-property) { get; set; } | The type of user target for this invite See [`TargetUserType`](./TargetUserType.md) | | [Delete](#delete-method)(…) | Delete an invite. Requires the MANAGE_CHANNELS permission on the channel this invite belongs to, or MANAGE_GUILD to remove any invite across the guild. Returns an invite object on success. See [Delete Invite](https://discord.com/developers/docs/resources/invite#delete-invite) | | static [Get](#get-method)(…) | Returns an invite object for the given code. See [Get Invite](https://discord.com/developers/docs/resources/invite#get-invite) | @@ -88,6 +89,22 @@ public DiscordInvite() ## See Also +* class [DiscordInvite](./DiscordInvite.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Type property + +The type of the invite + +```csharp +public InviteType Type { get; set; } +``` + +## See Also + +* enum [InviteType](./InviteType.md) * class [DiscordInvite](./DiscordInvite.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordMessage.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordMessage.md index 5dc2fa3fe..69d9754f8 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordMessage.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordMessage.md @@ -16,6 +16,7 @@ public class DiscordMessage : IFileAttachments | [ApplicationId](#applicationid-property) { get; set; } | If the message is an Interaction or application-owned webhook, this is the id of the application | | [Attachments](#attachments-property) { get; set; } | Any attached files [`MessageAttachment`](./MessageAttachment.md) | | [Author](#author-property) { get; set; } | The author of this message (not guaranteed to be a valid user) The author object follows the structure of the user object, but is only a valid user in the case where the message is generated by a user or bot user. If the message is generated by a webhook, the author object corresponds to the webhook's id, username, and avatar. You can tell if a message is generated by a webhook by checking for the webhook_id on the message object. [`DiscordUser`](./DiscordUser.md) | +| [Call](#call-property) { get; set; } | The call associated with the message | | [ChannelId](#channelid-property) { get; set; } | ID of the channel the message was sent in | | [Components](#components-property) { get; set; } | Sent if the message contains components like buttons, action rows, or other interactive components | | [Content](#content-property) { get; set; } | Contents of the message | @@ -26,14 +27,17 @@ public class DiscordMessage : IFileAttachments | [GuildId](#guildid-property) { get; set; } | ID of the guild the message was sent in | | [Id](#id-property) { get; set; } | ID of the message | | [Interaction](#interaction-property) { get; set; } | Sent if the message is a response to an Interaction | +| [InteractionMetadata](#interactionmetadata-property) { get; set; } | sent if the message is sent as a result of an interaction | | [Member](#member-property) { get; set; } | Member properties for this message's author [`GuildMember`](./GuildMember.md) | | [MentionEveryone](#mentioneveryone-property) { get; set; } | Whether this message mentions everyone | | [MentionRoles](#mentionroles-property) { get; set; } | Roles specifically mentioned in this message | | [Mentions](#mentions-property) { get; set; } | Users specifically mentioned in the message [`DiscordUser`](./DiscordUser.md) | | [MentionsChannels](#mentionschannels-property) { get; set; } | Channels specifically mentioned in this message [`ChannelMention`](./ChannelMention.md) | | [MessageReference](#messagereference-property) { get; set; } | Data showing the source of a crosspost, channel follow add, pin, or reply message [`MessageReference`](./MessageReference.md) | +| [MessageSnapshots](#messagesnapshots-property) { get; set; } | The message associated with the message_reference. This is a minimal subset of fields in a message (e.g. author is excluded.) [`MessageReference`](./MessageReference.md) | | [Nonce](#nonce-property) { get; set; } | Used for validating a message was sent | | [Pinned](#pinned-property) { get; set; } | Whether this message is pinned | +| [Poll](#poll-property) { get; set; } | Poll object | | [Position](#position-property) { get; set; } | A generally increasing integer (there may be gaps or duplicates) that represents the approximate position of the message in a thread, it can be used to estimate the relative position of the message in a thread in company with total_message_sent on parent thread | | [Reactions](#reactions-property) { get; set; } | Reactions to the message [`MessageReaction`](./MessageReaction.md) | | [ReferencedMessage](#referencedmessage-property) { get; } | The message associated with the message_reference | @@ -54,12 +58,14 @@ public class DiscordMessage : IFileAttachments | [Edit](#edit-method)(…) | Edit a previously sent message. The fields content, embed, allowed_mentions and flags can be edited by the original message author. Other users can only edit flags and only if they have the MANAGE_MESSAGES permission in the corresponding channel. When specifying flags, ensure to include all previously set flags/bits in addition to ones that you are modifying. Only flags documented in the table below may be modified by users (unsupported flag changes are currently ignored without error). See [Edit Message](https://discord.com/developers/docs/resources/channel#edit-message) | | [EditGlobalTemplateMessage](#editglobaltemplatemessage-method)(…) | Edit a message using a global message template | | [EditTemplateMessage](#edittemplatemessage-method)(…) | Edit a message using a localized message template | +| [EndPoll](#endpoll-method)(…) | Immediately ends the poll. You cannot end polls from other users. See [End Poll](https://discord.com/developers/docs/resources/poll#end-poll) | +| [GetPollVoters](#getpollvoters-method)(…) | Get a list of users that voted for this specific answer. See [Get Answer Voters](https://discord.com/developers/docs/resources/poll#get-answer-voters) | | [GetReactions](#getreactions-method-1-of-2)(…) | Get a list of users that reacted with this emoji Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> See [Get Reactions](https://discord.com/developers/docs/resources/channel#get-reactions) (2 methods) | | [Pin](#pin-method)(…) | Pin a message in a channel. Requires the MANAGE_MESSAGES permission. See [Add Pinned Channel Message](https://discord.com/developers/docs/resources/channel#add-pinned-channel-message) | | [Reply](#reply-method-1-of-5)(…) | Replies to a previously sent message See [Create Message](https://discord.com/developers/docs/resources/channel#create-message) (5 methods) | | [ReplyWithGlobalTemplate](#replywithglobaltemplate-method)(…) | Reply to a message using a global message template | | [ReplyWithTemplate](#replywithtemplate-method)(…) | Reply to a message using a global message template | -| [StartThread](#startthread-method)(…) | Creates a new public thread this message See [https://discord.com/developers/docs/resources/channel#start-thread-from-message](https://discord.com/developers/docs/resources/channel#start-thread-from-message) | +| [StartThread](#startthread-method)(…) | Creates a new public thread this message See [Start Thread](https://discord.com/developers/docs/resources/channel#start-thread-from-message) | | [Unpin](#unpin-method)(…) | Delete a pinned message in a channel. Requires the MANAGE_MESSAGES permission. See [Unpin Pinned Channel Message](https://discord.com/developers/docs/resources/channel#delete-pinned-channel-message) | | static [Create](#create-method-1-of-5)(…) | Post a message to a guild text or DM channel. If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. See [Create Message](https://discord.com/developers/docs/resources/channel#create-message) (5 methods) | | static [CreateGlobalTemplateMessage](#createglobaltemplatemessage-method)(…) | Send a message in the channel with the given ID using a global message template | @@ -920,7 +926,7 @@ public IPromise Unpin(DiscordClient client)   # StartThread method -Creates a new public thread this message See [https://discord.com/developers/docs/resources/channel#start-thread-from-message](https://discord.com/developers/docs/resources/channel#start-thread-from-message) +Creates a new public thread this message See [Start Thread](https://discord.com/developers/docs/resources/channel#start-thread-from-message) ```csharp public IPromise StartThread(DiscordClient client, ThreadCreateFromMessage create) @@ -942,6 +948,54 @@ public IPromise StartThread(DiscordClient client, ThreadCreateFr * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# GetPollVoters method + +Get a list of users that voted for this specific answer. See [Get Answer Voters](https://discord.com/developers/docs/resources/poll#get-answer-voters) + +```csharp +public IPromise GetPollVoters(DiscordClient client, PollAnswers answer, + GetPollAnswerVoters filter = null) +``` + +| parameter | description | +| --- | --- | +| client | Client to use | +| answer | Answer to get voters for | +| filter | | + +## See Also + +* interface [IPromise<TPromised>](../Interfaces/IPromise%7BTPromised%7D.md) +* class [GetPollAnswerResponse](./GetPollAnswerResponse.md) +* class [DiscordClient](../Clients/DiscordClient.md) +* class [PollAnswers](./PollAnswers.md) +* class [GetPollAnswerVoters](./GetPollAnswerVoters.md) +* class [DiscordMessage](./DiscordMessage.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# EndPoll method + +Immediately ends the poll. You cannot end polls from other users. See [End Poll](https://discord.com/developers/docs/resources/poll#end-poll) + +```csharp +public IPromise EndPoll(DiscordClient client) +``` + +| parameter | description | +| --- | --- | +| client | Client to use | + +## See Also + +* interface [IPromise<TPromised>](../Interfaces/IPromise%7BTPromised%7D.md) +* class [DiscordClient](../Clients/DiscordClient.md) +* class [DiscordMessage](./DiscordMessage.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # DiscordMessage constructor The default constructor. @@ -1337,6 +1391,22 @@ public MessageReference MessageReference { get; set; } * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# MessageSnapshots property + +The message associated with the message_reference. This is a minimal subset of fields in a message (e.g. author is excluded.) [`MessageReference`](./MessageReference.md) + +```csharp +public List MessageSnapshots { get; set; } +``` + +## See Also + +* class [MessageSnapshot](./MessageSnapshot.md) +* class [DiscordMessage](./DiscordMessage.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # Flags property Message flags combined as a bitfield [`MessageFlags`](./MessageFlags.md) @@ -1363,6 +1433,22 @@ public DiscordMessage ReferencedMessage { get; } ## See Also +* class [DiscordMessage](./DiscordMessage.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# InteractionMetadata property + +sent if the message is sent as a result of an interaction + +```csharp +public MessageInteraction InteractionMetadata { get; set; } +``` + +## See Also + +* class [MessageInteraction](./MessageInteraction.md) * class [DiscordMessage](./DiscordMessage.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) @@ -1373,6 +1459,7 @@ public DiscordMessage ReferencedMessage { get; } Sent if the message is a response to an Interaction ```csharp +[Obsolete("Deprecated in favor of InteractionMetadata")] public MessageInteraction Interaction { get; set; } ``` @@ -1464,6 +1551,38 @@ public RoleSubscription RoleSubscriptionData { get; set; } * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     +# Poll property + +Poll object + +```csharp +public DiscordPoll Poll { get; set; } +``` + +## See Also + +* class [DiscordPoll](./DiscordPoll.md) +* class [DiscordMessage](./DiscordMessage.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Call property + +The call associated with the message + +```csharp +public MessageCall Call { get; set; } +``` + +## See Also + +* class [MessageCall](./MessageCall.md) +* class [DiscordMessage](./DiscordMessage.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  # FileAttachments property File Attachments to add to the message on edit diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordPoll.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordPoll.md new file mode 100644 index 000000000..70ef7c82a --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordPoll.md @@ -0,0 +1,136 @@ +# DiscordPoll class + +Represents a [Discord Poll](https://discord.com/developers/docs/resources/poll#poll-object-poll-object-structure) + +```csharp +public class DiscordPoll +``` + +## Public Members + +| name | description | +| --- | --- | +| [DiscordPoll](#discordpoll-constructor)() | The default constructor. | +| [AllowMultiselect](#allowmultiselect-property) { get; set; } | Whether a user can select multiple answers | +| [Answers](#answers-property) { get; set; } | Each of the answers available in the poll. | +| [Expiry](#expiry-property) { get; set; } | The time when the poll ends. | +| [LayoutType](#layouttype-property) { get; set; } | The layout type of the poll | +| [Question](#question-property) { get; set; } | The question of the poll. Only text is supported. | +| [Results](#results-property) { get; set; } | The results of the poll | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [DiscordPoll.cs](../../../../Oxide.Ext.Discord/Entities/DiscordPoll.cs) +  +  +# DiscordPoll constructor + +The default constructor. + +```csharp +public DiscordPoll() +``` + +## See Also + +* class [DiscordPoll](./DiscordPoll.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Question property + +The question of the poll. Only text is supported. + +```csharp +public PollMedia Question { get; set; } +``` + +## See Also + +* class [PollMedia](./PollMedia.md) +* class [DiscordPoll](./DiscordPoll.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Answers property + +Each of the answers available in the poll. + +```csharp +public List Answers { get; set; } +``` + +## See Also + +* class [PollAnswers](./PollAnswers.md) +* class [DiscordPoll](./DiscordPoll.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Expiry property + +The time when the poll ends. + +```csharp +public DateTimeOffset? Expiry { get; set; } +``` + +## See Also + +* class [DiscordPoll](./DiscordPoll.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AllowMultiselect property + +Whether a user can select multiple answers + +```csharp +public bool AllowMultiselect { get; set; } +``` + +## See Also + +* class [DiscordPoll](./DiscordPoll.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# LayoutType property + +The layout type of the poll + +```csharp +public PollLayoutType LayoutType { get; set; } +``` + +## See Also + +* enum [PollLayoutType](./PollLayoutType.md) +* class [DiscordPoll](./DiscordPoll.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Results property + +The results of the poll + +```csharp +public PollResults Results { get; set; } +``` + +## See Also + +* class [PollResults](./PollResults.md) +* class [DiscordPoll](./DiscordPoll.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordSkuType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordSkuType.md index 006c66ff6..b94d0f38e 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordSkuType.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordSkuType.md @@ -10,6 +10,8 @@ public enum DiscordSkuType | name | value | description | | --- | --- | --- | +| Durable | `Durable` | Durable one-time purchase | +| Consumable | `Consumable` | Consumable one-time purchase | | Subscription | `Subscription` | Represents a recurring subscription | | SubscriptionGroup | `SubscriptionGroup` | System-generated group for each SUBSCRIPTION SKU created | diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordUser.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordUser.md index 74eb7a429..e2c538744 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordUser.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordUser.md @@ -13,7 +13,7 @@ public class DiscordUser : IDebugLoggable, IDiscordCacheable, ISnow | [DiscordUser](#discorduser-constructor)() | The default constructor. | | [AccentColor](#accentcolor-property) { get; set; } | The user's banner color encoded as an integer representation of hexadecimal color code | | [Avatar](#avatar-property) { get; set; } | The user's avatar hash | -| [AvatarDecoration](#avatardecoration-property) { get; set; } | The user's avatar decoration hash | +| [AvatarDecoration](#avatardecoration-property) { get; set; } | The user's avatar decoration | | [Banner](#banner-property) { get; set; } | The user's banner, or null if unset | | [Bot](#bot-property) { get; set; } | Whether the user belongs to an OAuth2 application | | [Discriminator](#discriminator-property) { get; set; } | The user's 4-digit discord-tag | @@ -805,14 +805,15 @@ public UserFlags? PublicFlags { get; set; }   # AvatarDecoration property -The user's avatar decoration hash +The user's avatar decoration ```csharp -public string AvatarDecoration { get; set; } +public AvatarDecorationData AvatarDecoration { get; set; } ``` ## See Also +* class [AvatarDecorationData](./AvatarDecorationData.md) * class [DiscordUser](./DiscordUser.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordWebhook.md b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordWebhook.md index 4913467bc..4d229a025 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordWebhook.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/DiscordWebhook.md @@ -14,6 +14,7 @@ public class DiscordWebhook | [ApplicationId](#applicationid-property) { get; set; } | The bot/OAuth2 application that created this webhook | | [Avatar](#avatar-property) { get; set; } | the default user avatar hash of the webhook | | [ChannelId](#channelid-property) { get; set; } | The channel id this webhook is for, if any | +| [Client](#client-property) { get; } | Client for the webhook | | [GuildId](#guildid-property) { get; set; } | The guild id this webhook is for, if any | | [Id](#id-property) { get; set; } | The id of the webhook | | [Name](#name-property) { get; set; } | The default name of the webhook | @@ -792,5 +793,21 @@ public Snowflake SourceChannel { get; set; } * class [DiscordWebhook](./DiscordWebhook.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Client property + +Client for the webhook + +```csharp +public WebhookClient Client { get; } +``` + +## See Also + +* class [WebhookClient](../Clients/WebhookClient.md) +* class [DiscordWebhook](./DiscordWebhook.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/EntitiesNamespace.md b/Docs/Generated/Oxide.Ext.Discord/Entities/EntitiesNamespace.md index 4f9ba83e5..7bc640244 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/EntitiesNamespace.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/EntitiesNamespace.md @@ -13,7 +13,12 @@ | class [AllowedMentions](./AllowedMentions.md) | Represents a [Allowed Mention Types](https://discord.com/developers/docs/resources/channel#allowed-mentions-object) | | enum [AllowedMentionTypes](./AllowedMentionTypes.md) | Represents a [Allowed Mention Types](https://discord.com/developers/docs/resources/channel#allowed-mentions-object-allowed-mention-types) for a message | | enum [ApplicationCommandType](./ApplicationCommandType.md) | Represents [Application Command Type](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-types) | +| class [ApplicationEmojiCreate](./ApplicationEmojiCreate.md) | Represents [Application Emoji Create Structure](https://discord.com/developers/docs/resources/emoji#create-application-emoji-json-params) | +| class [ApplicationEmojis](./ApplicationEmojis.md) | Represents [Application Emojis](https://discord.com/developers/docs/resources/emoji#list-application-emojis) | +| class [ApplicationEmojiUpdate](./ApplicationEmojiUpdate.md) | Represents [Emoji Update Structure](https://discord.com/developers/docs/resources/emoji#modify-guild-emoji-json-params) | | [Flags] enum [ApplicationFlags](./ApplicationFlags.md) | Represents [Application Flags](https://discord.com/developers/docs/resources/application#application-object-application-flags) | +| enum [ApplicationIntegrationType](./ApplicationIntegrationType.md) | Represents a [Application Integration Types](https://discord.com/developers/docs/resources/application#application-object-application-integration-types) | +| class [ApplicationIntegrationTypeConfiguration](./ApplicationIntegrationTypeConfiguration.md) | Represents a [Application Integration Type Configuration](https://discord.com/developers/docs/resources/application#application-object-application-integration-type-configuration-object) | | class [ApplicationRoleConnectionMetadata](./ApplicationRoleConnectionMetadata.md) | Represents [Application Role Connection Metadata Structure](https://discord.com/developers/docs/resources/application-role-connection-metadata#application-role-connection-metadata-object-application-role-connection-metadata-structure) | | enum [ApplicationRoleConnectionMetadataType](./ApplicationRoleConnectionMetadataType.md) | Represents [Application Role Connection Metadata Type](Application Role Connection Metadata Structure) | | class [ApplicationUpdate](./ApplicationUpdate.md) | Represents [Edit Application Structure](https://discord.com/developers/docs/resources/application#edit-current-application-json-params) | @@ -29,6 +34,7 @@ | class [AutoModRuleModify](./AutoModRuleModify.md) | Represents [Auto Mod Rule Modify](https://discord.com/developers/docs/resources/auto-moderation#modify-auto-moderation-rule-json-params) | | class [AutoModTriggerMetadata](./AutoModTriggerMetadata.md) | Represents [Auto Mod Trigger Metadata](https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata) | | enum [AutoModTriggerType](./AutoModTriggerType.md) | Represents [Auto Mod Trigger Types](https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types) | +| class [AvatarDecorationData](./AvatarDecorationData.md) | Represents [Avatar Decoration Structure](https://discord.com/developers/docs/resources/user#avatar-decoration-data-object-avatar-decoration-data-structure) | | abstract class [BaseComponent](./BaseComponent.md) | Represents [Message Component](https://discord.com/developers/docs/interactions/message-components#component-object) within discord | | abstract class [BaseInteractableComponent](./BaseInteractableComponent.md) | Represent a MessageComponent that can be interacted with | | abstract class [BaseInteractionMessage](./BaseInteractionMessage.md) | Represents a Base Message for an interaction | @@ -82,6 +88,7 @@ | class [DiscordInteraction](./DiscordInteraction.md) | Represents [Interaction Structure](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-structure) | | class [DiscordInvite](./DiscordInvite.md) | Represents an [Invite Structure](https://discord.com/developers/docs/resources/invite#invite-object) that when used, adds a user to a guild or group DM channel. | | class [DiscordMessage](./DiscordMessage.md) | Represents a [Message Structure](https://discord.com/developers/docs/resources/channel#message-object) sent in a channel within Discord.. | +| class [DiscordPoll](./DiscordPoll.md) | Represents a [Discord Poll](https://discord.com/developers/docs/resources/poll#poll-object-poll-object-structure) | | class [DiscordRole](./DiscordRole.md) | Represents [Role Structure](https://discord.com/developers/docs/topics/permissions#role-object) | | class [DiscordSku](./DiscordSku.md) | Represents a [SKU Structure](https://discord.com/developers/docs/monetization/skus#sku-object-sku-structure) | | enum [DiscordSkuType](./DiscordSkuType.md) | Represents a [Discord SKU Types](https://discord.com/developers/docs/monetization/skus#sku-object-sku-types) | @@ -113,6 +120,8 @@ | class [GatewayReadyEvent](./GatewayReadyEvent.md) | Represents [Ready](https://discord.com/developers/docs/topics/gateway#ready) The ready event is dispatched when a client has completed the initial handshake with the gateway (for new sessions) | | class [GatewayResumedEvent](./GatewayResumedEvent.md) | Represents [Resumed](https://discord.com/developers/docs/topics/gateway#resumed) The resumed event is dispatched when a client has sent a resume payload to the gateway (for resuming existing sessions). | | class [GetEntitlements](./GetEntitlements.md) | Get Entitlements Query String Builder | +| class [GetPollAnswerResponse](./GetPollAnswerResponse.md) | Represents a [Get Poll Answers Response](https://discord.com/developers/docs/resources/poll#get-answer-voters-response-body) | +| class [GetPollAnswerVoters](./GetPollAnswerVoters.md) | Represents a [Get Answer Voters Query String Params](https://discord.com/developers/docs/resources/poll#get-answer-voters-query-string-params) | | class [GetThreadMember](./GetThreadMember.md) | Represents [Get Thread Member Query String Params](https://discord.com/developers/docs/resources/channel#get-thread-member-query-string-params) | | class [GroupDmChannelUpdate](./GroupDmChannelUpdate.md) | Represents a [Group DM Channel Update Structure](https://discord.com/developers/docs/resources/channel#modify-channel-json-params-group-dm) | | class [GuildBan](./GuildBan.md) | Represents [Guild Ban Structure](https://discord.com/developers/docs/resources/guild#ban-object-ban-structure) | @@ -182,6 +191,7 @@ | class [InteractionAutoCompleteMessage](./InteractionAutoCompleteMessage.md) | Interaction Auto Complete Response Message | | class [InteractionAutoCompleteResponse](./InteractionAutoCompleteResponse.md) | Represents an Auto Complete response in Discord | | class [InteractionCallbackData](./InteractionCallbackData.md) | Represents [Interaction Application Command Callback Data Structure](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-data-structure) | +| enum [InteractionContextTypes](./InteractionContextTypes.md) | Represents a [Interaction Context Types](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-context-types) | | class [InteractionData](./InteractionData.md) | Represents [ApplicationCommandInteractionData](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-data) | | class [InteractionDataArgs](./InteractionDataArgs.md) | Args supplied for the interaction | | class [InteractionDataOption](./InteractionDataOption.md) | Represents [Application Command Interaction Data Option](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-interaction-data-option-structure) | @@ -189,8 +199,6 @@ | class [InteractionDataResolved](./InteractionDataResolved.md) | Represents [Application Command Interaction Data Option](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-resolved-data-structure) | | class [InteractionModalMessage](./InteractionModalMessage.md) | Represents an Interaction Modal Message | | class [InteractionModalResponse](./InteractionModalResponse.md) | Represents an Interaction Modal Response | -| class [InteractionPremiumRequiredMessage](./InteractionPremiumRequiredMessage.md) | Message for Premium Required | -| class [InteractionPremiumRequiredResponse](./InteractionPremiumRequiredResponse.md) | Response for premium Required | | class [InteractionResponse](./InteractionResponse.md) | Represents [Interaction Response](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object) | | enum [InteractionResponseType](./InteractionResponseType.md) | Represents [InteractionResponseType](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type) | | enum [InteractionType](./InteractionType.md) | Represents [InteractionType](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-type) | @@ -199,24 +207,31 @@ | class [InviteLookup](./InviteLookup.md) | Represents a [Scheduled Event Lookup Structure](https://discord.com/developers/docs/resources/guild-scheduled-event#list-scheduled-events-for-guild-query-string-params) within Discord. | | class [InviteMetadata](./InviteMetadata.md) | Represents [Invite Metadata Structure](https://discord.com/developers/docs/resources/invite#invite-metadata-object-invite-metadata-structure) | | class [InviteStageInstance](./InviteStageInstance.md) | Represents an [Invite Stage Instance](https://discord.com/developers/docs/resources/invite#invite-stage-instance-object) | +| enum [InviteType](./InviteType.md) | Represents [Invite Types](https://discord.com/developers/docs/resources/invite#invite-types) | | class [ListThreadMembers](./ListThreadMembers.md) | Represents [List Thread Member Query String Params](https://discord.com/developers/docs/resources/channel#list-thread-members-query-string-params) | | class [MentionableSelectComponent](./MentionableSelectComponent.md) | Represents a [Select Menus Component](https://discord.com/developers/docs/interactions/message-components#select-menus) within discord. | | class [MessageActivity](./MessageActivity.md) | Represents a [Message Activity Structure](https://discord.com/developers/docs/resources/channel#message-object-message-activity-structure) | | enum [MessageActivityType](./MessageActivityType.md) | Represents a [Message Activity Types](https://discord.com/developers/docs/resources/channel#message-object-message-activity-types) | | class [MessageAttachment](./MessageAttachment.md) | Represents a message [Attachment Structure](https://discord.com/developers/docs/resources/channel#attachment-object) | | class [MessageBulkDeletedEvent](./MessageBulkDeletedEvent.md) | Represents [Message Delete Bulk](https://discord.com/developers/docs/topics/gateway#message-delete-bulk) | +| class [MessageCall](./MessageCall.md) | Represents a [Message Call Structure](https://discord.com/developers/docs/resources/channel#message-call-object) | | enum [MessageComponentType](./MessageComponentType.md) | Represents a [Message Component Type](https://discord.com/developers/docs/interactions/message-components#component-types) within Discord.. | | class [MessageCreate](./MessageCreate.md) | Represents a [Message Create Structure](https://discord.com/developers/docs/resources/channel#create-message-jsonform-params) to be created in discord | | class [MessageDeletedEvent](./MessageDeletedEvent.md) | Represents [Message Delete](https://discord.com/developers/docs/topics/gateway#message-delete) | | class [MessageFileAttachment](./MessageFileAttachment.md) | Represents a file attachment for a discord message | | [Flags] enum [MessageFlags](./MessageFlags.md) | Represents [Message Flags](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a message | | class [MessageInteraction](./MessageInteraction.md) | Represents a [Message Interaction Structure](https://discord.com/developers/docs/interactions/receiving-and-responding#message-interaction-object) within Discord. | +| class [MessageInteractionMetadata](./MessageInteractionMetadata.md) | Represents a [Message Interaction Metadata Structure](https://discord.com/developers/docs/resources/channel#message-interaction-metadata-object-message-interaction-metadata-structure) within Discord. | +| class [MessagePollVoteAddedEvent](./MessagePollVoteAddedEvent.md) | Represents [Message Poll Vote Added Event](https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-add) | +| class [MessagePollVoteRemovedEvent](./MessagePollVoteRemovedEvent.md) | Represents [Message Poll Vote Removed Event](https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-remove) | | class [MessageReaction](./MessageReaction.md) | Represents a [Reaction Structure](https://discord.com/developers/docs/resources/channel#reaction-object) | | class [MessageReactionAddedEvent](./MessageReactionAddedEvent.md) | Represents [Message Reaction Add](https://discord.com/developers/docs/topics/gateway#message-reaction-add) | | class [MessageReactionRemovedAllEmojiEvent](./MessageReactionRemovedAllEmojiEvent.md) | Represents [Message Reaction Remove All](https://discord.com/developers/docs/topics/gateway#message-reaction-remove-emoji-message-reaction-remove-emoji) | | class [MessageReactionRemovedAllEvent](./MessageReactionRemovedAllEvent.md) | Represents [Message Reaction Remove All](https://discord.com/developers/docs/topics/gateway#message-reaction-remove-all) | | class [MessageReactionRemovedEvent](./MessageReactionRemovedEvent.md) | Represents [Message Reaction Remove](https://discord.com/developers/docs/topics/gateway#message-reaction-remove) | | class [MessageReference](./MessageReference.md) | Represents a [Message Reference Structure](https://discord.com/developers/docs/resources/channel#message-reference-object-message-reference-structure) for a message | +| enum [MessageReferenceType](./MessageReferenceType.md) | Represents [Message Reference Type](https://discord.com/developers/docs/resources/channel#message-reference-types) | +| class [MessageSnapshot](./MessageSnapshot.md) | Represents a [Message Snapshot](https://discord.com/developers/docs/resources/channel#message-snapshot-object) | | enum [MessageType](./MessageType.md) | Represents [Message Types](https://discord.com/developers/docs/resources/channel#message-object-message-types) | | class [MessageUpdate](./MessageUpdate.md) | Represents a [Message Update Structure](https://discord.com/developers/docs/resources/channel#edit-message-jsonform-params) sent in a channel within Discord.. | | class [OnboardingPrompt](./OnboardingPrompt.md) | Represents [Onboarding Prompt Structure](https://discord.com/developers/docs/resources/guild#guild-onboarding-object-onboarding-prompt-structure) | @@ -224,11 +239,18 @@ | enum [OnboardingPromptType](./OnboardingPromptType.md) | Represents [Prompt Types](https://discord.com/developers/docs/resources/guild#guild-onboarding-object-prompt-types) | | class [Overwrite](./Overwrite.md) | Represents a [Overwrite Structure](https://discord.com/developers/docs/resources/channel#overwrite-object-overwrite-structure) | | [Flags] enum [PermissionFlags](./PermissionFlags.md) | Represents [Permission Flags](https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags) for user or role | -| enum [PermissionType](./PermissionType.md) | Represents the type of a permission | +| enum [PermissionType](./PermissionType.md) | Represents the type of permission | +| class [PollAnswerCount](./PollAnswerCount.md) | Represents a [Discord Poll Answer Count](https://discord.com/developers/docs/resources/poll#poll-results-object-poll-answer-count-object-structure) | +| class [PollAnswers](./PollAnswers.md) | Represents a [Discord Poll Answers](https://discord.com/developers/docs/resources/poll#poll-answer-object) | +| class [PollCreate](./PollCreate.md) | Represents a [Discord Poll Create](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) | +| enum [PollLayoutType](./PollLayoutType.md) | Represents a [Discord Poll Layout Type](https://discord.com/developers/docs/resources/poll#layout-type) | +| class [PollMedia](./PollMedia.md) | Represents a [Discord Poll Media](https://discord.com/developers/docs/resources/poll#poll-media-object) | +| class [PollResults](./PollResults.md) | Represents a [Discord Poll Results](https://discord.com/developers/docs/resources/poll#poll-results-object) | | class [PresenceUpdatedEvent](./PresenceUpdatedEvent.md) | Represents [Presence Update](https://discord.com/developers/docs/topics/gateway#presence-update) | | enum [PrivacyLevel](./PrivacyLevel.md) | Represents a [Stage Privacy Level](https://discord.com/developers/docs/resources/stage-instance#stage-instance-object-privacy-level) within Discord. | | class [RateLimitResponse](./RateLimitResponse.md) | Represents a rate limit response from an API request | | class [ReactionCountDetails](./ReactionCountDetails.md) | Represents a [Reaction Count Details Structure](https://discord.com/developers/docs/resources/channel#reaction-count-details-object) | +| enum [ReactionType](./ReactionType.md) | Represents a [Discord Reaction Type](https://discord.com/developers/docs/resources/channel#get-reactions-reaction-types) | | enum [RequestErrorType](./RequestErrorType.md) | Represents a Discord Request Error Type | | class [RequestResponse](./RequestResponse.md) | Represents a REST response from discord | | class [ResponseError](./ResponseError.md) | Error object that is returned to the caller when a request fails | diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/EntitlementType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/EntitlementType.md index c6272c8ab..4a68a9833 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/EntitlementType.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/EntitlementType.md @@ -10,6 +10,13 @@ public enum EntitlementType | name | value | description | | --- | --- | --- | +| Purchase | `Purchase` | Entitlement was purchased by user | +| PremiumSubscription | `PremiumSubscription` | Entitlement for Discord Nitro subscription | +| DeveloperGift | `DeveloperGift` | Entitlement was gifted by developer | +| TestModePurchase | `TestModePurchase` | Entitlement was purchased by a dev in application test mode | +| FreePurchase | `FreePurchase` | Entitlement was granted when the SKU was free | +| UserGift | `UserGift` | Entitlement was claimed by user for free as a Nitro Subscriber | +| PremiumPurchase | `PremiumPurchase` | Entitlement was purchased as an app subscription | | ApplicationSubscription | `ApplicationSubscription` | Entitlement was purchased as an app subscription | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/GetPollAnswerResponse.md b/Docs/Generated/Oxide.Ext.Discord/Entities/GetPollAnswerResponse.md new file mode 100644 index 000000000..992458cd7 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/GetPollAnswerResponse.md @@ -0,0 +1,53 @@ +# GetPollAnswerResponse class + +Represents a [Get Poll Answers Response](https://discord.com/developers/docs/resources/poll#get-answer-voters-response-body) + +```csharp +public class GetPollAnswerResponse +``` + +## Public Members + +| name | description | +| --- | --- | +| [GetPollAnswerResponse](#getpollanswerresponse-constructor)() | The default constructor. | +| [Users](#users-property) { get; set; } | Users who voted for this answer | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [GetPollAnswerResponse.cs](../../../../Oxide.Ext.Discord/Entities/GetPollAnswerResponse.cs) +  +  +# GetPollAnswerResponse constructor + +The default constructor. + +```csharp +public GetPollAnswerResponse() +``` + +## See Also + +* class [GetPollAnswerResponse](./GetPollAnswerResponse.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Users property + +Users who voted for this answer + +```csharp +public List Users { get; set; } +``` + +## See Also + +* class [DiscordUser](./DiscordUser.md) +* class [GetPollAnswerResponse](./GetPollAnswerResponse.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/GetPollAnswerVoters.md b/Docs/Generated/Oxide.Ext.Discord/Entities/GetPollAnswerVoters.md new file mode 100644 index 000000000..de370fc5f --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/GetPollAnswerVoters.md @@ -0,0 +1,101 @@ +# GetPollAnswerVoters class + +Represents a [Get Answer Voters Query String Params](https://discord.com/developers/docs/resources/poll#get-answer-voters-query-string-params) + +```csharp +public class GetPollAnswerVoters : IDiscordQueryString +``` + +## Public Members + +| name | description | +| --- | --- | +| [GetPollAnswerVoters](#getpollanswervoters-constructor)() | The default constructor. | +| [After](#after-property) { get; set; } | Get users after this user ID | +| [Limit](#limit-property) { get; set; } | Max number of users to return (1-100) | +| [Type](#type-property) { get; set; } | The type of reaction | +| [ToQueryString](#toquerystring-method)() | | + +## See Also + +* interface [IDiscordQueryString](../Interfaces/IDiscordQueryString.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [GetPollAnswerVoters.cs](../../../../Oxide.Ext.Discord/Entities/GetPollAnswerVoters.cs) +  +  +# ToQueryString method + +```csharp +public string ToQueryString() +``` + +## See Also + +* class [GetPollAnswerVoters](./GetPollAnswerVoters.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GetPollAnswerVoters constructor + +The default constructor. + +```csharp +public GetPollAnswerVoters() +``` + +## See Also + +* class [GetPollAnswerVoters](./GetPollAnswerVoters.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Type property + +The type of reaction + +```csharp +public ReactionType Type { get; set; } +``` + +## See Also + +* enum [ReactionType](./ReactionType.md) +* class [GetPollAnswerVoters](./GetPollAnswerVoters.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# After property + +Get users after this user ID + +```csharp +public Snowflake? After { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [GetPollAnswerVoters](./GetPollAnswerVoters.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Limit property + +Max number of users to return (1-100) + +```csharp +public int? Limit { get; set; } +``` + +## See Also + +* class [GetPollAnswerVoters](./GetPollAnswerVoters.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/GuildMember.md b/Docs/Generated/Oxide.Ext.Discord/Entities/GuildMember.md index 305b73e59..88af04d84 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/GuildMember.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/GuildMember.md @@ -12,6 +12,7 @@ public class GuildMember : ISnowflakeEntity | --- | --- | | [GuildMember](#guildmember-constructor)() | The default constructor. | | [Avatar](#avatar-property) { get; set; } | The member's guild avatar hash | +| [AvatarDecoration](#avatardecoration-property) { get; set; } | Data for the member's guild avatar decoration | | [CommunicationDisabledUntil](#communicationdisableduntil-property) { get; set; } | When the user's timeout will expire and the user will be able to communicate in the guild again, null or a time in the past if the user is not timed out | | [Deaf](#deaf-property) { get; set; } | Whether the user is deafened in voice channels | | [DisplayName](#displayname-property) { get; } | Returns the display name show for the user in a guild | @@ -303,6 +304,22 @@ public DateTime? CommunicationDisabledUntil { get; set; } ## See Also +* class [GuildMember](./GuildMember.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AvatarDecoration property + +Data for the member's guild avatar decoration + +```csharp +public AvatarDecorationData AvatarDecoration { get; set; } +``` + +## See Also + +* class [AvatarDecorationData](./AvatarDecorationData.md) * class [GuildMember](./GuildMember.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionContextTypes.md b/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionContextTypes.md new file mode 100644 index 000000000..88d2836cd --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionContextTypes.md @@ -0,0 +1,23 @@ +# InteractionContextTypes enumeration + +Represents a [Interaction Context Types](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-context-types) + +```csharp +public enum InteractionContextTypes +``` + +## Values + +| name | value | description | +| --- | --- | --- | +| Guild | `Guild` | Interaction can be used within servers | +| BotDm | `BotDm` | Interaction can be used within DMs with the app's bot user | +| PrivateChannel | `PrivateChannel` | Interaction can be used within Group DMs and DMs other than the app's bot user | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [InteractionContextTypes.cs](../../../../Oxide.Ext.Discord/Entities/InteractionContextTypes.cs) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionPremiumRequiredMessage.md b/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionPremiumRequiredMessage.md deleted file mode 100644 index 8c0e75e26..000000000 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionPremiumRequiredMessage.md +++ /dev/null @@ -1,36 +0,0 @@ -# InteractionPremiumRequiredMessage class - -Message for Premium Required - -```csharp -public class InteractionPremiumRequiredMessage -``` - -## Public Members - -| name | description | -| --- | --- | -| [InteractionPremiumRequiredMessage](#interactionpremiumrequiredmessage-constructor)() | The default constructor. | - -## See Also - -* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -* [InteractionPremiumRequiredMessage.cs](../../../../Oxide.Ext.Discord/Entities/InteractionPremiumRequiredMessage.cs) -  -  -# InteractionPremiumRequiredMessage constructor - -The default constructor. - -```csharp -public InteractionPremiumRequiredMessage() -``` - -## See Also - -* class [InteractionPremiumRequiredMessage](./InteractionPremiumRequiredMessage.md) -* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) - - diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionPremiumRequiredResponse.md b/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionPremiumRequiredResponse.md deleted file mode 100644 index f4cac22cf..000000000 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionPremiumRequiredResponse.md +++ /dev/null @@ -1,39 +0,0 @@ -# InteractionPremiumRequiredResponse class - -Response for premium Required - -```csharp -public class InteractionPremiumRequiredResponse : - BaseInteractionResponse -``` - -## Public Members - -| name | description | -| --- | --- | -| [InteractionPremiumRequiredResponse](#interactionpremiumrequiredresponse-constructor)() | Constructor | - -## See Also - -* class [BaseInteractionResponse<T>](./BaseInteractionResponse%7BT%7D.md) -* class [InteractionPremiumRequiredMessage](./InteractionPremiumRequiredMessage.md) -* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -* [InteractionPremiumRequiredResponse.cs](../../../../Oxide.Ext.Discord/Entities/InteractionPremiumRequiredResponse.cs) -  -  -# InteractionPremiumRequiredResponse constructor - -Constructor - -```csharp -public InteractionPremiumRequiredResponse() -``` - -## See Also - -* class [InteractionPremiumRequiredResponse](./InteractionPremiumRequiredResponse.md) -* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) - - diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionResponseType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionResponseType.md index ea0869b7e..8f5ec7cdb 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionResponseType.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/InteractionResponseType.md @@ -17,7 +17,6 @@ public enum InteractionResponseType : byte | UpdateMessage | `UpdateMessage` | For components, edit the message the component was attached to | | ApplicationCommandAutocompleteResult | `ApplicationCommandAutocompleteResult` | Respond to an autocomplete interaction with suggested choices | | Modal | `Modal` | Respond to an interaction with an modal for a user to fill-out Note: You can't respond to a ModalSubmit with a new MODAL. | -| PremiumRequired | `PremiumRequired` | Respond to an interaction with an upgrade button, only available for apps with monetization enabled | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/InviteType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/InviteType.md new file mode 100644 index 000000000..df032d978 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/InviteType.md @@ -0,0 +1,23 @@ +# InviteType enumeration + +Represents [Invite Types](https://discord.com/developers/docs/resources/invite#invite-types) + +```csharp +public enum InviteType : byte +``` + +## Values + +| name | value | description | +| --- | --- | --- | +| Guild | `Guild` | Guild Invite | +| GroupDm | `GroupDm` | Guild Invite | +| Friend | `Friend` | Guild Invite | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [InviteType.cs](../../../../Oxide.Ext.Discord/Entities/InviteType.cs) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageAttachment.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageAttachment.md index 1b511f85c..ccc042a6e 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageAttachment.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageAttachment.md @@ -21,6 +21,7 @@ public class MessageAttachment : ISnowflakeEntity | [Id](#id-property) { get; set; } | Attachment ID | | [ProxyUrl](#proxyurl-property) { get; set; } | A proxied url of file | | [Size](#size-property) { get; set; } | Size of file in bytes | +| [Title](#title-property) { get; set; } | Title of the file | | [Url](#url-property) { get; set; } | Source url of file | | [Waveform](#waveform-property) { get; set; } | base64 encoded bytearray representing a sampled waveform (currently for voice messages) | | [Width](#width-property) { get; set; } | Width of file (if image) | @@ -74,6 +75,21 @@ public string Filename { get; set; } ## See Also +* class [MessageAttachment](./MessageAttachment.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Title property + +Title of the file + +```csharp +public string Title { get; set; } +``` + +## See Also + * class [MessageAttachment](./MessageAttachment.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageCall.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageCall.md new file mode 100644 index 000000000..944ca905e --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageCall.md @@ -0,0 +1,69 @@ +# MessageCall class + +Represents a [Message Call Structure](https://discord.com/developers/docs/resources/channel#message-call-object) + +```csharp +public class MessageCall +``` + +## Public Members + +| name | description | +| --- | --- | +| [MessageCall](#messagecall-constructor)() | The default constructor. | +| [EndedTimestamp](#endedtimestamp-property) { get; set; } | Time when call ended | +| [Participants](#participants-property) { get; set; } | Array of user ids that participated in the call | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [MessageCall.cs](../../../../Oxide.Ext.Discord/Entities/MessageCall.cs) +  +  +# MessageCall constructor + +The default constructor. + +```csharp +public MessageCall() +``` + +## See Also + +* class [MessageCall](./MessageCall.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Participants property + +Array of user ids that participated in the call + +```csharp +public List Participants { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessageCall](./MessageCall.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# EndedTimestamp property + +Time when call ended + +```csharp +public DateTimeOffset? EndedTimestamp { get; set; } +``` + +## See Also + +* class [MessageCall](./MessageCall.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageCreate.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageCreate.md index 5ce1e7c09..05e7830fb 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageCreate.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageCreate.md @@ -12,7 +12,7 @@ public class MessageCreate : BaseMessageCreate | --- | --- | | [MessageCreate](#messagecreate-constructor)() | The default constructor. | | [EnforceNonce](#enforcenonce-property) { get; set; } | If true and nonce is present, it will be checked for uniqueness in the past few minutes. If another message was created by the same author with the same nonce, that message will be returned and no new message will be created. | -| [MessageReference](#messagereference-property) { get; set; } | Include to make your message a reply | +| [MessageReference](#messagereference-property) { get; set; } | Include to make your message a reply or a forward | | [Nonce](#nonce-property) { get; set; } | Can be used to verify a message was sent (up to 25 characters). Value will appear in the Message Create event. | ## See Also @@ -70,7 +70,7 @@ public bool EnforceNonce { get; set; }   # MessageReference property -Include to make your message a reply +Include to make your message a reply or a forward ```csharp public MessageReference MessageReference { get; set; } diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageInteractionMetadata.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageInteractionMetadata.md new file mode 100644 index 000000000..701cd6a9d --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageInteractionMetadata.md @@ -0,0 +1,155 @@ +# MessageInteractionMetadata class + +Represents a [Message Interaction Metadata Structure](https://discord.com/developers/docs/resources/channel#message-interaction-metadata-object-message-interaction-metadata-structure) within Discord. + +```csharp +public class MessageInteractionMetadata +``` + +## Public Members + +| name | description | +| --- | --- | +| [MessageInteractionMetadata](#messageinteractionmetadata-constructor)() | The default constructor. | +| [AuthorizingIntegrationOwners](#authorizingintegrationowners-property) { get; set; } | IDs for installation context(s) related to an interaction. | +| [Id](#id-property) { get; set; } | ID of the interaction | +| [InteractedMessageId](#interactedmessageid-property) { get; set; } | ID of the message that contained interactive component, present only on messages created from component interactions | +| [OriginalResponseMessageId](#originalresponsemessageid-property) { get; set; } | ID of the original response message, present only on follow-up messages | +| [TriggeringInteractionMetadata](#triggeringinteractionmetadata-property) { get; set; } | Metadata for the interaction that was used to open the modal, present only on modal submit interactions | +| [Type](#type-property) { get; set; } | Type of interaction | +| [User](#user-property) { get; set; } | IUser who triggered the interaction | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [MessageInteractionMetadata.cs](../../../../Oxide.Ext.Discord/Entities/MessageInteractionMetadata.cs) +  +  +# MessageInteractionMetadata constructor + +The default constructor. + +```csharp +public MessageInteractionMetadata() +``` + +## See Also + +* class [MessageInteractionMetadata](./MessageInteractionMetadata.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Id property + +ID of the interaction + +```csharp +public Snowflake Id { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessageInteractionMetadata](./MessageInteractionMetadata.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Type property + +Type of interaction + +```csharp +public InteractionType Type { get; set; } +``` + +## See Also + +* enum [InteractionType](./InteractionType.md) +* class [MessageInteractionMetadata](./MessageInteractionMetadata.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# User property + +IUser who triggered the interaction + +```csharp +public DiscordUser User { get; set; } +``` + +## See Also + +* class [DiscordUser](./DiscordUser.md) +* class [MessageInteractionMetadata](./MessageInteractionMetadata.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AuthorizingIntegrationOwners property + +IDs for installation context(s) related to an interaction. + +```csharp +public Hash AuthorizingIntegrationOwners { get; set; } +``` + +## See Also + +* enum [ApplicationIntegrationType](./ApplicationIntegrationType.md) +* struct [Snowflake](./Snowflake.md) +* class [MessageInteractionMetadata](./MessageInteractionMetadata.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# OriginalResponseMessageId property + +ID of the original response message, present only on follow-up messages + +```csharp +public Snowflake? OriginalResponseMessageId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessageInteractionMetadata](./MessageInteractionMetadata.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# InteractedMessageId property + +ID of the message that contained interactive component, present only on messages created from component interactions + +```csharp +public Snowflake? InteractedMessageId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessageInteractionMetadata](./MessageInteractionMetadata.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# TriggeringInteractionMetadata property + +Metadata for the interaction that was used to open the modal, present only on modal submit interactions + +```csharp +public MessageInteractionMetadata TriggeringInteractionMetadata { get; set; } +``` + +## See Also + +* class [MessageInteractionMetadata](./MessageInteractionMetadata.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessagePollVoteAddedEvent.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessagePollVoteAddedEvent.md new file mode 100644 index 000000000..e111f2bbd --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessagePollVoteAddedEvent.md @@ -0,0 +1,120 @@ +# MessagePollVoteAddedEvent class + +Represents [Message Poll Vote Added Event](https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-add) + +```csharp +public class MessagePollVoteAddedEvent +``` + +## Public Members + +| name | description | +| --- | --- | +| [MessagePollVoteAddedEvent](#messagepollvoteaddedevent-constructor)() | The default constructor. | +| [AnswerId](#answerid-property) { get; set; } | ID of the answer | +| [ChannelId](#channelid-property) { get; set; } | The id of the channel | +| [GuildId](#guildid-property) { get; set; } | ID of the guild | +| [MessageId](#messageid-property) { get; set; } | ID of the message | +| [UserId](#userid-property) { get; set; } | ID of the user | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [MessagePollVoteAddedEvent.cs](../../../../Oxide.Ext.Discord/Entities/MessagePollVoteAddedEvent.cs) +  +  +# MessagePollVoteAddedEvent constructor + +The default constructor. + +```csharp +public MessagePollVoteAddedEvent() +``` + +## See Also + +* class [MessagePollVoteAddedEvent](./MessagePollVoteAddedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# UserId property + +ID of the user + +```csharp +public Snowflake UserId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessagePollVoteAddedEvent](./MessagePollVoteAddedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# ChannelId property + +The id of the channel + +```csharp +public Snowflake ChannelId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessagePollVoteAddedEvent](./MessagePollVoteAddedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# MessageId property + +ID of the message + +```csharp +public Snowflake MessageId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessagePollVoteAddedEvent](./MessagePollVoteAddedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GuildId property + +ID of the guild + +```csharp +public Snowflake? GuildId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessagePollVoteAddedEvent](./MessagePollVoteAddedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AnswerId property + +ID of the answer + +```csharp +public int AnswerId { get; set; } +``` + +## See Also + +* class [MessagePollVoteAddedEvent](./MessagePollVoteAddedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessagePollVoteRemovedEvent.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessagePollVoteRemovedEvent.md new file mode 100644 index 000000000..8b5e5d9b3 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessagePollVoteRemovedEvent.md @@ -0,0 +1,120 @@ +# MessagePollVoteRemovedEvent class + +Represents [Message Poll Vote Removed Event](https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-remove) + +```csharp +public class MessagePollVoteRemovedEvent +``` + +## Public Members + +| name | description | +| --- | --- | +| [MessagePollVoteRemovedEvent](#messagepollvoteremovedevent-constructor)() | The default constructor. | +| [AnswerId](#answerid-property) { get; set; } | ID of the answer | +| [ChannelId](#channelid-property) { get; set; } | The id of the channel | +| [GuildId](#guildid-property) { get; set; } | ID of the guild | +| [MessageId](#messageid-property) { get; set; } | ID of the message | +| [UserId](#userid-property) { get; set; } | ID of the user | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [MessagePollVoteRemovedEvent.cs](../../../../Oxide.Ext.Discord/Entities/MessagePollVoteRemovedEvent.cs) +  +  +# MessagePollVoteRemovedEvent constructor + +The default constructor. + +```csharp +public MessagePollVoteRemovedEvent() +``` + +## See Also + +* class [MessagePollVoteRemovedEvent](./MessagePollVoteRemovedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# UserId property + +ID of the user + +```csharp +public Snowflake UserId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessagePollVoteRemovedEvent](./MessagePollVoteRemovedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# ChannelId property + +The id of the channel + +```csharp +public Snowflake ChannelId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessagePollVoteRemovedEvent](./MessagePollVoteRemovedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# MessageId property + +ID of the message + +```csharp +public Snowflake MessageId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessagePollVoteRemovedEvent](./MessagePollVoteRemovedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GuildId property + +ID of the guild + +```csharp +public Snowflake? GuildId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessagePollVoteRemovedEvent](./MessagePollVoteRemovedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AnswerId property + +ID of the answer + +```csharp +public int AnswerId { get; set; } +``` + +## See Also + +* class [MessagePollVoteRemovedEvent](./MessagePollVoteRemovedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReactionAddedEvent.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReactionAddedEvent.md index 420b81288..12013d563 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReactionAddedEvent.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReactionAddedEvent.md @@ -11,12 +11,15 @@ public class MessageReactionAddedEvent | name | description | | --- | --- | | [MessageReactionAddedEvent](#messagereactionaddedevent-constructor)() | The default constructor. | +| [Burst](#burst-property) { get; set; } | True if this is a super-reaction | +| [BurstColors](#burstcolors-property) { get; set; } | Colors used for super-reaction animation | | [ChannelId](#channelid-property) { get; set; } | The id of the channel | | [Emoji](#emoji-property) { get; set; } | The emoji used to react | | [GuildId](#guildid-property) { get; set; } | The id of the guild | | [Member](#member-property) { get; set; } | The member who reacted if this happened in a guild | | [MessageAuthorId](#messageauthorid-property) { get; set; } | ID of the user who authored the message which was reacted to | | [MessageId](#messageid-property) { get; set; } | The id of the message | +| [Type](#type-property) { get; set; } | The type of the reaction | | [UserId](#userid-property) { get; set; } | The id of the user | ## See Also @@ -151,5 +154,52 @@ public Snowflake? MessageAuthorId { get; set; } * class [MessageReactionAddedEvent](./MessageReactionAddedEvent.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Burst property + +True if this is a super-reaction + +```csharp +public bool Burst { get; set; } +``` + +## See Also + +* class [MessageReactionAddedEvent](./MessageReactionAddedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# BurstColors property + +Colors used for super-reaction animation + +```csharp +public List BurstColors { get; set; } +``` + +## See Also + +* struct [DiscordColor](./DiscordColor.md) +* class [MessageReactionAddedEvent](./MessageReactionAddedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Type property + +The type of the reaction + +```csharp +public ReactionType Type { get; set; } +``` + +## See Also + +* enum [ReactionType](./ReactionType.md) +* class [MessageReactionAddedEvent](./MessageReactionAddedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReactionRemovedEvent.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReactionRemovedEvent.md index 66974dccb..e5191e5e0 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReactionRemovedEvent.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReactionRemovedEvent.md @@ -11,10 +11,12 @@ public class MessageReactionRemovedEvent | name | description | | --- | --- | | [MessageReactionRemovedEvent](#messagereactionremovedevent-constructor)() | The default constructor. | +| [Burst](#burst-property) { get; set; } | True if this is a super-reaction | | [ChannelId](#channelid-property) { get; set; } | The id of the channel | -| [Emoji](#emoji-property) { get; set; } | The emoji removed | +| [Emoji](#emoji-property) { get; set; } | Emoji used to react | | [GuildId](#guildid-property) { get; set; } | The id of the guild | | [MessageId](#messageid-property) { get; set; } | The id of the message | +| [Type](#type-property) { get; set; } | The type of the reaction | | [UserId](#userid-property) { get; set; } | The id of the user | ## See Also @@ -105,7 +107,7 @@ public Snowflake? GuildId { get; set; }   # Emoji property -The emoji removed +Emoji used to react ```csharp public DiscordEmoji Emoji { get; set; } @@ -117,5 +119,36 @@ public DiscordEmoji Emoji { get; set; } * class [MessageReactionRemovedEvent](./MessageReactionRemovedEvent.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Burst property + +True if this is a super-reaction + +```csharp +public bool Burst { get; set; } +``` + +## See Also + +* class [MessageReactionRemovedEvent](./MessageReactionRemovedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Type property + +The type of the reaction + +```csharp +public ReactionType Type { get; set; } +``` + +## See Also + +* enum [ReactionType](./ReactionType.md) +* class [MessageReactionRemovedEvent](./MessageReactionRemovedEvent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReference.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReference.md index c58692f96..f38a5eedc 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReference.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReference.md @@ -15,6 +15,7 @@ public class MessageReference | [FailIfNotExists](#failifnotexists-property) { get; set; } | When sending, whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message, default true | | [GuildId](#guildid-property) { get; set; } | ID of the originating message's guild | | [MessageId](#messageid-property) { get; set; } | ID of the originating message | +| [Type](#type-property) { get; set; } | Type of reference. | ## See Also @@ -33,6 +34,22 @@ public MessageReference() ## See Also +* class [MessageReference](./MessageReference.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Type property + +Type of reference. + +```csharp +public MessageReferenceType? Type { get; set; } +``` + +## See Also + +* enum [MessageReferenceType](./MessageReferenceType.md) * class [MessageReference](./MessageReference.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReferenceType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReferenceType.md new file mode 100644 index 000000000..c4eeded44 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageReferenceType.md @@ -0,0 +1,22 @@ +# MessageReferenceType enumeration + +Represents [Message Reference Type](https://discord.com/developers/docs/resources/channel#message-reference-types) + +```csharp +public enum MessageReferenceType +``` + +## Values + +| name | value | description | +| --- | --- | --- | +| Default | `Default` | A standard reference used by replies. | +| Forward | `Forward` | Reference used to point to a message at a point in time. | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [MessageReferenceType.cs](../../../../Oxide.Ext.Discord/Entities/MessageReferenceType.cs) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageSnapshot.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageSnapshot.md new file mode 100644 index 000000000..ec6f6f9b7 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageSnapshot.md @@ -0,0 +1,70 @@ +# MessageSnapshot class + +Represents a [Message Snapshot](https://discord.com/developers/docs/resources/channel#message-snapshot-object) + +```csharp +public class MessageSnapshot +``` + +## Public Members + +| name | description | +| --- | --- | +| [MessageSnapshot](#messagesnapshot-constructor)() | The default constructor. | +| [GuildId](#guildid-property) { get; set; } | ID of the origin message's guild | +| [Message](#message-property) { get; set; } | Subset of fields in the message object | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [MessageSnapshot.cs](../../../../Oxide.Ext.Discord/Entities/MessageSnapshot.cs) +  +  +# MessageSnapshot constructor + +The default constructor. + +```csharp +public MessageSnapshot() +``` + +## See Also + +* class [MessageSnapshot](./MessageSnapshot.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Message property + +Subset of fields in the message object + +```csharp +public DiscordMessage Message { get; set; } +``` + +## See Also + +* class [DiscordMessage](./DiscordMessage.md) +* class [MessageSnapshot](./MessageSnapshot.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GuildId property + +ID of the origin message's guild + +```csharp +public Snowflake? GuildId { get; set; } +``` + +## See Also + +* struct [Snowflake](./Snowflake.md) +* class [MessageSnapshot](./MessageSnapshot.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageType.md index 350b84f01..69b5f5c7e 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/MessageType.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/MessageType.md @@ -42,6 +42,11 @@ public enum MessageType : byte | StageRaiseHand | `StageRaiseHand` | Message is a stage raise hand | | StageTopic | `StageTopic` | Message is a stage topic | | GuildApplicationPremiumSubscription | `GuildApplicationPremiumSubscription` | Message is a Guild Application Premium Subscription | +| GuildIncidentAlertModeEnabled | `GuildIncidentAlertModeEnabled` | Message is a Guild Incident Alert Mode Enabled | +| GuildIncidentAlertModeDisabled | `GuildIncidentAlertModeDisabled` | Message is a Guild Incident Alert Mode Disabled | +| GuildIncidentReportRaid | `GuildIncidentReportRaid` | Message is a Guild Incident Report Raid | +| GuildIncidentReportFalseAlarm | `GuildIncidentReportFalseAlarm` | Message is a Guild Incident Report False Alarm | +| PurchaseNotification | `PurchaseNotification` | Message is a Purchase Notification | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/PermissionFlags.md b/Docs/Generated/Oxide.Ext.Discord/Entities/PermissionFlags.md index 4cff0058b..29a80cdf5 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/PermissionFlags.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/PermissionFlags.md @@ -64,7 +64,9 @@ public enum PermissionFlags : ulong | CreateEvents | `1 << 44` | Allows for creating scheduled events, and editing and deleting those created by the current user | | UseExternalSounds | `1 << 45` | Allows the usage of custom soundboard sounds from other servers | | SendVoiceMessages | `1 << 46` | Allows sending voice messages | -| UseClydeAi | `1 << 47` | Allows members to interact with the Clyde AI bot | +| UseClydeAi | `1 << 47` | Allows sending polls | +| SendPolls | `1 << 49` | Allows sending polls | +| UseExternalApps | `1 << 50` | Allows user-installed apps to send public responses. When disabled, users will still be allowed to use their apps but the responses will be ephemeral. This only applies to apps not also installed to the server. | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/PermissionType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/PermissionType.md index a1697820d..9a9a1efb9 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/PermissionType.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/PermissionType.md @@ -1,6 +1,6 @@ # PermissionType enumeration -Represents the type of a permission +Represents the type of permission ```csharp public enum PermissionType : byte diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/PollAnswerCount.md b/Docs/Generated/Oxide.Ext.Discord/Entities/PollAnswerCount.md new file mode 100644 index 000000000..6798c938f --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/PollAnswerCount.md @@ -0,0 +1,84 @@ +# PollAnswerCount class + +Represents a [Discord Poll Answer Count](https://discord.com/developers/docs/resources/poll#poll-results-object-poll-answer-count-object-structure) + +```csharp +public class PollAnswerCount +``` + +## Public Members + +| name | description | +| --- | --- | +| [PollAnswerCount](#pollanswercount-constructor)() | The default constructor. | +| [Count](#count-property) { get; set; } | The number of votes for this answer | +| [Id](#id-property) { get; set; } | The answer_id | +| [MeVoted](#mevoted-property) { get; set; } | Whether the current user voted for this answer | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [PollAnswerCount.cs](../../../../Oxide.Ext.Discord/Entities/PollAnswerCount.cs) +  +  +# PollAnswerCount constructor + +The default constructor. + +```csharp +public PollAnswerCount() +``` + +## See Also + +* class [PollAnswerCount](./PollAnswerCount.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Id property + +The answer_id + +```csharp +public int Id { get; set; } +``` + +## See Also + +* class [PollAnswerCount](./PollAnswerCount.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Count property + +The number of votes for this answer + +```csharp +public int Count { get; set; } +``` + +## See Also + +* class [PollAnswerCount](./PollAnswerCount.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# MeVoted property + +Whether the current user voted for this answer + +```csharp +public bool MeVoted { get; set; } +``` + +## See Also + +* class [PollAnswerCount](./PollAnswerCount.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/PollAnswers.md b/Docs/Generated/Oxide.Ext.Discord/Entities/PollAnswers.md new file mode 100644 index 000000000..353c7b4b8 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/PollAnswers.md @@ -0,0 +1,69 @@ +# PollAnswers class + +Represents a [Discord Poll Answers](https://discord.com/developers/docs/resources/poll#poll-answer-object) + +```csharp +public class PollAnswers +``` + +## Public Members + +| name | description | +| --- | --- | +| [PollAnswers](#pollanswers-constructor)() | The default constructor. | +| [AnswerId](#answerid-property) { get; set; } | The ID of the answer | +| [PollMedia](#pollmedia-property) { get; set; } | The data of the answer | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [PollAnswers.cs](../../../../Oxide.Ext.Discord/Entities/PollAnswers.cs) +  +  +# PollAnswers constructor + +The default constructor. + +```csharp +public PollAnswers() +``` + +## See Also + +* class [PollAnswers](./PollAnswers.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AnswerId property + +The ID of the answer + +```csharp +public int AnswerId { get; set; } +``` + +## See Also + +* class [PollAnswers](./PollAnswers.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# PollMedia property + +The data of the answer + +```csharp +public PollMedia PollMedia { get; set; } +``` + +## See Also + +* class [PollMedia](./PollMedia.md) +* class [PollAnswers](./PollAnswers.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/PollCreate.md b/Docs/Generated/Oxide.Ext.Discord/Entities/PollCreate.md new file mode 100644 index 000000000..a5d02fd2e --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/PollCreate.md @@ -0,0 +1,119 @@ +# PollCreate class + +Represents a [Discord Poll Create](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) + +```csharp +public class PollCreate +``` + +## Public Members + +| name | description | +| --- | --- | +| [PollCreate](#pollcreate-constructor)() | The default constructor. | +| [AllowMultiselect](#allowmultiselect-property) { get; set; } | Whether a user can select multiple answers | +| [Answers](#answers-property) { get; set; } | Each of the answers available in the poll. | +| [Duration](#duration-property) { get; set; } | Number of hours the poll should be open for, up to 32 days | +| [LayoutType](#layouttype-property) { get; set; } | The layout type of the poll | +| [Question](#question-property) { get; set; } | The question of the poll. Only text is supported. | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [PollCreate.cs](../../../../Oxide.Ext.Discord/Entities/PollCreate.cs) +  +  +# PollCreate constructor + +The default constructor. + +```csharp +public PollCreate() +``` + +## See Also + +* class [PollCreate](./PollCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Question property + +The question of the poll. Only text is supported. + +```csharp +public PollMedia Question { get; set; } +``` + +## See Also + +* class [PollMedia](./PollMedia.md) +* class [PollCreate](./PollCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Answers property + +Each of the answers available in the poll. + +```csharp +public List Answers { get; set; } +``` + +## See Also + +* class [PollAnswers](./PollAnswers.md) +* class [PollCreate](./PollCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Duration property + +Number of hours the poll should be open for, up to 32 days + +```csharp +public int Duration { get; set; } +``` + +## See Also + +* class [PollCreate](./PollCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AllowMultiselect property + +Whether a user can select multiple answers + +```csharp +public bool AllowMultiselect { get; set; } +``` + +## See Also + +* class [PollCreate](./PollCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# LayoutType property + +The layout type of the poll + +```csharp +public PollLayoutType LayoutType { get; set; } +``` + +## See Also + +* enum [PollLayoutType](./PollLayoutType.md) +* class [PollCreate](./PollCreate.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/PollLayoutType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/PollLayoutType.md new file mode 100644 index 000000000..af1d326aa --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/PollLayoutType.md @@ -0,0 +1,21 @@ +# PollLayoutType enumeration + +Represents a [Discord Poll Layout Type](https://discord.com/developers/docs/resources/poll#layout-type) + +```csharp +public enum PollLayoutType +``` + +## Values + +| name | value | description | +| --- | --- | --- | +| Default | `Default` | The default layout type. | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [PollLayoutType.cs](../../../../Oxide.Ext.Discord/Entities/PollLayoutType.cs) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/PollMedia.md b/Docs/Generated/Oxide.Ext.Discord/Entities/PollMedia.md new file mode 100644 index 000000000..5264a5e59 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/PollMedia.md @@ -0,0 +1,69 @@ +# PollMedia class + +Represents a [Discord Poll Media](https://discord.com/developers/docs/resources/poll#poll-media-object) + +```csharp +public class PollMedia +``` + +## Public Members + +| name | description | +| --- | --- | +| [PollMedia](#pollmedia-constructor)() | The default constructor. | +| [Emoji](#emoji-property) { get; set; } | The emoji of the field | +| [Text](#text-property) { get; set; } | The text of the field | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [PollMedia.cs](../../../../Oxide.Ext.Discord/Entities/PollMedia.cs) +  +  +# PollMedia constructor + +The default constructor. + +```csharp +public PollMedia() +``` + +## See Also + +* class [PollMedia](./PollMedia.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Text property + +The text of the field + +```csharp +public string Text { get; set; } +``` + +## See Also + +* class [PollMedia](./PollMedia.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Emoji property + +The emoji of the field + +```csharp +public DiscordEmoji Emoji { get; set; } +``` + +## See Also + +* class [DiscordEmoji](./DiscordEmoji.md) +* class [PollMedia](./PollMedia.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/PollResults.md b/Docs/Generated/Oxide.Ext.Discord/Entities/PollResults.md new file mode 100644 index 000000000..02a223d5d --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/PollResults.md @@ -0,0 +1,69 @@ +# PollResults class + +Represents a [Discord Poll Results](https://discord.com/developers/docs/resources/poll#poll-results-object) + +```csharp +public class PollResults +``` + +## Public Members + +| name | description | +| --- | --- | +| [PollResults](#pollresults-constructor)() | The default constructor. | +| [AnswerCounts](#answercounts-property) { get; set; } | The counts for each answer | +| [IsFinalized](#isfinalized-property) { get; set; } | Whether the votes have been precisely counted | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [PollResults.cs](../../../../Oxide.Ext.Discord/Entities/PollResults.cs) +  +  +# PollResults constructor + +The default constructor. + +```csharp +public PollResults() +``` + +## See Also + +* class [PollResults](./PollResults.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# IsFinalized property + +Whether the votes have been precisely counted + +```csharp +public bool IsFinalized { get; set; } +``` + +## See Also + +* class [PollResults](./PollResults.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AnswerCounts property + +The counts for each answer + +```csharp +public List AnswerCounts { get; set; } +``` + +## See Also + +* class [PollAnswerCount](./PollAnswerCount.md) +* class [PollResults](./PollResults.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ReactionType.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ReactionType.md new file mode 100644 index 000000000..e773fde00 --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ReactionType.md @@ -0,0 +1,22 @@ +# ReactionType enumeration + +Represents a [Discord Reaction Type](https://discord.com/developers/docs/resources/channel#get-reactions-reaction-types) + +```csharp +public enum ReactionType +``` + +## Values + +| name | value | description | +| --- | --- | --- | +| Normal | `Normal` | Normal Reaction Type | +| Burst | `Burst` | Burst Reaction Type | + +## See Also + +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [ReactionType.cs](../../../../Oxide.Ext.Discord/Entities/ReactionType.cs) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/Snowflake.md b/Docs/Generated/Oxide.Ext.Discord/Entities/Snowflake.md index 71d2c523e..9faa5a42f 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/Snowflake.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/Snowflake.md @@ -22,7 +22,7 @@ public struct Snowflake : IComparable, IComparable, IDiscordKe | override [ToString](#tostring-method)() | Returns ID as a string | | [TryFormat](#tryformat-method)(…) | Try to format the snowflake into the span | | static readonly [DiscordEpoch](#discordepoch-field) | DateTimeOffset since discord Epoch | -| static [TryParse](#tryparse-method)(…) | Try to parse the a string into a snowflake value | +| static [TryParse](#tryparse-method-1-of-2)(…) | Try to parse the a string into a snowflake value (2 methods) | | [operator ==](#snowflake-equality-operator) | Returns true if left and right are equal | | [explicit operator](#snowflake-explicit-operator-1-of-2) | Converts a ulong to a snowflake (2 operators) | | [operator >](#snowflake-greaterthan-operator) | Returns true if left snowflake's ID is greater than right's ID | @@ -70,7 +70,32 @@ public bool IsValid() * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     -# TryParse method +# TryParse method (1 of 2) + +Try to parse the a string into a snowflake value + +```csharp +public static bool TryParse(ReadOnlySpan value, out Snowflake snowflake) +``` + +| parameter | description | +| --- | --- | +| value | String to parse | +| snowflake | Snowflake to return | + +## Return Value + +True if parse succeeded; false otherwise + +## See Also + +* struct [Snowflake](./Snowflake.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# TryParse method (2 of 2) Try to parse the a string into a snowflake value diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/ThreadForumCreate.md b/Docs/Generated/Oxide.Ext.Discord/Entities/ThreadForumCreate.md index d61e9d319..9e899c3f2 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/ThreadForumCreate.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/ThreadForumCreate.md @@ -35,7 +35,7 @@ Adds an attachment to the message ```csharp public void AddAttachment(string filename, byte[] data, string contentType, - string description = null) + string description = null, string title = null) ``` | parameter | description | @@ -44,6 +44,7 @@ public void AddAttachment(string filename, byte[] data, string contentType, | data | byte[] of the attachment | | contentType | Attachment content type | | description | Description for the attachment | +| title | Title of the attachment | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/UserModifyCurrent.md b/Docs/Generated/Oxide.Ext.Discord/Entities/UserModifyCurrent.md index d7f5f3557..b506188e3 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/UserModifyCurrent.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/UserModifyCurrent.md @@ -12,6 +12,7 @@ public class UserModifyCurrent | --- | --- | | [UserModifyCurrent](#usermodifycurrent-constructor)() | The default constructor. | | [Avatar](#avatar-property) { get; set; } | If passed, modifies the user's avatar | +| [Banner](#banner-property) { get; set; } | If passed, modifies the user's banner | | [Username](#username-property) { get; set; } | User's username, if changed may cause the user's discriminator to be randomized. | | [Validate](#validate-method)() | | @@ -70,11 +71,28 @@ public string Username { get; set; } If passed, modifies the user's avatar ```csharp -public string Avatar { get; set; } +public DiscordImageData Avatar { get; set; } ``` ## See Also +* struct [DiscordImageData](./DiscordImageData.md) +* class [UserModifyCurrent](./UserModifyCurrent.md) +* namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Banner property + +If passed, modifies the user's banner + +```csharp +public DiscordImageData Banner { get; set; } +``` + +## See Also + +* struct [DiscordImageData](./DiscordImageData.md) * class [UserModifyCurrent](./UserModifyCurrent.md) * namespace [Oxide.Ext.Discord.Entities](./EntitiesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Entities/WebhookEditMessage.md b/Docs/Generated/Oxide.Ext.Discord/Entities/WebhookEditMessage.md index 1be2f35ca..ac0c35279 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Entities/WebhookEditMessage.md +++ b/Docs/Generated/Oxide.Ext.Discord/Entities/WebhookEditMessage.md @@ -66,7 +66,7 @@ Adds an attachment to the message ```csharp public void AddAttachment(string filename, byte[] data, string contentType, - string description = null) + string description = null, string title = null) ``` | parameter | description | @@ -75,6 +75,7 @@ public void AddAttachment(string filename, byte[] data, string contentType, | data | byte[] of the attachment | | contentType | Attachment content type | | description | Description for the attachment | +| title | Title of the attachment | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Exceptions/DiscordLoggerException.md b/Docs/Generated/Oxide.Ext.Discord/Exceptions/DiscordLoggerException.md new file mode 100644 index 000000000..50a08c4de --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Exceptions/DiscordLoggerException.md @@ -0,0 +1,16 @@ +# DiscordLoggerException class + +Exceptions for the [`DiscordClient`](../Clients/DiscordClient.md) + +```csharp +public class DiscordLoggerException : BaseDiscordException +``` + +## See Also + +* class [BaseDiscordException](./BaseDiscordException.md) +* namespace [Oxide.Ext.Discord.Exceptions](./ExceptionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [DiscordLoggerException.cs](../../../../Oxide.Ext.Discord/Exceptions/DiscordLoggerException.cs) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/Exceptions/ExceptionsNamespace.md b/Docs/Generated/Oxide.Ext.Discord/Exceptions/ExceptionsNamespace.md index 81f2460e1..7151a22fa 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Exceptions/ExceptionsNamespace.md +++ b/Docs/Generated/Oxide.Ext.Discord/Exceptions/ExceptionsNamespace.md @@ -10,6 +10,7 @@ | class [DiscordApplicationException](./DiscordApplicationException.md) | Exceptions for [`DiscordApplication`](./Oxide.Ext.Discord/Entities/DiscordApplication.md) | | class [DiscordClientException](./DiscordClientException.md) | Exceptions for the [`DiscordClient`](./Oxide.Ext.Discord/Clients/DiscordClient.md) | | class [DiscordLocaleNotFoundException](./DiscordLocaleNotFoundException.md) | Exception thrown when Discord Locale is not found | +| class [DiscordLoggerException](./DiscordLoggerException.md) | Exceptions for the [`DiscordClient`](./Oxide.Ext.Discord/Clients/DiscordClient.md) | | class [DiscordTemplateException](./DiscordTemplateException.md) | Exception for Discord Templates | | class [DiscordWebSocketException](./DiscordWebSocketException.md) | Represents an exception that occured with the websocket | | class [DuplicateTemplateException](./DuplicateTemplateException.md) | Thrown when duplicate templates have been registered for the same type, plugin, and name | diff --git a/Docs/Generated/Oxide.Ext.Discord/Exceptions/InvalidSnowflakeException.md b/Docs/Generated/Oxide.Ext.Discord/Exceptions/InvalidSnowflakeException.md index 607a851dc..2a2e00033 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Exceptions/InvalidSnowflakeException.md +++ b/Docs/Generated/Oxide.Ext.Discord/Exceptions/InvalidSnowflakeException.md @@ -6,11 +6,76 @@ Exception thrown when an invalid Snowflake ID is used in an API call public class InvalidSnowflakeException : BaseDiscordException ``` +## Public Members + +| name | description | +| --- | --- | +| static [ThrowIfInvalid](#throwifinvalid-method-1-of-4)(…) | (4 methods) | + ## See Also * class [BaseDiscordException](./BaseDiscordException.md) * namespace [Oxide.Ext.Discord.Exceptions](./ExceptionsNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) * [InvalidSnowflakeException.cs](../../../../Oxide.Ext.Discord/Exceptions/InvalidSnowflakeException.cs) +  +  +# ThrowIfInvalid method (1 of 4) + +```csharp +public static void ThrowIfInvalid(ICollection snowflakes, string paramName = null) +``` + +## See Also + +* struct [Snowflake](../Entities/Snowflake.md) +* class [InvalidSnowflakeException](./InvalidSnowflakeException.md) +* namespace [Oxide.Ext.Discord.Exceptions](./ExceptionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# ThrowIfInvalid method (2 of 4) + +```csharp +public static void ThrowIfInvalid(Snowflake snowflake, string paramName = null) +``` + +## See Also + +* struct [Snowflake](../Entities/Snowflake.md) +* class [InvalidSnowflakeException](./InvalidSnowflakeException.md) +* namespace [Oxide.Ext.Discord.Exceptions](./ExceptionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# ThrowIfInvalid method (3 of 4) + +```csharp +public static void ThrowIfInvalid(Snowflake? snowflake, string paramName = null) +``` + +## See Also + +* struct [Snowflake](../Entities/Snowflake.md) +* class [InvalidSnowflakeException](./InvalidSnowflakeException.md) +* namespace [Oxide.Ext.Discord.Exceptions](./ExceptionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# ThrowIfInvalid method (4 of 4) + +```csharp +public static void ThrowIfInvalid(Snowflake? snowflake, bool requireValue, string paramName = null) +``` + +## See Also + +* struct [Snowflake](../Entities/Snowflake.md) +* class [InvalidSnowflakeException](./InvalidSnowflakeException.md) +* namespace [Oxide.Ext.Discord.Exceptions](./ExceptionsNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Extensions/DiscordUserExt.md b/Docs/Generated/Oxide.Ext.Discord/Extensions/DiscordUserExt.md index 1d7a409b8..2a4dc9b43 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Extensions/DiscordUserExt.md +++ b/Docs/Generated/Oxide.Ext.Discord/Extensions/DiscordUserExt.md @@ -10,9 +10,9 @@ public static class DiscordUserExt | name | description | | --- | --- | -| static [HasPermission](#haspermission-method)(…) | Return if the discord user has the given oxide permission. If the user is not linked this will return false | +| static [HasPermission](#haspermission-method)(…) | Return if the discord user has the given oxide permission. If the user is not linked, this will return false | | static [IsLinked](#islinked-method)(…) | Returns true if the player is linked | -| static [SendChatMessage](#sendchatmessage-method-1-of-2)(…) | Send chat message to the user if they're connected (2 methods) | +| static [SendChatMessage](#sendchatmessage-method-1-of-2)(…) | Send a chat message to the user if they're connected (2 methods) | ## See Also @@ -23,7 +23,7 @@ public static class DiscordUserExt   # SendChatMessage method (1 of 2) -Send chat message to the user if they're connected +Send a chat message to the user if they're connected ```csharp public static void SendChatMessage(this DiscordUser user, string message) @@ -45,7 +45,7 @@ public static void SendChatMessage(this DiscordUser user, string message) # SendChatMessage method (2 of 2) -Send chat message to the user if they're connected +Send a chat message to the user if they're connected ```csharp public static void SendChatMessage(this DiscordUser user, string message, string prefix, @@ -69,7 +69,7 @@ public static void SendChatMessage(this DiscordUser user, string message, string   # HasPermission method -Return if the discord user has the given oxide permission. If the user is not linked this will return false +Return if the discord user has the given oxide permission. If the user is not linked, this will return false ```csharp public static bool HasPermission(this DiscordUser user, string permission) diff --git a/Docs/Generated/Oxide.Ext.Discord/Extensions/IEnumerableExt.md b/Docs/Generated/Oxide.Ext.Discord/Extensions/IEnumerableExt.md index d6c54358d..e7f3a2fc1 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Extensions/IEnumerableExt.md +++ b/Docs/Generated/Oxide.Ext.Discord/Extensions/IEnumerableExt.md @@ -44,7 +44,7 @@ Pooled List{TSource} | exception | condition | | --- | --- | -| ArgumentNullException | Thrown if source is null | +| ArgumentNullException | Thrown if the source is null | ## See Also @@ -81,7 +81,7 @@ Pooled Hash{TKey, TElement} | exception | condition | | --- | --- | -| ArgumentNullException | Thrown if source is null | +| ArgumentNullException | Thrown if the source is null | ## See Also @@ -118,7 +118,7 @@ Pooled Hash{TKey, TElement} | exception | condition | | --- | --- | -| ArgumentNullException | Thrown if source is null | +| ArgumentNullException | Thrown if the source is null | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Factory/DiscordClientFactory.md b/Docs/Generated/Oxide.Ext.Discord/Factory/DiscordClientFactory.md index 95e735741..4cc193834 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Factory/DiscordClientFactory.md +++ b/Docs/Generated/Oxide.Ext.Discord/Factory/DiscordClientFactory.md @@ -10,7 +10,7 @@ public sealed class DiscordClientFactory : Singleton | name | description | | --- | --- | -| [CreateClient](#createclient-method)(…) | Creates the client for the given plugin. If one already exist the existing one is returned | +| [CreateClient](#createclient-method)(…) | Creates the client for the given plugin. If one already exists, the existing one is returned | | [GetClient](#getclient-method-1-of-2)(…) | Gets the client for the given plugin (2 methods) | ## See Also @@ -23,7 +23,7 @@ public sealed class DiscordClientFactory : Singleton   # CreateClient method -Creates the client for the given plugin. If one already exist the existing one is returned +Creates the client for the given plugin. If one already exists, the existing one is returned ```csharp public DiscordClient CreateClient(Plugin plugin) @@ -61,7 +61,7 @@ public DiscordClient GetClient(Plugin plugin) | parameter | description | | --- | --- | -| plugin | Plugin to get client for | +| plugin | Plugin to get the client for | ## Return Value @@ -86,7 +86,7 @@ public DiscordClient GetClient(string pluginName) | parameter | description | | --- | --- | -| pluginName | Plugin Name to get client for | +| pluginName | Plugin Name to get the client for | ## Return Value diff --git a/Docs/Generated/Oxide.Ext.Discord/Helpers/DiscordCdn.md b/Docs/Generated/Oxide.Ext.Discord/Helpers/DiscordCdn.md index 290970f68..9af620e8a 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Helpers/DiscordCdn.md +++ b/Docs/Generated/Oxide.Ext.Discord/Helpers/DiscordCdn.md @@ -63,7 +63,7 @@ Url of the emoji | exception | condition | | --- | --- | -| ArgumentException | Thrown if format is Jpg or WebP | +| ArgumentException | Thrown if the format is Jpg or WebP | ## See Also @@ -125,7 +125,7 @@ Url of the guild splash | exception | condition | | --- | --- | -| ArgumentException | Thrown if format is Gif | +| ArgumentException | Thrown if the format is GIF | ## See Also @@ -159,7 +159,7 @@ Url of the guild discovery splash | exception | condition | | --- | --- | -| ArgumentException | Thrown if format is Gif | +| ArgumentException | Thrown if the format is GIF | ## See Also @@ -193,7 +193,7 @@ Url of the guild banner | exception | condition | | --- | --- | -| ArgumentException | Thrown if format is Gif | +| ArgumentException | Thrown if the format is GIF | ## See Also @@ -227,7 +227,7 @@ Url of the User banner | exception | condition | | --- | --- | -| ArgumentException | Thrown if format is Gif | +| ArgumentException | Thrown if the format is GIF | ## See Also @@ -278,7 +278,7 @@ public static string GetUserAvatarUrl(Snowflake userId, string userAvatar, ## Return Value -Url of the users avatar +Url of the user's avatar ## See Also @@ -323,14 +323,13 @@ Url of the Guild Member avatar Returns the Url of the User Avatar Decoration ```csharp -public static string GetUserAvatarDecoration(Snowflake userId, string decorationHash, +public static string GetUserAvatarDecoration(AvatarDecorationData data, DiscordImageFormat format = DiscordImageFormat.Auto) ``` | parameter | description | | --- | --- | -| userId | Discord User ID | -| decorationHash | Guild Member avatar | +| data | Avatar Decoration Data | | format | Format the avatar is in | ## Return Value @@ -339,7 +338,7 @@ Url of the Guild Member avatar ## See Also -* struct [Snowflake](../Entities/Snowflake.md) +* class [AvatarDecorationData](../Entities/AvatarDecorationData.md) * enum [DiscordImageFormat](../Entities/DiscordImageFormat.md) * class [DiscordCdn](./DiscordCdn.md) * namespace [Oxide.Ext.Discord.Helpers](./HelpersNamespace.md) @@ -369,7 +368,7 @@ Url of the application icon | exception | condition | | --- | --- | -| ArgumentException | Throw if format is Gif | +| ArgumentException | Throw if the format is GIF | ## See Also @@ -403,7 +402,7 @@ Url of the application icon | exception | condition | | --- | --- | -| ArgumentException | Throw if format is Gif | +| ArgumentException | Throw if the format is GIF | ## See Also @@ -437,7 +436,7 @@ Url of the application asset icon | exception | condition | | --- | --- | -| ArgumentException | Throw if format is Gif | +| ArgumentException | Throw if the format is GIF | ## See Also @@ -471,7 +470,7 @@ Url of the achievement icon | exception | condition | | --- | --- | -| ArgumentException | Throw if format is Gif | +| ArgumentException | Throw if the format is GIF | ## See Also @@ -504,7 +503,7 @@ Url of the achievement icon | exception | condition | | --- | --- | -| ArgumentException | Throw if format is Gif | +| ArgumentException | Throw if the format is GIF | ## See Also @@ -538,7 +537,7 @@ Url of the achievement icon | exception | condition | | --- | --- | -| ArgumentException | Throw if format is Gif | +| ArgumentException | Throw if the format is GIF | ## See Also @@ -572,7 +571,7 @@ Url to the sticker pack banner | exception | condition | | --- | --- | -| ArgumentException | Thrown if image type is not PNG,JPEG, or WebP | +| ArgumentException | Thrown if the image type is not PNG, JPEG, or WebP | ## See Also @@ -629,7 +628,7 @@ Return url for the role icon | exception | condition | | --- | --- | -| ArgumentException | Thrown if image type is not PNG or Lottie | +| ArgumentException | Thrown if the image type is not PNG or Lottie | ## See Also @@ -662,7 +661,7 @@ Return url for the guild schedule event cover icon | exception | condition | | --- | --- | -| ArgumentException | Thrown if image type is not PNG or Lottie | +| ArgumentException | Thrown if the image type is not PNG or Lottie | ## See Also @@ -696,7 +695,7 @@ Return url for the guild member banner | exception | condition | | --- | --- | -| ArgumentException | Thrown if image type is not PNG or Lottie | +| ArgumentException | Thrown if the image type is not PNG or Lottie | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Helpers/DiscordFormatting.md b/Docs/Generated/Oxide.Ext.Discord/Helpers/DiscordFormatting.md index 7d98f60f4..46a6b9d3a 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Helpers/DiscordFormatting.md +++ b/Docs/Generated/Oxide.Ext.Discord/Helpers/DiscordFormatting.md @@ -15,7 +15,7 @@ public static class DiscordFormatting | static [Bold](#bold-method)(…) | Will display the message in bold | | static [CodeBlockLanguage](#codeblocklanguage-method)(…) | Will display a multiline code bloc with the specified language | | static [CodeBlockMultiLine](#codeblockmultiline-method)(…) | Will display the message as a multiline code block | -| static [CodeBlockOneLine](#codeblockoneline-method)(…) | Will display the message as a one line code block | +| static [CodeBlockOneLine](#codeblockoneline-method)(…) | Will display the message as a one-line code block | | static [CustomEmojiDataString](#customemojidatastring-method)(…) | Returns formatting string for custom emoji to be used in a url | | static [CustomEmojiMessageString](#customemojimessagestring-method)(…) | Returns formatting string for custom emoji to be used in a message | | static [EmojiMessageString](#emojimessagestring-method)(…) | Return the emoji string for a message | @@ -27,10 +27,10 @@ public static class DiscordFormatting | static [ItalicsBold](#italicsbold-method)(…) | Will display the message in italics and bold | | static [List](#list-method)(…) | Creates a list item for the given message | | static [MaskLink](#masklink-method)(…) | Creates a clickable link displayed as the mask text | -| static [MentionApplicationCommand](#mentionapplicationcommand-method)(…) | Mention the the Application command | +| static [MentionApplicationCommand](#mentionapplicationcommand-method)(…) | Mention the Application command | | static [MentionApplicationCommandCustom](#mentionapplicationcommandcustom-method)(…) | Mention the application command using a custom command string | -| static [MentionChannel](#mentionchannel-method)(…) | Mention the the channel with the given ID | -| static [MentionRole](#mentionrole-method)(…) | Mention the the role with the given ID | +| static [MentionChannel](#mentionchannel-method)(…) | Mention the channel with the given ID | +| static [MentionRole](#mentionrole-method)(…) | Mention the role with the given ID | | static [MentionUser](#mentionuser-method)(…) | Mention the user with the given user ID | | static [NumberedList](#numberedlist-method)(…) | Creates a list item for the given message | | static [Spoiler](#spoiler-method)(…) | Will display the text as a spoiler | @@ -74,7 +74,7 @@ Mention user formatted string   # MentionChannel method -Mention the the channel with the given ID +Mention the channel with the given ID ```csharp public static string MentionChannel(Snowflake channelId) @@ -98,7 +98,7 @@ Mention channel formatted string   # MentionRole method -Mention the the role with the given ID +Mention the role with the given ID ```csharp public static string MentionRole(Snowflake roleId) @@ -122,7 +122,7 @@ Mention role formatted string   # MentionApplicationCommand method -Mention the the Application command +Mention the Application command ```csharp public static string MentionApplicationCommand(Snowflake commandId, string name, @@ -500,7 +500,7 @@ Strikethrough formatted message   # CodeBlockOneLine method -Will display the message as a one line code block +Will display the message as a one-line code block ```csharp public static string CodeBlockOneLine(string message) diff --git a/Docs/Generated/Oxide.Ext.Discord/Interfaces/IDiscordCacheable{T}.md b/Docs/Generated/Oxide.Ext.Discord/Interfaces/IDiscordCacheable{T}.md index 73eec387b..c8f01fd8e 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Interfaces/IDiscordCacheable{T}.md +++ b/Docs/Generated/Oxide.Ext.Discord/Interfaces/IDiscordCacheable{T}.md @@ -14,7 +14,7 @@ public interface IDiscordCacheable | name | description | | --- | --- | -| [Id](#id-property) { get; set; } | Id of the entity | +| [Id](#id-property) { get; set; } | ID of the entity | | [Update](#update-method)(…) | Method to update the entity | ## See Also @@ -45,7 +45,7 @@ public void Update(T update)   # Id property -Id of the entity +ID of the entity ```csharp public Snowflake Id { get; set; } diff --git a/Docs/Generated/Oxide.Ext.Discord/Interfaces/IPromise.md b/Docs/Generated/Oxide.Ext.Discord/Interfaces/IPromise.md index c3081ee8c..6ebe31a31 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Interfaces/IPromise.md +++ b/Docs/Generated/Oxide.Ext.Discord/Interfaces/IPromise.md @@ -11,11 +11,13 @@ public interface IPromise | name | description | | --- | --- | | [Id](#id-property) { get; } | ID of the promise, useful for debugging. | +| [AsTask](#astask-method)() | returns the task for this promise | | [Catch](#catch-method)(…) | Handle errors for the promise. | | [Catch<TException>](#catch&lt;texception&gt;-method)(…) | Catches a specified exception | | [ContinueWith](#continuewith-method)(…) | Add a callback that chains a non-value promise. ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. The state of the returning promise will be based on the new non-value promise, not the preceding (rejected or resolved) promise. | | [ContinueWith<TConvert>](#continuewith&lt;tconvert&gt;-method)(…) | Add a callback that chains a value promise (optionally converting to a different value type). ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. The state of the returning promise will be based on the new value promise, not the preceding (rejected or resolved) promise. | | [Finally](#finally-method)(…) | Add a finally callback. Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. The returned promise will be resolved or rejected, as per the preceding promise. | +| [GetAwaiter](#getawaiter-method)() | returns the task awaiter for this promise | | [Then](#then-method-1-of-5)(…) | Add a resolved callback that chains a non-value promise. (5 methods) | | [Then<TConvert>](#then&lt;tconvert&gt;-method-1-of-2)(…) | Add a resolved callback that chains a value promise (optionally converting to a different value type). (2 methods) | | [ThenAll](#thenall-method)(…) | Chain an enumerable of promises, all of which must resolve. The resulting promise is resolved when all of the promises have resolved. It is rejected as soon as any of the promises have been rejected. | @@ -269,6 +271,36 @@ public IPromise ContinueWith(Func> onComp ## See Also * interface [IPromise<TPromised>](./IPromise%7BTPromised%7D.md) +* interface [IPromise](./IPromise.md) +* namespace [Oxide.Ext.Discord.Interfaces](./InterfacesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AsTask method + +returns the task for this promise + +```csharp +public ValueTask AsTask() +``` + +## See Also + +* interface [IPromise](./IPromise.md) +* namespace [Oxide.Ext.Discord.Interfaces](./InterfacesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GetAwaiter method + +returns the task awaiter for this promise + +```csharp +public ValueTaskAwaiter GetAwaiter() +``` + +## See Also + * interface [IPromise](./IPromise.md) * namespace [Oxide.Ext.Discord.Interfaces](./InterfacesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Interfaces/IPromise{TPromised}.md b/Docs/Generated/Oxide.Ext.Discord/Interfaces/IPromise{TPromised}.md index d413bc475..2ccf7735f 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Interfaces/IPromise{TPromised}.md +++ b/Docs/Generated/Oxide.Ext.Discord/Interfaces/IPromise{TPromised}.md @@ -11,11 +11,13 @@ public interface IPromise | name | description | | --- | --- | | [Id](#id-property) { get; } | ID of the promise, useful for debugging. | +| [AsTask](#astask-method)() | returns the task for this promise | | [Catch](#catch-method-1-of-2)(…) | Handle errors for the promise. (2 methods) | | [Catch<TException>](#catch&lt;texception&gt;-method)(…) | Catches a specified exception | | [ContinueWith](#continuewith-method)(…) | Add a callback that chains a non-value promise. ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. The state of the returning promise will be based on the new non-value promise, not the preceding (rejected or resolved) promise. | | [ContinueWith<TConvert>](#continuewith&lt;tconvert&gt;-method)(…) | Add a callback that chains a value promise (optionally converting to a different value type). ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. The state of the returning promise will be based on the new value promise, not the preceding (rejected or resolved) promise. | | [Finally](#finally-method)(…) | Add a finally callback. Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. The returned promise will be resolved or rejected, as per the preceding promise. | +| [GetAwaiter](#getawaiter-method)() | returns the task awaiter for this promise | | [Then](#then-method-1-of-4)(…) | Add a resolved callback. (4 methods) | | [Then<TConvert>](#then&lt;tconvert&gt;-method-1-of-3)(…) | Add a resolved callback that chains a value promise (optionally converting to a different value type). (3 methods) | | [ThenAll](#thenall-method)(…) | Chain an enumerable of promises, all of which must resolve. Converts to a non-value promise. The resulting promise is resolved when all of the promises have resolved. It is rejected as soon as any of the promises have been rejected. | @@ -264,6 +266,36 @@ public IPromise ContinueWith(Func> onComp ## See Also +* interface [IPromise<TPromised>](./IPromise%7BTPromised%7D.md) +* namespace [Oxide.Ext.Discord.Interfaces](./InterfacesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AsTask method + +returns the task for this promise + +```csharp +public ValueTask AsTask() +``` + +## See Also + +* interface [IPromise<TPromised>](./IPromise%7BTPromised%7D.md) +* namespace [Oxide.Ext.Discord.Interfaces](./InterfacesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GetAwaiter method + +returns the task awaiter for this promise + +```csharp +public ValueTaskAwaiter GetAwaiter() +``` + +## See Also + * interface [IPromise<TPromised>](./IPromise%7BTPromised%7D.md) * namespace [Oxide.Ext.Discord.Interfaces](./InterfacesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Json/DiscordColorConverter.md b/Docs/Generated/Oxide.Ext.Discord/Json/DiscordColorConverter.md index 28a6e9ce4..99e337dce 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Json/DiscordColorConverter.md +++ b/Docs/Generated/Oxide.Ext.Discord/Json/DiscordColorConverter.md @@ -11,7 +11,7 @@ public class DiscordColorConverter : JsonConverter | name | description | | --- | --- | | [DiscordColorConverter](#discordcolorconverter-constructor)() | The default constructor. | -| override [CanConvert](#canconvert-method)(…) | Check if can convert | +| override [CanConvert](#canconvert-method)(…) | Check if it can convert | | override [ReadJson](#readjson-method)(…) | Reads from JSON | | override [WriteJson](#writejson-method)(…) | Writes to JSON | @@ -55,7 +55,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist   # CanConvert method -Check if can convert +Check if it can convert ```csharp public override bool CanConvert(Type objectType) diff --git a/Docs/Generated/Oxide.Ext.Discord/Json/DiscordEnumConverter.md b/Docs/Generated/Oxide.Ext.Discord/Json/DiscordEnumConverter.md index 864bc724b..07369d311 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Json/DiscordEnumConverter.md +++ b/Docs/Generated/Oxide.Ext.Discord/Json/DiscordEnumConverter.md @@ -1,6 +1,6 @@ # DiscordEnumConverter class -Handles deserializing JSON values as strings. If the value doesn't exist return the default value. +Handles deserializing JSON values as strings. If the value doesn't exist, return the default value. ```csharp public class DiscordEnumConverter : JsonConverter diff --git a/Docs/Generated/Oxide.Ext.Discord/Json/JsonNamespace.md b/Docs/Generated/Oxide.Ext.Discord/Json/JsonNamespace.md index 67a8c8d7e..37c145808 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Json/JsonNamespace.md +++ b/Docs/Generated/Oxide.Ext.Discord/Json/JsonNamespace.md @@ -3,18 +3,18 @@ | public type | description | | --- | --- | | class [DiscordColorConverter](./DiscordColorConverter.md) | Handles the JSON Serialization / Deserialization for DiscordColor | -| class [DiscordEnumConverter](./DiscordEnumConverter.md) | Handles deserializing JSON values as strings. If the value doesn't exist return the default value. | +| class [DiscordEnumConverter](./DiscordEnumConverter.md) | Handles deserializing JSON values as strings. If the value doesn't exist, return the default value. | | class [DiscordImageDataConverter](./DiscordImageDataConverter.md) | Represents the JsonConverter for [`DiscordImageData`](./Oxide.Ext.Discord/Entities/DiscordImageData.md) | | class [DiscordJsonReader](./DiscordJsonReader.md) | This is a pooled JSON reader that can read as string, deserialize object, or populate a given object async | | class [DiscordJsonWriter](./DiscordJsonWriter.md) | This is a pooled JSON writer that can write JSON to a stream | | class [EventPayloadConverter](./EventPayloadConverter.md) | JSON converter for [`EventPayload`](./Oxide.Ext.Discord/Entities/EventPayload.md) | | class [HashListConverter<TValue>](./HashListConverter%7BTValue%7D.md) | Converts to and from a list in JSON to a hash | -| class [MessageComponentsConverter](./MessageComponentsConverter.md) | Converter for list of message components | +| class [MessageComponentsConverter](./MessageComponentsConverter.md) | Converter for a list of message components | | class [PermissionFlagsStringConverter](./PermissionFlagsStringConverter.md) | Converts Permission Flags to and from a JSON string | | class [RoleTagsConverter](./RoleTagsConverter.md) | Handles converting [`RoleTags`](./Oxide.Ext.Discord/Entities/RoleTags.md) This type contains special deserialization types | -| class [SnowflakeConverter](./SnowflakeConverter.md) | Converts a snowflake to and from it's JSON string value | -| class [TemplateComponentsConverter](./TemplateComponentsConverter.md) | Converter for list of message components | -| class [TemplateKeyConverter](./TemplateKeyConverter.md) | Json Template Key Converter | +| class [SnowflakeConverter](./SnowflakeConverter.md) | Converts a snowflake to and from its JSON string value | +| class [TemplateComponentsConverter](./TemplateComponentsConverter.md) | Converter for a list of message components | +| class [TemplateKeyConverter](./TemplateKeyConverter.md) | JSON Template Key Converter | | class [UnixDateTimeConverter](./UnixDateTimeConverter.md) | Converts a DateTimeOffset to and from a json long | diff --git a/Docs/Generated/Oxide.Ext.Discord/Json/MessageComponentsConverter.md b/Docs/Generated/Oxide.Ext.Discord/Json/MessageComponentsConverter.md index a1f89fcdd..06d8f442d 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Json/MessageComponentsConverter.md +++ b/Docs/Generated/Oxide.Ext.Discord/Json/MessageComponentsConverter.md @@ -1,6 +1,6 @@ # MessageComponentsConverter class -Converter for list of message components +Converter for a list of message components ```csharp public class MessageComponentsConverter : JsonConverter diff --git a/Docs/Generated/Oxide.Ext.Discord/Json/SnowflakeConverter.md b/Docs/Generated/Oxide.Ext.Discord/Json/SnowflakeConverter.md index d10c30481..73bdf1fdf 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Json/SnowflakeConverter.md +++ b/Docs/Generated/Oxide.Ext.Discord/Json/SnowflakeConverter.md @@ -1,6 +1,6 @@ # SnowflakeConverter class -Converts a snowflake to and from it's JSON string value +Converts a snowflake to and from its JSON string value ```csharp public class SnowflakeConverter : JsonConverter diff --git a/Docs/Generated/Oxide.Ext.Discord/Json/TemplateComponentsConverter.md b/Docs/Generated/Oxide.Ext.Discord/Json/TemplateComponentsConverter.md index 4ad0c8afc..5dbc3054e 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Json/TemplateComponentsConverter.md +++ b/Docs/Generated/Oxide.Ext.Discord/Json/TemplateComponentsConverter.md @@ -1,6 +1,6 @@ # TemplateComponentsConverter class -Converter for list of message components +Converter for a list of message components ```csharp public class TemplateComponentsConverter : JsonConverter diff --git a/Docs/Generated/Oxide.Ext.Discord/Json/TemplateKeyConverter.md b/Docs/Generated/Oxide.Ext.Discord/Json/TemplateKeyConverter.md index cb021a46f..c6a3a8254 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Json/TemplateKeyConverter.md +++ b/Docs/Generated/Oxide.Ext.Discord/Json/TemplateKeyConverter.md @@ -1,6 +1,6 @@ # TemplateKeyConverter class -Json Template Key Converter +JSON Template Key Converter ```csharp public class TemplateKeyConverter : JsonConverter diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary.md index 056cabe81..6f507546e 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary.md @@ -11,6 +11,7 @@ public abstract class BaseDiscordLibrary : Library | name | description | | --- | --- | | [BaseDiscordLibrary](#basediscordlibrary-constructor)() | Constructor | +| virtual [OnClientBotConnect](#onclientbotconnect-method)(…) | Called on the library when a plugin is loaded | | virtual [OnPluginLoaded](#onpluginloaded-method)(…) | Called on the library when a plugin is loaded | | virtual [OnPluginUnloaded](#onpluginunloaded-method)(…) | Called on the library when a plugin is unloaded | @@ -26,18 +27,36 @@ public abstract class BaseDiscordLibrary : Library Called on the library when a plugin is loaded ```csharp -protected virtual void OnPluginLoaded(PluginSetup data, BotConnection connection) +protected virtual void OnPluginLoaded(DiscordClient client) ``` | parameter | description | | --- | --- | -| data | Plugin that was loaded | -| connection | Connection for the plugin | +| client | Client for the loaded plugin | ## See Also -* class [PluginSetup](../Plugins/PluginSetup.md) -* class [BotConnection](../Connections/BotConnection.md) +* class [DiscordClient](../Clients/DiscordClient.md) +* class [BaseDiscordLibrary](./BaseDiscordLibrary.md) +* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# OnClientBotConnect method + +Called on the library when a plugin is loaded + +```csharp +protected virtual void OnClientBotConnect(DiscordClient client) +``` + +| parameter | description | +| --- | --- | +| client | Client for the connecting bot | + +## See Also + +* class [DiscordClient](../Clients/DiscordClient.md) * class [BaseDiscordLibrary](./BaseDiscordLibrary.md) * namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordAppCommand.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordAppCommand.md index 9c9ccc5ca..c2e7f3a63 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordAppCommand.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordAppCommand.md @@ -21,7 +21,7 @@ public class DiscordAppCommand : BaseDiscordLibrary, IDebugLo | name | description | | --- | --- | -| override [OnPluginLoaded](#onpluginloaded-method)(…) | | +| override [OnClientBotConnect](#onclientbotconnect-method)(…) | | | override [OnPluginUnloaded](#onpluginunloaded-method)(…) | | ## See Also @@ -187,16 +187,15 @@ public void RemoveApplicationCommand(Plugin plugin, DiscordApplication app, Inte * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     -# OnPluginLoaded method +# OnClientBotConnect method ```csharp -protected override void OnPluginLoaded(PluginSetup data, BotConnection connection) +protected override void OnClientBotConnect(DiscordClient client) ``` ## See Also -* class [PluginSetup](../Plugins/PluginSetup.md) -* class [BotConnection](../Connections/BotConnection.md) +* class [DiscordClient](../Clients/DiscordClient.md) * class [DiscordAppCommand](./DiscordAppCommand.md) * namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordCommand.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordCommand.md index 576892512..731f73cef 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordCommand.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordCommand.md @@ -26,7 +26,7 @@ public class DiscordCommand : BaseDiscordLibrary, IDebugLoggable | name | description | | --- | --- | -| override [OnPluginLoaded](#onpluginloaded-method)(…) | | +| override [OnClientBotConnect](#onclientbotconnect-method)(…) | | | override [OnPluginUnloaded](#onpluginunloaded-method)(…) | Called when a plugin has been unloaded | ## See Also @@ -138,7 +138,7 @@ public void AddGuildLocalizedCommand(string langKey, Plugin plugin, | --- | --- | | langKey | Lang Key on the plugin that contains the command | | plugin | Plugin to add the localized command for | -| allowedChannels | Channel or Category Id's this command is allowed in | +| allowedChannels | Channel or Category ID's this command is allowed in | | callback | Method name of the callback | ## See Also @@ -162,7 +162,7 @@ public void AddGuildCommand(string command, Plugin plugin, List allow | --- | --- | | command | Name of the command | | plugin | Plugin to add the localized command for | -| allowedChannels | Channel or Category Id's this command is allowed in | +| allowedChannels | Channel or Category ID's this command is allowed in | | callback | Method name of the callback | ## See Also @@ -193,16 +193,15 @@ public void RemoveDiscordCommand(string command, Plugin plugin) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     -# OnPluginLoaded method +# OnClientBotConnect method ```csharp -protected override void OnPluginLoaded(PluginSetup data, BotConnection connection) +protected override void OnClientBotConnect(DiscordClient client) ``` ## See Also -* class [PluginSetup](../Plugins/PluginSetup.md) -* class [BotConnection](../Connections/BotConnection.md) +* class [DiscordClient](../Clients/DiscordClient.md) * class [DiscordCommand](./DiscordCommand.md) * namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordLink.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordLink.md index a5048e1ce..a6347e7cf 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordLink.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordLink.md @@ -25,7 +25,7 @@ public class DiscordLink : BaseDiscordLibrary, IDebugLoggable | [IsLinked](#islinked-method-1-of-5)(…) | Returns if the specified ID is linked (5 methods) | | [LogDebug](#logdebug-method)(…) | | | [OnLinked](#onlinked-method)(…) | Called by a link plugin when a link occured | -| [OnUnlinked](#onunlinked-method)(…) | Called by a link plugin when an unlink occured | +| [OnUnlinked](#onunlinked-method)(…) | Called by a link plugin when an unlink has occured | | [RemoveLinkPlugin](#removelinkplugin-method)(…) | Removes a link plugin from the Discord Link library | ## Protected Members @@ -228,11 +228,11 @@ public PlayerId GetPlayerId(DiscordUser user) | parameter | description | | --- | --- | -| user | [`DiscordUser`](../Entities/DiscordUser.md) to get player Id for | +| user | [`DiscordUser`](../Entities/DiscordUser.md) to get player ID for | ## Return Value -Player ID of the given given discord ID if linked; null otherwise +Player ID of the given discord ID if linked; null otherwise ## See Also @@ -258,7 +258,7 @@ public PlayerId GetPlayerId(Snowflake discordId) ## Return Value -Player ID of the given given discord ID if linked; null otherwise +Player ID of the given discord ID if linked; null otherwise ## See Also @@ -548,7 +548,7 @@ public void OnLinked(Plugin plugin, IPlayer player, DiscordUser discord)   # OnUnlinked method -Called by a link plugin when an unlink occured +Called by a link plugin when an unlink has occured ```csharp public void OnUnlinked(Plugin plugin, IPlayer player, DiscordUser discord) diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordLocale.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordLocale.md index f3c22ff22..4d33aac0f 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordLocale.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordLocale.md @@ -13,13 +13,8 @@ public struct DiscordLocale : IEquatable | static [Parse](#parse-method)(…) | Parses a Discord Locale | | [IsValid](#isvalid-property) { get; } | Is the Locale Valid | | readonly [Id](#id-field) | ID of the locale | -| [Equals](#equals-method)(…) | | -| override [Equals](#equals-method)(…) | | -| override [GetHashCode](#gethashcode-method)() | | | [GetServerLocale](#getserverlocale-method)() | Returns the Server Locale for this Discord Locale | | override [ToString](#tostring-method)() | Returns the ID of the Locale | -| [operator ==](#discordlocale-equality-operator) | Returns if two Discord Locales are equal to each other | -| [operator !=](#discordlocale-inequality-operator) | Returns if two Discord Locales are not equal to each other | ## See Also @@ -62,86 +57,6 @@ Parsed Discord Locale ## See Also -* struct [DiscordLocale](./DiscordLocale.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# Equals method (1 of 2) - -```csharp -public bool Equals(DiscordLocale other) -``` - -## See Also - -* struct [DiscordLocale](./DiscordLocale.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) - ---- - -# Equals method (2 of 2) - -```csharp -public override bool Equals(object obj) -``` - -## See Also - -* struct [DiscordLocale](./DiscordLocale.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# GetHashCode method - -```csharp -public override int GetHashCode() -``` - -## See Also - -* struct [DiscordLocale](./DiscordLocale.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# DiscordLocale Equality operator - -Returns if two Discord Locales are equal to each other - -```csharp -public static bool operator ==(DiscordLocale left, DiscordLocale right) -``` - -| parameter | description | -| --- | --- | -| left | | -| right | | - -## See Also - -* struct [DiscordLocale](./DiscordLocale.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# DiscordLocale Inequality operator - -Returns if two Discord Locales are not equal to each other - -```csharp -public static bool operator !=(DiscordLocale left, DiscordLocale right) -``` - -| parameter | description | -| --- | --- | -| left | | -| right | | - -## See Also - * struct [DiscordLocale](./DiscordLocale.md) * namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordPlaceholders.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordPlaceholders.md index 12935a9a7..e7598c005 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordPlaceholders.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordPlaceholders.md @@ -86,7 +86,7 @@ public string ProcessPlaceholders(string text, PlaceholderData data) ## Return Value -string with placeholders replaced. If no placeholders are found the original string is returned +String with placeholders replaced. If no placeholders are found, the original string is returned ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordPool.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordPool.md index a2cefedf0..995bb3e4c 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordPool.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/DiscordPool.md @@ -58,13 +58,12 @@ public DiscordPluginPool GetOrCreate(Plugin plugin) # OnPluginLoaded method ```csharp -protected override void OnPluginLoaded(PluginSetup data, BotConnection connection) +protected override void OnPluginLoaded(DiscordClient client) ``` ## See Also -* class [PluginSetup](../Plugins/PluginSetup.md) -* class [BotConnection](../Connections/BotConnection.md) +* class [DiscordClient](../Clients/DiscordClient.md) * class [DiscordPool](./DiscordPool.md) * namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderData.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderData.md index 73d33368c..d4e6d8160 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderData.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderData.md @@ -16,7 +16,7 @@ public class PlaceholderData : BasePoolable | [AddGuild](#addguild-method-1-of-2)(…) | Add a [`DiscordGuild`](../Entities/DiscordGuild.md) by [`DiscordClient`](../Clients/DiscordClient.md) and GuildId (2 methods) | | [AddGuildMember](#addguildmember-method-1-of-2)(…) | Add a [`GuildMember`](../Entities/GuildMember.md) by [`DiscordClient`](../Clients/DiscordClient.md), GuildId, and UserId (2 methods) | | [AddInteraction](#addinteraction-method)(…) | Adds a [`DiscordInteraction`](../Entities/DiscordInteraction.md) | -| [AddIp](#addip-method)(…) | Adds a IP | +| [AddIp](#addip-method)(…) | Adds an IP | | [AddMessage](#addmessage-method)(…) | Add a [`DiscordMessage`](../Entities/DiscordMessage.md) | | [AddPlayer](#addplayer-method)(…) | Adds a IPlayer | | [AddPlugin](#addplugin-method)(…) | Adds a Plugin | @@ -702,7 +702,7 @@ This   # AddIp method -Adds a IP +Adds an IP ```csharp public PlaceholderData AddIp(string ip) diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderDataKey.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderDataKey.md index bf008eb1c..8043a0f6e 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderDataKey.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderDataKey.md @@ -13,9 +13,6 @@ public struct PlaceholderDataKey : IEquatable | [PlaceholderDataKey](#placeholderdatakey-constructor)(…) | Constructor | | [IsValid](#isvalid-property) { get; } | If the [`Key`](#key-field) is a valid value | | readonly [Key](#key-field) | Value of the key | -| override [Equals](#equals-method)(…) | | -| [Equals](#equals-method)(…) | | -| override [GetHashCode](#gethashcode-method)() | | ## See Also @@ -24,46 +21,6 @@ public struct PlaceholderDataKey : IEquatable * [PlaceholderDataKey.cs](../../../../Oxide.Ext.Discord/Libraries/PlaceholderDataKey.cs)     -# Equals method (1 of 2) - -```csharp -public override bool Equals(object obj) -``` - -## See Also - -* struct [PlaceholderDataKey](./PlaceholderDataKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) - ---- - -# Equals method (2 of 2) - -```csharp -public bool Equals(PlaceholderDataKey other) -``` - -## See Also - -* struct [PlaceholderDataKey](./PlaceholderDataKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# GetHashCode method - -```csharp -public override int GetHashCode() -``` - -## See Also - -* struct [PlaceholderDataKey](./PlaceholderDataKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  # PlaceholderDataKey constructor Constructor diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderKey.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderKey.md index 927921348..1fabceb81 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderKey.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/PlaceholderKey.md @@ -14,9 +14,6 @@ public struct PlaceholderKey : IComparable, IDiscordKey, IEquata | [IsValid](#isvalid-property) { get; } | If [`Placeholder`](#placeholder-field) Is a Valid Key | | readonly [Placeholder](#placeholder-field) | Placeholder Key | | [CompareTo](#compareto-method)(…) | | -| override [Equals](#equals-method)(…) | | -| [Equals](#equals-method)(…) | | -| override [GetHashCode](#gethashcode-method)() | | | override [ToString](#tostring-method)() | Returns the PlaceholderKey formatted as a usable placeholder in text | | [WithFormat](#withformat-method)(…) | Applies a format to a given [`PlaceholderKey`](./PlaceholderKey.md) | | [implicit operator](#placeholderkey-implicit-operator) | Implicitly converts to String by calling the [`ToString`](#tostring-method) method. | @@ -62,46 +59,6 @@ public override string ToString() ## See Also -* struct [PlaceholderKey](./PlaceholderKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# Equals method (1 of 2) - -```csharp -public override bool Equals(object obj) -``` - -## See Also - -* struct [PlaceholderKey](./PlaceholderKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) - ---- - -# Equals method (2 of 2) - -```csharp -public bool Equals(PlaceholderKey other) -``` - -## See Also - -* struct [PlaceholderKey](./PlaceholderKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# GetHashCode method - -```csharp -public override int GetHashCode() -``` - -## See Also - * struct [PlaceholderKey](./PlaceholderKey.md) * namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/PlayerId.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/PlayerId.md index d5c61e2c8..1db813faf 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/PlayerId.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/PlayerId.md @@ -14,9 +14,6 @@ public struct PlayerId : IEquatable | [IsValid](#isvalid-property) { get; } | Returns true if the ID is valid; false otherwise | | [Player](#player-property) { get; } | Returns the IPlayer for the Player ID | | readonly [Id](#id-field) | ID of the player | -| override [Equals](#equals-method)(…) | | -| [Equals](#equals-method)(…) | | -| override [GetHashCode](#gethashcode-method)() | | ## See Also @@ -25,46 +22,6 @@ public struct PlayerId : IEquatable * [PlayerId.cs](../../../../Oxide.Ext.Discord/Libraries/PlayerId.cs)     -# Equals method (1 of 2) - -```csharp -public override bool Equals(object obj) -``` - -## See Also - -* struct [PlayerId](./PlayerId.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) - ---- - -# Equals method (2 of 2) - -```csharp -public bool Equals(PlayerId other) -``` - -## See Also - -* struct [PlayerId](./PlayerId.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# GetHashCode method - -```csharp -public override int GetHashCode() -``` - -## See Also - -* struct [PlayerId](./PlayerId.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  # PlayerId constructor (1 of 2) Constructor diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/ServerLocale.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/ServerLocale.md index 0ea7d24ff..f284ddb68 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/ServerLocale.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/ServerLocale.md @@ -15,13 +15,8 @@ public struct ServerLocale : IEquatable | [IsDefault](#isdefault-property) { get; } | Returns if the Locale is the default server language "en" | | [IsValid](#isvalid-property) { get; } | Returns if the Locale is valid | | readonly [Id](#id-field) | ID of the Locale | -| override [Equals](#equals-method)(…) | | -| [Equals](#equals-method)(…) | | | [GetDiscordLocale](#getdiscordlocale-method)() | Returns the [`DiscordLocale`](./DiscordLocale.md) for this server locale | -| override [GetHashCode](#gethashcode-method)() | | | override [ToString](#tostring-method)() | Returns the ID of the ServerLocale | -| [operator ==](#serverlocale-equality-operator) | Returns if two Server Locales are equal to each other | -| [operator !=](#serverlocale-inequality-operator) | Returns if two Server Locales are not equal to each other | ## See Also @@ -60,86 +55,6 @@ public static ServerLocale Parse(string locale) ## See Also -* struct [ServerLocale](./ServerLocale.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# Equals method (1 of 2) - -```csharp -public override bool Equals(object obj) -``` - -## See Also - -* struct [ServerLocale](./ServerLocale.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) - ---- - -# Equals method (2 of 2) - -```csharp -public bool Equals(ServerLocale other) -``` - -## See Also - -* struct [ServerLocale](./ServerLocale.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# GetHashCode method - -```csharp -public override int GetHashCode() -``` - -## See Also - -* struct [ServerLocale](./ServerLocale.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# ServerLocale Equality operator - -Returns if two Server Locales are equal to each other - -```csharp -public static bool operator ==(ServerLocale left, ServerLocale right) -``` - -| parameter | description | -| --- | --- | -| left | | -| right | | - -## See Also - -* struct [ServerLocale](./ServerLocale.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# ServerLocale Inequality operator - -Returns if two Server Locales are not equal to each other - -```csharp -public static bool operator !=(ServerLocale left, ServerLocale right) -``` - -| parameter | description | -| --- | --- | -| left | | -| right | | - -## See Also - * struct [ServerLocale](./ServerLocale.md) * namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/TemplateKey.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/TemplateKey.md index ada44318b..36b17e4f1 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/TemplateKey.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/TemplateKey.md @@ -13,13 +13,8 @@ public struct TemplateKey : IDiscordKey, IEquatable | [TemplateKey](#templatekey-constructor)(…) | Constructor | | [IsValid](#isvalid-property) { get; } | If [`Name`](#name-field) Is a Valid Key | | readonly [Name](#name-field) | Placeholder Key | -| override [Equals](#equals-method)(…) | | -| [Equals](#equals-method)(…) | | -| override [GetHashCode](#gethashcode-method)() | | | override [ToString](#tostring-method)() | Returns the template name | -| [operator ==](#templatekey-equality-operator) | Template Key == operator | | [implicit operator](#templatekey-implicit-operator) | Implicitly converts to String by calling the [`ToString`](#tostring-method) method. | -| [operator !=](#templatekey-inequality-operator) | Template Key != operator | ## See Also @@ -29,86 +24,6 @@ public struct TemplateKey : IDiscordKey, IEquatable * [TemplateKey.cs](../../../../Oxide.Ext.Discord/Libraries/TemplateKey.cs)     -# Equals method (1 of 2) - -```csharp -public override bool Equals(object obj) -``` - -## See Also - -* struct [TemplateKey](./TemplateKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) - ---- - -# Equals method (2 of 2) - -```csharp -public bool Equals(TemplateKey other) -``` - -## See Also - -* struct [TemplateKey](./TemplateKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# GetHashCode method - -```csharp -public override int GetHashCode() -``` - -## See Also - -* struct [TemplateKey](./TemplateKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# TemplateKey Equality operator - -Template Key == operator - -```csharp -public static bool operator ==(TemplateKey left, TemplateKey right) -``` - -| parameter | description | -| --- | --- | -| left | | -| right | | - -## See Also - -* struct [TemplateKey](./TemplateKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# TemplateKey Inequality operator - -Template Key != operator - -```csharp -public static bool operator !=(TemplateKey left, TemplateKey right) -``` - -| parameter | description | -| --- | --- | -| left | | -| right | | - -## See Also - -* struct [TemplateKey](./TemplateKey.md) -* namespace [Oxide.Ext.Discord.Libraries](./LibrariesNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  # ToString method Returns the template name diff --git a/Docs/Generated/Oxide.Ext.Discord/Libraries/TemplateVersion.md b/Docs/Generated/Oxide.Ext.Discord/Libraries/TemplateVersion.md index 56300f9d6..a9ec823b5 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Libraries/TemplateVersion.md +++ b/Docs/Generated/Oxide.Ext.Discord/Libraries/TemplateVersion.md @@ -15,14 +15,9 @@ public struct TemplateVersion : IComparable, IEquatable, IEquatable | --- | --- | | [IsValid](#isvalid-property) { get; } | Returns if the PluginId is valid | | readonly [Id](#id-field) | Hashcode value of the Plugin Name | -| override [Equals](#equals-method)(…) | | -| [Equals](#equals-method)(…) | | -| override [GetHashCode](#gethashcode-method)() | | | [LogDebug](#logdebug-method)(…) | | | override [ToString](#tostring-method)() | Returns the PluginName | -| [operator ==](#pluginid-equality-operator) | | -| [operator !=](#pluginid-inequality-operator) | | ## See Also @@ -28,82 +23,6 @@ public struct PluginId : IDebugLoggable, IEquatable * [PluginId.cs](../../../../Oxide.Ext.Discord/Plugins/PluginId.cs)     -# Equals method (1 of 2) - -```csharp -public override bool Equals(object obj) -``` - -## See Also - -* struct [PluginId](./PluginId.md) -* namespace [Oxide.Ext.Discord.Plugins](./PluginsNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) - ---- - -# Equals method (2 of 2) - -```csharp -public bool Equals(PluginId other) -``` - -## See Also - -* struct [PluginId](./PluginId.md) -* namespace [Oxide.Ext.Discord.Plugins](./PluginsNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# GetHashCode method - -```csharp -public override int GetHashCode() -``` - -## See Also - -* struct [PluginId](./PluginId.md) -* namespace [Oxide.Ext.Discord.Plugins](./PluginsNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# PluginId Equality operator - -```csharp -public static bool operator ==(PluginId left, PluginId right) -``` - -| parameter | description | -| --- | --- | -| left | | -| right | | - -## See Also - -* struct [PluginId](./PluginId.md) -* namespace [Oxide.Ext.Discord.Plugins](./PluginsNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# PluginId Inequality operator - -```csharp -public static bool operator !=(PluginId left, PluginId right) -``` - -| parameter | description | -| --- | --- | -| left | | -| right | | - -## See Also - -* struct [PluginId](./PluginId.md) -* namespace [Oxide.Ext.Discord.Plugins](./PluginsNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  # ToString method Returns the PluginName diff --git a/Docs/Generated/Oxide.Ext.Discord/Rest/Bucket.md b/Docs/Generated/Oxide.Ext.Discord/Rest/Bucket.md index 4b52f6c63..b180054d0 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Rest/Bucket.md +++ b/Docs/Generated/Oxide.Ext.Discord/Rest/Bucket.md @@ -41,7 +41,7 @@ public void Init(BucketId bucketId, RestHandler rest, ILogger logger) | parameter | description | | --- | --- | -| bucketId | ID of the bucket. If not a known bucket then will be part of the route. If know bucket will be the Discord bucket ID | +| bucketId | ID of the bucket. If not a known bucket, then it will be part of the route. If known bucket, it will be the Discord bucket ID | | rest | The handler that owns this Bucket | | logger | Logger for this bucket | diff --git a/Docs/Generated/Oxide.Ext.Discord/Rest/BucketId.md b/Docs/Generated/Oxide.Ext.Discord/Rest/BucketId.md index 4ebdcdbef..811970f78 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Rest/BucketId.md +++ b/Docs/Generated/Oxide.Ext.Discord/Rest/BucketId.md @@ -13,12 +13,7 @@ public struct BucketId : IEquatable | [BucketId](#bucketid-constructor)(…) | Constructor | | [IsValid](#isvalid-property) { get; } | If the bucket ID is valid | | readonly [Id](#id-field) | ID of the bucket | -| [Equals](#equals-method)(…) | | -| override [Equals](#equals-method)(…) | | -| override [GetHashCode](#gethashcode-method)() | | | override [ToString](#tostring-method)() | | -| [operator ==](#bucketid-equality-operator) | | -| [operator !=](#bucketid-inequality-operator) | | ## See Also @@ -27,46 +22,6 @@ public struct BucketId : IEquatable * [BucketId.cs](../../../../Oxide.Ext.Discord/Rest/BucketId.cs)     -# Equals method (1 of 2) - -```csharp -public bool Equals(BucketId other) -``` - -## See Also - -* struct [BucketId](./BucketId.md) -* namespace [Oxide.Ext.Discord.Rest](./RestNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) - ---- - -# Equals method (2 of 2) - -```csharp -public override bool Equals(object obj) -``` - -## See Also - -* struct [BucketId](./BucketId.md) -* namespace [Oxide.Ext.Discord.Rest](./RestNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# GetHashCode method - -```csharp -public override int GetHashCode() -``` - -## See Also - -* struct [BucketId](./BucketId.md) -* namespace [Oxide.Ext.Discord.Rest](./RestNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  # ToString method ```csharp @@ -75,42 +30,6 @@ public override string ToString() ## See Also -* struct [BucketId](./BucketId.md) -* namespace [Oxide.Ext.Discord.Rest](./RestNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# BucketId Equality operator - -```csharp -public static bool operator ==(BucketId left, BucketId right) -``` - -| parameter | description | -| --- | --- | -| left | | -| right | | - -## See Also - -* struct [BucketId](./BucketId.md) -* namespace [Oxide.Ext.Discord.Rest](./RestNamespace.md) -* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) -  -  -# BucketId Inequality operator - -```csharp -public static bool operator !=(BucketId left, BucketId right) -``` - -| parameter | description | -| --- | --- | -| left | | -| right | | - -## See Also - * struct [BucketId](./BucketId.md) * namespace [Oxide.Ext.Discord.Rest](./RestNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Rest/RequestCompletedStatus.md b/Docs/Generated/Oxide.Ext.Discord/Rest/RequestCompletedStatus.md index ec56e3192..b72e3f814 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Rest/RequestCompletedStatus.md +++ b/Docs/Generated/Oxide.Ext.Discord/Rest/RequestCompletedStatus.md @@ -13,7 +13,7 @@ public enum RequestCompletedStatus : byte | Success | `Success` | The request completed successfully | | ErrorFatal | `ErrorFatal` | The request encountered a fatal error | | ErrorRetry | `ErrorRetry` | The error attempt multiple times to complete the request and was unsuccessful | -| Cancelled | `Cancelled` | The request was cancelled. The [`DiscordClient`](../Clients/DiscordClient.md) was disconnected while making the request | +| Cancelled | `Cancelled` | The request was canceled. The [`DiscordClient`](../Clients/DiscordClient.md) was disconnected while making the request | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Rest/RequestStatus.md b/Docs/Generated/Oxide.Ext.Discord/Rest/RequestStatus.md index 6343be29e..6d9389792 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Rest/RequestStatus.md +++ b/Docs/Generated/Oxide.Ext.Discord/Rest/RequestStatus.md @@ -15,8 +15,8 @@ public enum RequestStatus : byte | PendingBucket | `PendingBucket` | Requesting is waiting for bucket to be ready | | PendingStart | `PendingStart` | Request is waiting to start | | InProgress | `InProgress` | Request is in progress | -| Completed | `Completed` | Request completed and was not cancelled | -| Cancelled | `Cancelled` | Request was cancelled | +| Completed | `Completed` | Request completed and was not canceled | +| Cancelled | `Cancelled` | Request was canceled | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Rest/RestHandler.md b/Docs/Generated/Oxide.Ext.Discord/Rest/RestHandler.md index 30ea1038c..fa89dd4d6 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Rest/RestHandler.md +++ b/Docs/Generated/Oxide.Ext.Discord/Rest/RestHandler.md @@ -10,22 +10,22 @@ public class RestHandler : IDebugLoggable | name | description | | --- | --- | -| [RestHandler](#resthandler-constructor)(…) | Creates a new REST handler for a bot client | +| [RestHandler](#resthandler-constructor-1-of-2)(…) | Creates a new REST handler for bot / webhook clients (2 constructors) | | readonly [Buckets](#buckets-field) | Buckets with Routes we don't know the Hash of yet | | readonly [Client](#client-field) | HttpClient for API Requests | | readonly [RateLimit](#ratelimit-field) | Global Rate Limit for the bot | | readonly [RouteToBucketId](#routetobucketid-field) | Route to Bucket ID | | [Delete](#delete-method)(…) | Performs a HTTP Delete Request | -| [Delete<TResult>](#delete&lt;tresult&gt;-method)(…) | Performs a HTTP Delete Request with TResult response | -| [Get<TResult>](#get&lt;tresult&gt;-method)(…) | Performs a HTTP Get Request with TResult response | +| [Delete<TResult>](#delete&lt;tresult&gt;-method)(…) | Performs an HTTP Delete Request with TResult response | +| [Get<TResult>](#get&lt;tresult&gt;-method)(…) | Performs ann HTTP Get Request with TResult response | | [GetBucket](#getbucket-method)(…) | Returns the bucket with the given ID | | [LogDebug](#logdebug-method)(…) | | -| [Patch](#patch-method)(…) | Performs a HTTP Patch Request | -| [Patch<TResult>](#patch&lt;tresult&gt;-method)(…) | Performs a HTTP Patch Request with TResult response | +| [Patch](#patch-method)(…) | Performs an HTTP Patch Request | +| [Patch<TResult>](#patch&lt;tresult&gt;-method)(…) | Performs an HTTP Patch Request with TResult response | | [Post](#post-method)(…) | Performs a HTTP Post Request | -| [Post<TResult>](#post&lt;tresult&gt;-method)(…) | Performs a HTTP Post Request with TResult response | -| [Put](#put-method)(…) | Performs a HTTP Put Request | -| [Put<TResult>](#put&lt;tresult&gt;-method)(…) | Performs a HTTP Put Request with TResult response | +| [Post<TResult>](#post&lt;tresult&gt;-method)(…) | Performs an HTTP Post Request with TResult response | +| [Put](#put-method)(…) | Performs an HTTP Put Request | +| [Put<TResult>](#put&lt;tresult&gt;-method)(…) | Performs an HTTP Put Request with TResult response | | [QueueBucket](#queuebucket-method)(…) | Queues the request for the bucket | | [Shutdown](#shutdown-method)() | Shutdown the REST handler | | [StartRequest](#startrequest-method)(…) | Starts the request | @@ -40,7 +40,7 @@ public class RestHandler : IDebugLoggable   # Get<TResult> method -Performs a HTTP Get Request with TResult response +Performs ann HTTP Get Request with TResult response ```csharp public IPromise Get(DiscordClient client, string url, @@ -93,7 +93,7 @@ public IPromise Post(DiscordClient client, string url, object data, # Post<TResult> method (2 of 2) -Performs a HTTP Post Request with TResult response +Performs an HTTP Post Request with TResult response ```csharp public IPromise Post(DiscordClient client, string url, object data, @@ -120,7 +120,7 @@ public IPromise Post(DiscordClient client, string url, object   # Put method (1 of 2) -Performs a HTTP Put Request +Performs an HTTP Put Request ```csharp public IPromise Put(DiscordClient client, string url, object data, @@ -147,7 +147,7 @@ public IPromise Put(DiscordClient client, string url, object data, # Put<TResult> method (2 of 2) -Performs a HTTP Put Request with TResult response +Performs an HTTP Put Request with TResult response ```csharp public IPromise Put(DiscordClient client, string url, object data, @@ -174,7 +174,7 @@ public IPromise Put(DiscordClient client, string url, object d   # Patch method (1 of 2) -Performs a HTTP Patch Request +Performs an HTTP Patch Request ```csharp public IPromise Patch(DiscordClient client, string url, object data, @@ -201,7 +201,7 @@ public IPromise Patch(DiscordClient client, string url, object data, # Patch<TResult> method (2 of 2) -Performs a HTTP Patch Request with TResult response +Performs an HTTP Patch Request with TResult response ```csharp public IPromise Patch(DiscordClient client, string url, object data, @@ -253,7 +253,7 @@ public IPromise Delete(DiscordClient client, string url, RequestOptions? options # Delete<TResult> method (2 of 2) -Performs a HTTP Delete Request with TResult response +Performs an HTTP Delete Request with TResult response ```csharp public IPromise Delete(DiscordClient client, string url, @@ -364,7 +364,28 @@ public void LogDebug(DebugLogger logger) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md)     -# RestHandler constructor +# RestHandler constructor (1 of 2) + +Creates a new REST handler for bot / webhook clients + +```csharp +public RestHandler(ILogger logger) +``` + +| parameter | description | +| --- | --- | +| logger | | + +## See Also + +* interface [ILogger](../Interfaces/ILogger.md) +* class [RestHandler](./RestHandler.md) +* namespace [Oxide.Ext.Discord.Rest](./RestNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# RestHandler constructor (2 of 2) Creates a new REST handler for a bot client diff --git a/Docs/Generated/Oxide.Ext.Discord/Types/BasePool{TPooled,TPool}.md b/Docs/Generated/Oxide.Ext.Discord/Types/BasePool{TPooled,TPool}.md index ff288d038..0d5d8e3f1 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Types/BasePool{TPooled,TPool}.md +++ b/Docs/Generated/Oxide.Ext.Discord/Types/BasePool{TPooled,TPool}.md @@ -31,7 +31,7 @@ public abstract class BasePool : IPool | --- | --- | | [BasePool](#basepool&lt;tpooled,tpool&gt;-constructor)() | The default constructor. | | [PluginPool](#pluginpool-field) | Plugin Pool for this pool | -| abstract [CreateNew](#createnew-method)() | Creates new type of T | +| abstract [CreateNew](#createnew-method)() | Creates a new type of T | | abstract [GetPoolSize](#getpoolsize-method)(…) | Returns the pool size from the pool settings for the pool | | virtual [OnFreeItem](#onfreeitem-method)(…) | Returns if an item can be freed to the pool | | virtual [OnGetItem](#ongetitem-method)(…) | Called when an item is retrieved from the pool | @@ -102,7 +102,7 @@ public TPooled Get()   # CreateNew method -Creates new type of T +Creates a new type of T ```csharp protected abstract TPooled CreateNew() @@ -215,7 +215,7 @@ protected virtual bool OnFreeItem(ref TPooled item) ## Return Value -True if can be freed; false otherwise +True if the item can be freed; false otherwise ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Types/BasePromise.md b/Docs/Generated/Oxide.Ext.Discord/Types/BasePromise.md index d7a5738fb..f4f6fc2c9 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Types/BasePromise.md +++ b/Docs/Generated/Oxide.Ext.Discord/Types/BasePromise.md @@ -12,7 +12,7 @@ public class BasePromise : BasePoolable, IRejectable | --- | --- | | [Id](#id-property) { get; } | ID of the promise | | [State](#state-property) { get; protected set; } | Tracks the current state of the promise. | -| [Reject](#reject-method)(…) | | +| virtual [Reject](#reject-method)(…) | | ## Protected Members @@ -38,7 +38,7 @@ public class BasePromise : BasePoolable, IRejectable # Reject method ```csharp -public void Reject(Exception ex) +public virtual void Reject(Exception ex) ``` ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/Types/IPool{T}.md b/Docs/Generated/Oxide.Ext.Discord/Types/IPool{T}.md index fd745653d..37d505a69 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Types/IPool{T}.md +++ b/Docs/Generated/Oxide.Ext.Discord/Types/IPool{T}.md @@ -14,7 +14,7 @@ public interface IPool : IPool | name | description | | --- | --- | -| [Free](#free-method)(…) | Returns the pooled type back to the pool | +| [Free](#free-method)(…) | Returns the pooled type to the pool | | [Get](#get-method)() | Returns the Pooled type or a new instance if pool is empty. | ## See Also @@ -42,7 +42,7 @@ public T Get()   # Free method -Returns the pooled type back to the pool +Returns the pooled type to the pool ```csharp public void Free(T poolable) diff --git a/Docs/Generated/Oxide.Ext.Discord/Types/Promise.md b/Docs/Generated/Oxide.Ext.Discord/Types/Promise.md index ec817ac25..ab8f965a8 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Types/Promise.md +++ b/Docs/Generated/Oxide.Ext.Discord/Types/Promise.md @@ -1,6 +1,6 @@ # Promise class -Implements a non-generic C# promise, this is a promise that simply resolves without delivering a value. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise +Implements a non-generic C# promise; this is a promise that simply resolves without delivering a value. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise ```csharp public sealed class Promise : BasePromise, IPendingPromise @@ -12,11 +12,14 @@ public sealed class Promise : BasePromise, IPendingPromise | --- | --- | | [Promise](#promise-constructor)() | Constructor for the promise | | static [Create](#create-method)() | Creates a Promise | +| [AsTask](#astask-method)() | | | [Catch](#catch-method)(…) | | | [Catch<TException>](#catch&lt;texception&gt;-method)(…) | | | [ContinueWith](#continuewith-method)(…) | | | [ContinueWith<TConvert>](#continuewith&lt;tconvert&gt;-method)(…) | | | [Finally](#finally-method)(…) | | +| [GetAwaiter](#getawaiter-method)() | | +| override [Reject](#reject-method)(…) | | | [Resolve](#resolve-method)() | | | [Then](#then-method-1-of-5)(…) | (5 methods) | | [Then<TConvert>](#then&lt;tconvert&gt;-method-1-of-2)(…) | (2 methods) | @@ -32,7 +35,7 @@ public sealed class Promise : BasePromise, IPendingPromise | name | description | | --- | --- | -| override [ClearHandlers](#clearhandlers-method)() | Helper function clear out all handlers after resolution or rejection. | +| override [ClearHandlers](#clearhandlers-method)() | Helper function to clear out all handlers after resolution or rejection. | | override [EnterPool](#enterpool-method)() | | ## See Also @@ -93,7 +96,7 @@ public static IPromise Rejected(Exception ex)   # ClearHandlers method -Helper function clear out all handlers after resolution or rejection. +Helper function to clear out all handlers after resolution or rejection. ```csharp protected override void ClearHandlers() @@ -114,6 +117,19 @@ public void Resolve() ## See Also +* class [Promise](./Promise.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Reject method + +```csharp +public override void Reject(Exception ex) +``` + +## See Also + * class [Promise](./Promise.md) * namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) @@ -402,6 +418,32 @@ public IPromise ContinueWith(Func> onComp ## See Also * interface [IPromise<TPromised>](../Interfaces/IPromise%7BTPromised%7D.md) +* class [Promise](./Promise.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AsTask method + +```csharp +public ValueTask AsTask() +``` + +## See Also + +* class [Promise](./Promise.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GetAwaiter method + +```csharp +public ValueTaskAwaiter GetAwaiter() +``` + +## See Also + * class [Promise](./Promise.md) * namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Types/Promise{TPromised}.md b/Docs/Generated/Oxide.Ext.Discord/Types/Promise{TPromised}.md index 62607a572..b3699373b 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Types/Promise{TPromised}.md +++ b/Docs/Generated/Oxide.Ext.Discord/Types/Promise{TPromised}.md @@ -12,17 +12,20 @@ public sealed class Promise : BasePromise, IPendingPromise | --- | --- | | [Promise](#promise&lt;tpromised&gt;-constructor)() | Constructor | | static [Create](#create-method)() | Returns a promise that is currently pending | +| [AsTask](#astask-method)() | | | [Catch](#catch-method-1-of-2)(…) | (2 methods) | | [Catch<TException>](#catch&lt;texception&gt;-method)(…) | | | [ContinueWith](#continuewith-method)(…) | | | [ContinueWith<TConvert>](#continuewith&lt;tconvert&gt;-method)(…) | | | [Finally](#finally-method)(…) | | +| [GetAwaiter](#getawaiter-method)() | | +| override [Reject](#reject-method)(…) | | | [Resolve](#resolve-method)(…) | | | [Then](#then-method-1-of-4)(…) | (4 methods) | | [Then<TConvert>](#then&lt;tconvert&gt;-method-1-of-3)(…) | (3 methods) | | [ThenAll](#thenall-method)(…) | | | [ThenAll<TConvert>](#thenall&lt;tconvert&gt;-method)(…) | | -| static [All](#all-method-1-of-2)(…) | Returns a promise that resolves when all of the promises in the enumerable argument have resolved. Returns a promise of a collection of the resolved results. (2 methods) | +| static [All](#all-method-1-of-2)(…) | Returns a promise that resolves when all the promises in the enumerable argument have resolved. Returns a promise of a collection of the resolved results. (2 methods) | | static [Create](#create-method)(…) | | | static [Create<TConvert>](#create&lt;tconvert&gt;-method)() | Returns a promise that is currently pending | | static [Rejected](#rejected-method)(…) | Convert an exception directly into a rejected promise. | @@ -134,6 +137,19 @@ public void Resolve(TPromised value) ## See Also +* class [Promise<TPromised>](./Promise%7BTPromised%7D.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Reject method + +```csharp +public override void Reject(Exception ex) +``` + +## See Also + * class [Promise<TPromised>](./Promise%7BTPromised%7D.md) * namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) @@ -339,7 +355,7 @@ public static IPromise> All( # All method (2 of 2) -Returns a promise that resolves when all of the promises in the enumerable argument have resolved. Returns a promise of a collection of the resolved results. +Returns a promise that resolves when all the promises in the enumerable argument have resolved. Returns a promise of a collection of the resolved results. ```csharp public static IPromise> All(params IPromise[] promises) @@ -391,6 +407,32 @@ public IPromise ContinueWith(Func> onComp ## See Also * interface [IPromise<TPromised>](../Interfaces/IPromise%7BTPromised%7D.md) +* class [Promise<TPromised>](./Promise%7BTPromised%7D.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AsTask method + +```csharp +public ValueTask AsTask() +``` + +## See Also + +* class [Promise<TPromised>](./Promise%7BTPromised%7D.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GetAwaiter method + +```csharp +public ValueTaskAwaiter GetAwaiter() +``` + +## See Also + * class [Promise<TPromised>](./Promise%7BTPromised%7D.md) * namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) * assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) diff --git a/Docs/Generated/Oxide.Ext.Discord/Types/TypesNamespace.md b/Docs/Generated/Oxide.Ext.Discord/Types/TypesNamespace.md index 79e01990b..e2b01364a 100644 --- a/Docs/Generated/Oxide.Ext.Discord/Types/TypesNamespace.md +++ b/Docs/Generated/Oxide.Ext.Discord/Types/TypesNamespace.md @@ -12,13 +12,14 @@ | interface [IPool<T>](./IPool%7BT%7D.md) | Represents a pool of type T | | class [PoolSettings](./PoolSettings.md) | Settings for the pools | | struct [PoolSize](./PoolSize.md) | Represents size constraints for a pool | -| class [Promise](./Promise.md) | Implements a non-generic C# promise, this is a promise that simply resolves without delivering a value. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise | +| class [Promise](./Promise.md) | Implements a non-generic C# promise; this is a promise that simply resolves without delivering a value. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise | | class [Promise<TPromised>](./Promise%7BTPromised%7D.md) | Implements a C# promise. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise | | enum [PromiseState](./PromiseState.md) | Specifies the state of a promise. | | struct [RejectHandler](./RejectHandler.md) | Represents a handler invoked when the promise is rejected. | | class [RestRateLimit](./RestRateLimit.md) | Represents a rate limit for rest requests | | abstract class [Singleton<T>](./Singleton%7BT%7D.md) | Represents a singleton of type {T} | | class [UkkonenTrie<T>](./UkkonenTrie%7BT%7D.md) | A Ukkonen Suffix Trie | +| struct [ValueStringBuilder](./ValueStringBuilder.md) | | | class [WebsocketRateLimit](./WebsocketRateLimit.md) | Represents a WebSocket Rate Limit | diff --git a/Docs/Generated/Oxide.Ext.Discord/Types/ValueStringBuilder.md b/Docs/Generated/Oxide.Ext.Discord/Types/ValueStringBuilder.md new file mode 100644 index 000000000..32db19a6b --- /dev/null +++ b/Docs/Generated/Oxide.Ext.Discord/Types/ValueStringBuilder.md @@ -0,0 +1,500 @@ +# ValueStringBuilder structure + +```csharp +[Obsolete("Types with embedded references are not supported in this version of your compiler.")] +public struct ValueStringBuilder +``` + +## Public Members + +| name | description | +| --- | --- | +| [ValueStringBuilder](#valuestringbuilder-constructor-1-of-2)(…) | (2 constructors) | +| [Capacity](#capacity-property) { get; } | | +| [Item](#valuestringbuilder-indexer) { get; } | | +| [Length](#length-property) { get; set; } | | +| [RawChars](#rawchars-property) { get; } | Returns the underlying storage of the builder. | +| [Append](#append-method-1-of-12)(…) | (12 methods) | +| [AppendLine](#appendline-method)() | | +| [AppendLine](#appendline-method)(…) | | +| [AppendSpan](#appendspan-method)(…) | | +| [AsSpan](#asspan-method)() | | +| [AsSpan](#asspan-method-1-of-3)(…) | Returns a span around the contents of the builder. (3 methods) | +| [Dispose](#dispose-method)() | | +| [EnsureCapacity](#ensurecapacity-method)(…) | | +| [GetPinnableReference](#getpinnablereference-method)() | Get a pinnable reference to the builder. Does not ensure there is a null char after [`Length`](#length-property) This overload is pattern matched in the C# 7.3+ compiler so you can omit the explicit method call, and write eg "fixed (char* c = builder)" | +| [GetPinnableReference](#getpinnablereference-method)(…) | Get a pinnable reference to the builder. | +| [Insert](#insert-method-1-of-2)(…) | (2 methods) | +| override [ToString](#tostring-method)() | | +| [TryCopyTo](#trycopyto-method)(…) | | + +## See Also + +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +* [ValueStringBuilder.cs](../../../../Oxide.Ext.Discord/Types/ValueStringBuilder.cs) +  +  +# EnsureCapacity method + +```csharp +public void EnsureCapacity(int capacity) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# GetPinnableReference method (1 of 2) + +Get a pinnable reference to the builder. Does not ensure there is a null char after [`Length`](#length-property) This overload is pattern matched in the C# 7.3+ compiler so you can omit the explicit method call, and write eg "fixed (char* c = builder)" + +```csharp +public char GetPinnableReference() +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# GetPinnableReference method (2 of 2) + +Get a pinnable reference to the builder. + +```csharp +public char GetPinnableReference(bool terminate) +``` + +| parameter | description | +| --- | --- | +| terminate | Ensures that the builder has a null char after [`Length`](#length-property) | + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# ToString method + +```csharp +public override string ToString() +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AsSpan method (1 of 4) + +```csharp +public ReadOnlySpan AsSpan() +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# AsSpan method (2 of 4) + +Returns a span around the contents of the builder. + +```csharp +public ReadOnlySpan AsSpan(bool terminate) +``` + +| parameter | description | +| --- | --- | +| terminate | Ensures that the builder has a null char after [`Length`](#length-property) | + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# AsSpan method (3 of 4) + +```csharp +public ReadOnlySpan AsSpan(int start) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# AsSpan method (4 of 4) + +```csharp +public ReadOnlySpan AsSpan(int start, int length) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# TryCopyTo method + +```csharp +public bool TryCopyTo(Span destination, out int charsWritten) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Insert method (1 of 2) + +```csharp +public void Insert(int index, string s) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Insert method (2 of 2) + +```csharp +public void Insert(int index, char value, int count) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Append method (1 of 12) + +```csharp +public void Append(char c) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (2 of 12) + +```csharp +public void Append(ReadOnlySpan value) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (3 of 12) + +```csharp +public void Append(string s) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (4 of 12) + +```csharp +public void Append(char c, int count) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (5 of 12) + +```csharp +public void Append(byte value, string format = null, IFormatProvider provider = null) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (6 of 12) + +```csharp +public void Append(int value, string format = null, IFormatProvider provider = null) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (7 of 12) + +```csharp +public void Append(long value, string format = null, IFormatProvider provider = null) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (8 of 12) + +```csharp +public void Append(sbyte value, string format = null, IFormatProvider provider = null) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (9 of 12) + +```csharp +public void Append(short value, string format = null, IFormatProvider provider = null) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (10 of 12) + +```csharp +public void Append(uint value, string format = null, IFormatProvider provider = null) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (11 of 12) + +```csharp +public void Append(ulong value, string format = null, IFormatProvider provider = null) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# Append method (12 of 12) + +```csharp +public void Append(ushort value, string format = null, IFormatProvider provider = null) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AppendSpan method + +```csharp +public Span AppendSpan(int length) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# AppendLine method (1 of 2) + +```csharp +public void AppendLine() +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# AppendLine method (2 of 2) + +```csharp +public void AppendLine(string s) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Dispose method + +```csharp +public void Dispose() +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# ValueStringBuilder constructor (1 of 2) + +```csharp +public ValueStringBuilder(int initialCapacity) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + +--- + +# ValueStringBuilder constructor (2 of 2) + +```csharp +public ValueStringBuilder(Span initialBuffer) +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Length property + +```csharp +public int Length { get; set; } +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# Capacity property + +```csharp +public int Capacity { get; } +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# ValueStringBuilder indexer + +```csharp +public char this[int index] { get; } +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) +  +  +# RawChars property + +Returns the underlying storage of the builder. + +```csharp +public Span RawChars { get; } +``` + +## See Also + +* struct [ValueStringBuilder](./ValueStringBuilder.md) +* namespace [Oxide.Ext.Discord.Types](./TypesNamespace.md) +* assembly [Oxide.Ext.Discord](../../Oxide.Ext.Discord.md) + + diff --git a/Docs/Generated/Oxide.Ext.Discord/WebSockets/DiscordDispatchCode.md b/Docs/Generated/Oxide.Ext.Discord/WebSockets/DiscordDispatchCode.md index 24f6707d0..372c0c700 100644 --- a/Docs/Generated/Oxide.Ext.Discord/WebSockets/DiscordDispatchCode.md +++ b/Docs/Generated/Oxide.Ext.Discord/WebSockets/DiscordDispatchCode.md @@ -75,6 +75,8 @@ public enum DiscordDispatchCode : byte | AutoModerationRuleUpdate | `AutoModerationRuleUpdate` | Represents the [AUTO_MODERATION_RULE_UPDATE](https://discord.com/developers/docs/topics/gateway#auto-moderation-rule-update) gateway event | | AutoModerationRuleDelete | `AutoModerationRuleDelete` | Represents the [AUTO_MODERATION_RULE_DELETE](https://discord.com/developers/docs/topics/gateway#auto-moderation-rule-delete) gateway event | | AutoModerationActionExecution | `AutoModerationActionExecution` | Represents the [AUTO_MODERATION_ACTION_EXECUTION](https://discord.com/developers/docs/topics/gateway#auto-moderation-action-execution) gateway event | +| MessagePollVoteAdded | `MessagePollVoteAdded` | Represents the [MESSAGE_POLL_VOTE_ADD](https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-add) gateway event | +| MessagePollVoteRemoved | `MessagePollVoteRemoved` | Represents the [MESSAGE_POLL_VOTE_REMOVE](https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-remove) gateway event | ## See Also diff --git a/Docs/Generated/Oxide.Ext.Discord/WebSockets/DiscordWebsocketCloseCode.md b/Docs/Generated/Oxide.Ext.Discord/WebSockets/DiscordWebsocketCloseCode.md index ea3d7a3fd..3c25305bf 100644 --- a/Docs/Generated/Oxide.Ext.Discord/WebSockets/DiscordWebsocketCloseCode.md +++ b/Docs/Generated/Oxide.Ext.Discord/WebSockets/DiscordWebsocketCloseCode.md @@ -20,10 +20,10 @@ public enum DiscordWebsocketCloseCode | RateLimited | `RateLimited` | Woah nelly! You're sending payloads to us too quickly. Slow it down! You will be disconnected on receiving this. | | SessionTimedOut | `SessionTimedOut` | Your session timed out. Reconnect and start a new one. | | InvalidShard | `InvalidShard` | You sent us an invalid shard when identifying. | -| ShardingRequired | `ShardingRequired` | The session would have handled too many guilds - you are required to shard your connection in order to connect. | +| ShardingRequired | `ShardingRequired` | The session would have handled too many guilds - you are required to shard your connection to connect. | | InvalidApiVersion | `InvalidApiVersion` | You sent an invalid version for the gateway. | | InvalidIntents | `InvalidIntents` | You sent an invalid intent for a Gateway Intent. You may have incorrectly calculated the bitwise value. | -| DisallowedIntent | `DisallowedIntent` | You sent a disallowed intent for a Gateway Intent. You may have tried to specify an intent that you have not enabled or are not whitelisted for. | +| DisallowedIntent | `DisallowedIntent` | You sent a disallowed intent for a Gateway Intent. You may have tried to specify an intent that you have not enabled or are not allowlisted for. | | DiscordExtensionReconnect | `DiscordExtensionReconnect` | Used to identify a reconnect should occur to discord | | UnknownCloseCode | `UnknownCloseCode` | Used when a code is sent that we don't have yet. | diff --git a/Docs/Generated/Oxide.Ext.Discord/WebSockets/SocketState.md b/Docs/Generated/Oxide.Ext.Discord/WebSockets/SocketState.md index bf866e5ab..294522d58 100644 --- a/Docs/Generated/Oxide.Ext.Discord/WebSockets/SocketState.md +++ b/Docs/Generated/Oxide.Ext.Discord/WebSockets/SocketState.md @@ -10,8 +10,8 @@ public enum SocketState : byte | name | value | description | | --- | --- | --- | -| Connecting | `Connecting` | Socket is in the process of connecting | -| Connected | `Connected` | Socket is connect and functioning normally | +| Connecting | `Connecting` | Websocket is in the process of connecting | +| Connected | `Connected` | Websocket is connected and functioning normally | | Disconnecting | `Disconnecting` | Websocket is currently disconnecting from a connected web socket | | Disconnected | `Disconnected` | Websocket is currently disconnect and not waiting to connect | diff --git a/Docs/Generated/Oxide.Ext.Discord/WebSockets/WebSocketEventHandler.md b/Docs/Generated/Oxide.Ext.Discord/WebSockets/WebSocketEventHandler.md index 2b1fdf4af..837dd5b49 100644 --- a/Docs/Generated/Oxide.Ext.Discord/WebSockets/WebSocketEventHandler.md +++ b/Docs/Generated/Oxide.Ext.Discord/WebSockets/WebSocketEventHandler.md @@ -94,7 +94,7 @@ public ValueTask SocketMessage(Snowflake webSocketId, DiscordJsonReader reader) | parameter | description | | --- | --- | | webSocketId | ID of the web socket | -| reader | Json Reader containing the message | +| reader | JSON Reader containing the message | ## See Also diff --git a/Oxide.Ext.Discord/Attributes/ApplicationCommands/BaseApplicationCommandAttribute.cs b/Oxide.Ext.Discord/Attributes/ApplicationCommands/BaseApplicationCommandAttribute.cs index daf6328dd..ddbd3fd5e 100644 --- a/Oxide.Ext.Discord/Attributes/ApplicationCommands/BaseApplicationCommandAttribute.cs +++ b/Oxide.Ext.Discord/Attributes/ApplicationCommands/BaseApplicationCommandAttribute.cs @@ -1,7 +1,6 @@ -namespace Oxide.Ext.Discord.Attributes -{ - /// - /// Base attribute for Application Commands - /// - public abstract class BaseApplicationCommandAttribute : BaseDiscordAttribute { } -} \ No newline at end of file +namespace Oxide.Ext.Discord.Attributes; + +/// +/// Base attribute for Application Commands +/// +public abstract class BaseApplicationCommandAttribute : BaseDiscordAttribute { } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordApplicationCommandAttribute.cs b/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordApplicationCommandAttribute.cs index 8394863fa..c7cfb8735 100644 --- a/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordApplicationCommandAttribute.cs +++ b/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordApplicationCommandAttribute.cs @@ -1,37 +1,36 @@ using System; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Attributes +namespace Oxide.Ext.Discord.Attributes; + +/// +/// Discord Application Command Attribute for +/// Callback Hook Format: +/// +/// [DiscordApplicationCommandAttribute("Command", "Sub Command", "Group")] +/// private void ApplicationCommandMethod(DiscordInteraction interaction, InteractionDataParsed parsed) +/// { +/// Puts("ApplicationCommandMethod Works!"); +/// } +/// +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public class DiscordApplicationCommandAttribute : BaseApplicationCommandAttribute { + internal readonly string Command; + internal readonly string Group; + internal readonly string SubCommand; + /// - /// Discord Application Command Attribute for - /// Callback Hook Format: - /// - /// [DiscordApplicationCommandAttribute("Command", "Sub Command", "Group")] - /// private void ApplicationCommandMethod(DiscordInteraction interaction, InteractionDataParsed parsed) - /// { - /// Puts("ApplicationCommandMethod Works!"); - /// } - /// + /// Constructor /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - public class DiscordApplicationCommandAttribute : BaseApplicationCommandAttribute + /// Command for the Application Command + /// Sub Command for the Application Command + /// Sub Command Group for the Application Command + public DiscordApplicationCommandAttribute(string command, string subCommand = null, string group = null) { - internal readonly string Command; - internal readonly string Group; - internal readonly string SubCommand; - - /// - /// Constructor - /// - /// Command for the Application Command - /// Sub Command for the Application Command - /// Sub Command Group for the Application Command - public DiscordApplicationCommandAttribute(string command, string subCommand = null, string group = null) - { - Command = command; - Group = group; - SubCommand = subCommand; - } + Command = command; + Group = group; + SubCommand = subCommand; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordAutoCompleteCommandAttribute.cs b/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordAutoCompleteCommandAttribute.cs index efa7a56aa..abd035454 100644 --- a/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordAutoCompleteCommandAttribute.cs +++ b/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordAutoCompleteCommandAttribute.cs @@ -1,34 +1,33 @@ using System; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Attributes +namespace Oxide.Ext.Discord.Attributes; + +/// +/// Discord Auto Complete Command Attribute for +/// Callback Hook Format: +/// +/// [DiscordAutoCompleteCommandAttribute("ArgumentName")] +/// private void AutoCompleteCommand(DiscordInteraction interaction, InteractionDataOption focused) +/// { +/// Puts("AutoCompleteCommand Works!"); +/// } +/// +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public sealed class DiscordAutoCompleteCommandAttribute : DiscordApplicationCommandAttribute { + internal readonly string ArgumentName; + /// - /// Discord Auto Complete Command Attribute for - /// Callback Hook Format: - /// - /// [DiscordAutoCompleteCommandAttribute("ArgumentName")] - /// private void AutoCompleteCommand(DiscordInteraction interaction, InteractionDataOption focused) - /// { - /// Puts("AutoCompleteCommand Works!"); - /// } - /// + /// Constructor /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - public sealed class DiscordAutoCompleteCommandAttribute : DiscordApplicationCommandAttribute + /// Command for the Auto Complete + /// Argument Name for the Auto Complete + /// Sub Command for the Auto Complete + /// Sub Command Group for the Auto Complete + public DiscordAutoCompleteCommandAttribute(string command, string argumentName, string subCommand = null, string group = null) : base(command, subCommand, group) { - internal readonly string ArgumentName; - - /// - /// Constructor - /// - /// Command for the Auto Complete - /// Argument Name for the Auto Complete - /// Sub Command for the Auto Complete - /// Sub Command Group for the Auto Complete - public DiscordAutoCompleteCommandAttribute(string command, string argumentName, string subCommand = null, string group = null) : base(command, subCommand, group) - { - ArgumentName = argumentName; - } + ArgumentName = argumentName; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordMessageComponentCommandAttribute.cs b/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordMessageComponentCommandAttribute.cs index 02a0e8108..99b5781a0 100644 --- a/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordMessageComponentCommandAttribute.cs +++ b/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordMessageComponentCommandAttribute.cs @@ -1,31 +1,30 @@ using System; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Attributes +namespace Oxide.Ext.Discord.Attributes; + +/// +/// Discord Message Component Command Attribute for +/// Callback Hook Format: +/// +/// [DiscordMessageComponentCommandAttribute("CustomId")] +/// private void MessageComponentCommand(DiscordInteraction interaction) +/// { +/// Puts("MessageComponentCommand Works!"); +/// } +/// +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public sealed class DiscordMessageComponentCommandAttribute : BaseApplicationCommandAttribute { + internal readonly string CustomId; + /// - /// Discord Message Component Command Attribute for - /// Callback Hook Format: - /// - /// [DiscordMessageComponentCommandAttribute("CustomId")] - /// private void MessageComponentCommand(DiscordInteraction interaction) - /// { - /// Puts("MessageComponentCommand Works!"); - /// } - /// + /// Constructor /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - public sealed class DiscordMessageComponentCommandAttribute : BaseApplicationCommandAttribute + /// CustomID to match on. Matching uses string.StartsWith + public DiscordMessageComponentCommandAttribute(string customId) { - internal readonly string CustomId; - - /// - /// Constructor - /// - /// CustomID to match on. Matching uses string.StartsWith - public DiscordMessageComponentCommandAttribute(string customId) - { - CustomId = customId; - } + CustomId = customId; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordModalSubmitAttribute.cs b/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordModalSubmitAttribute.cs index 2061c9ed3..ac17c68b3 100644 --- a/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordModalSubmitAttribute.cs +++ b/Oxide.Ext.Discord/Attributes/ApplicationCommands/DiscordModalSubmitAttribute.cs @@ -1,31 +1,30 @@ using System; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Attributes +namespace Oxide.Ext.Discord.Attributes; + +/// +/// Discord Message Component Command Attribute for +/// Callback Hook Format: +/// +/// [DiscordModalSubmitAttribute("CustomId")] +/// private void ModalSubmitCommand(DiscordInteraction interaction) +/// { +/// Puts("ModalSubmitCommand Works!"); +/// } +/// +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public sealed class DiscordModalSubmitAttribute : BaseApplicationCommandAttribute { + internal readonly string CustomId; + /// - /// Discord Message Component Command Attribute for - /// Callback Hook Format: - /// - /// [DiscordModalSubmitAttribute("CustomId")] - /// private void ModalSubmitCommand(DiscordInteraction interaction) - /// { - /// Puts("ModalSubmitCommand Works!"); - /// } - /// + /// Constructor /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - public sealed class DiscordModalSubmitAttribute : BaseApplicationCommandAttribute + /// CustomID to match on. Matching uses string.StartsWith + public DiscordModalSubmitAttribute(string customId) { - internal readonly string CustomId; - - /// - /// Constructor - /// - /// CustomID to match on. Matching uses string.StartsWith - public DiscordModalSubmitAttribute(string customId) - { - CustomId = customId; - } + CustomId = customId; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Attributes/BaseCommandAttribute.cs b/Oxide.Ext.Discord/Attributes/BaseCommandAttribute.cs index f3cde1d4c..3ab6db52a 100644 --- a/Oxide.Ext.Discord/Attributes/BaseCommandAttribute.cs +++ b/Oxide.Ext.Discord/Attributes/BaseCommandAttribute.cs @@ -1,32 +1,31 @@ using System; -namespace Oxide.Ext.Discord.Attributes +namespace Oxide.Ext.Discord.Attributes; + +/// +/// Represents a base attribute for commands +/// +[AttributeUsage(AttributeTargets.Method)] +public abstract class BaseCommandAttribute : BaseDiscordAttribute { /// - /// Represents a base attribute for commands + /// Name of the command /// - [AttributeUsage(AttributeTargets.Method)] - public abstract class BaseCommandAttribute : BaseDiscordAttribute - { - /// - /// Name of the command - /// - public string Name { get; } + public string Name { get; } - /// - /// If the command name is the localization key - /// - public bool IsLocalized { get; } + /// + /// If the command name is the localization key + /// + public bool IsLocalized { get; } - /// - /// Constructor for a base command - /// - /// Name of the command - /// If the command name is the localization key for the command - protected BaseCommandAttribute(string name, bool isLocalized = false) - { - Name = name; - IsLocalized = isLocalized; - } + /// + /// Constructor for a base command + /// + /// Name of the command + /// If the command name is the localization key for the command + protected BaseCommandAttribute(string name, bool isLocalized = false) + { + Name = name; + IsLocalized = isLocalized; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Attributes/BaseDiscordAttribute.cs b/Oxide.Ext.Discord/Attributes/BaseDiscordAttribute.cs index 092abfb8a..ad5733410 100644 --- a/Oxide.Ext.Discord/Attributes/BaseDiscordAttribute.cs +++ b/Oxide.Ext.Discord/Attributes/BaseDiscordAttribute.cs @@ -1,9 +1,8 @@ using System; -namespace Oxide.Ext.Discord.Attributes -{ - /// - /// Base Attribute for all Discord Extension Attributes - /// - public abstract class BaseDiscordAttribute : Attribute { } -} \ No newline at end of file +namespace Oxide.Ext.Discord.Attributes; + +/// +/// Base Attribute for all Discord Extension Attributes +/// +public abstract class BaseDiscordAttribute : Attribute { } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Attributes/DirectMessageCommandAttribute.cs b/Oxide.Ext.Discord/Attributes/DirectMessageCommandAttribute.cs index 25ba6bcf6..da66fc24b 100644 --- a/Oxide.Ext.Discord/Attributes/DirectMessageCommandAttribute.cs +++ b/Oxide.Ext.Discord/Attributes/DirectMessageCommandAttribute.cs @@ -1,22 +1,21 @@ using System; -namespace Oxide.Ext.Discord.Attributes +namespace Oxide.Ext.Discord.Attributes; + +/// +/// Used to identify direct message bot commands +/// +[AttributeUsage(AttributeTargets.Method)] +[Obsolete("Direct Message Command is deprecated and will be removed in a future update. Please upgrade to application commands")] +public class DirectMessageCommandAttribute : BaseCommandAttribute { /// - /// Used to identify direct message bot commands + /// Creates a discord command to be used in direct messages to the bot /// - [AttributeUsage(AttributeTargets.Method)] - [Obsolete("Direct Message Command is deprecated and will be removed in a future update. Please upgrade to application commands")] - public class DirectMessageCommandAttribute : BaseCommandAttribute + /// Name of the command + /// If the command name is the localization key for the command + public DirectMessageCommandAttribute(string name, bool isLocalized = false) : base(name, isLocalized) { - /// - /// Creates a discord command to be used in direct messages to the bot - /// - /// Name of the command - /// If the command name is the localization key for the command - public DirectMessageCommandAttribute(string name, bool isLocalized = false) : base(name, isLocalized) - { - } } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Attributes/DiscordEnumAttribute.cs b/Oxide.Ext.Discord/Attributes/DiscordEnumAttribute.cs index 05dd6d070..0cf99194b 100644 --- a/Oxide.Ext.Discord/Attributes/DiscordEnumAttribute.cs +++ b/Oxide.Ext.Discord/Attributes/DiscordEnumAttribute.cs @@ -1,15 +1,14 @@ using System; -namespace Oxide.Ext.Discord.Attributes +namespace Oxide.Ext.Discord.Attributes; + +[AttributeUsage(AttributeTargets.Field)] +internal class DiscordEnumAttribute : Attribute { - [AttributeUsage(AttributeTargets.Field)] - internal class DiscordEnumAttribute : Attribute - { - public readonly string Name; + public readonly string Name; - public DiscordEnumAttribute(string name) - { - Name = name; - } + public DiscordEnumAttribute(string name) + { + Name = name; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Attributes/GuildCommandAttribute.cs b/Oxide.Ext.Discord/Attributes/GuildCommandAttribute.cs index 785f6220e..5210dc4ba 100644 --- a/Oxide.Ext.Discord/Attributes/GuildCommandAttribute.cs +++ b/Oxide.Ext.Discord/Attributes/GuildCommandAttribute.cs @@ -1,22 +1,21 @@ using System; -namespace Oxide.Ext.Discord.Attributes +namespace Oxide.Ext.Discord.Attributes; + +/// +/// Used to identify guild bot commands +/// +[AttributeUsage(AttributeTargets.Method)] +[Obsolete("Guild Command is deprecated and will be removed in a future update. Please upgrade to application commands")] +public class GuildCommandAttribute : BaseCommandAttribute { /// - /// Used to identify guild bot commands + /// Creates a discord command to be used in guild /// - [AttributeUsage(AttributeTargets.Method)] - [Obsolete("Guild Command is deprecated and will be removed in a future update. Please upgrade to application commands")] - public class GuildCommandAttribute : BaseCommandAttribute + /// Name of the command + /// If the command name is the localization key for the command + public GuildCommandAttribute(string name, bool isLocalized = false) : base(name, isLocalized) { - /// - /// Creates a discord command to be used in guild - /// - /// Name of the command - /// If the command name is the localization key for the command - public GuildCommandAttribute(string name, bool isLocalized = false) : base(name, isLocalized) - { - } } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Ansi/AnsiBuilder.cs b/Oxide.Ext.Discord/Builders/Ansi/AnsiBuilder.cs index 1b70f89ce..e8bcfad0f 100644 --- a/Oxide.Ext.Discord/Builders/Ansi/AnsiBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Ansi/AnsiBuilder.cs @@ -2,114 +2,113 @@ using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Builders.Ansi +namespace Oxide.Ext.Discord.Builders.Ansi; + +/// +/// Builder for ANSI colored text +/// +public class AnsiBuilder { + private readonly StringBuilder _sb; + /// - /// Builder for ANSI colored text + /// Constructor /// - public class AnsiBuilder + public AnsiBuilder() { - private readonly StringBuilder _sb; + _sb = DiscordPool.Internal.GetStringBuilder(); + _sb.AppendLine("```ansi"); + } - /// - /// Constructor - /// - public AnsiBuilder() - { - _sb = DiscordPool.Internal.GetStringBuilder(); - _sb.AppendLine("```ansi"); - } + /// + /// Appends text with the given color, background, and font style + /// + /// Text to add + /// Color of the text + /// Background color of the text + /// Font style of the text + public void Append(string text, TextColor color = TextColor.Default, BackgroundColor background = BackgroundColor.Default, FontStyle style = FontStyle.Default) + { + _sb.Append("\u001b["); + ProcessStyles(style); - /// - /// Appends text with the given color, background, and font style - /// - /// Text to add - /// Color of the text - /// Background color of the text - /// Font style of the text - public void Append(string text, TextColor color = TextColor.Default, BackgroundColor background = BackgroundColor.Default, FontStyle style = FontStyle.Default) + if (background != BackgroundColor.Default) { - _sb.Append("\u001b["); - ProcessStyles(style); - - if (background != BackgroundColor.Default) - { - _sb.Append(EnumCache.Instance.ToString(background)); - if (color != TextColor.Default) - { - _sb.Append(';'); - } - } - + _sb.Append(EnumCache.Instance.ToString(background)); if (color != TextColor.Default) { - _sb.Append(EnumCache.Instance.ToString(color)); + _sb.Append(';'); } - - _sb.Append('m'); - _sb.Append(text); - Reset(); } - /// - /// Appends text with a line terminator with the given color, background, and font style - /// - /// Text to add - /// Color of the text - /// Background color of the text - /// Font style of the text - public void AppendLine(string text, TextColor color = TextColor.Default, BackgroundColor background = BackgroundColor.Default, FontStyle style = FontStyle.Default) + if (color != TextColor.Default) { - Append(text, color, background, style); - _sb.AppendLine(); + _sb.Append(EnumCache.Instance.ToString(color)); } - /// - /// Appends a line - /// - public void AppendLine() - { - _sb.AppendLine(); - } + _sb.Append('m'); + _sb.Append(text); + Reset(); + } + + /// + /// Appends text with a line terminator with the given color, background, and font style + /// + /// Text to add + /// Color of the text + /// Background color of the text + /// Font style of the text + public void AppendLine(string text, TextColor color = TextColor.Default, BackgroundColor background = BackgroundColor.Default, FontStyle style = FontStyle.Default) + { + Append(text, color, background, style); + _sb.AppendLine(); + } + + /// + /// Appends a line + /// + public void AppendLine() + { + _sb.AppendLine(); + } - private void ProcessStyles(FontStyle style) + private void ProcessStyles(FontStyle style) + { + if (style == FontStyle.Default) { - if (style == FontStyle.Default) - { - _sb.Append("0;"); - return; - } - - if (HasFlag(style, FontStyle.Bold)) - { - _sb.Append("1;"); - } - - if (HasFlag(style, FontStyle.Underline)) - { - _sb.Append("4;"); - } + _sb.Append("0;"); + return; } - - private void Reset() + + if (HasFlag(style, FontStyle.Bold)) { - _sb.Append("\u001b[0;0m"); + _sb.Append("1;"); } - - private bool HasFlag(FontStyle style, FontStyle flag) + + if (HasFlag(style, FontStyle.Underline)) { - return (style & flag) == flag; + _sb.Append("4;"); } + } - /// - /// Returns the build Ansi Text - /// - /// - public string Build() - { - _sb.AppendLine(); - _sb.Append("```"); - return DiscordPool.Internal.ToStringAndFree(_sb); - } + private void Reset() + { + _sb.Append("\u001b[0;0m"); + } + + private bool HasFlag(FontStyle style, FontStyle flag) + { + return (style & flag) == flag; + } + + /// + /// Returns the build Ansi Text + /// + /// + public string Build() + { + _sb.AppendLine(); + _sb.Append("```"); + return DiscordPool.Internal.ToStringAndFree(_sb); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Ansi/BackgroundColor.cs b/Oxide.Ext.Discord/Builders/Ansi/BackgroundColor.cs index 1868d248b..4c6354895 100644 --- a/Oxide.Ext.Discord/Builders/Ansi/BackgroundColor.cs +++ b/Oxide.Ext.Discord/Builders/Ansi/BackgroundColor.cs @@ -1,53 +1,52 @@ -namespace Oxide.Ext.Discord.Builders.Ansi +namespace Oxide.Ext.Discord.Builders.Ansi; + +/// +/// Ansi Background colors +/// +public enum BackgroundColor : byte { /// - /// Ansi Background colors - /// - public enum BackgroundColor : byte - { - /// - /// Default - /// - Default = 0, - - /// - /// Dark Blue - /// - DarkBlue = 40, - - /// - /// Orange - /// - Orange = 41, - - /// - /// Marble Blue - /// - MarbleBlue = 42, - - /// - /// Grey Turquoise - /// - GreyTurquoise = 43, - - /// - /// Gray - /// - Gray = 44, - - /// - /// Indigo - /// - Indigo = 45, - - /// - /// Light Gray - /// - LightGray = 46, - - /// - /// White - /// - White = 47 - } + /// Default + /// + Default = 0, + + /// + /// Dark Blue + /// + DarkBlue = 40, + + /// + /// Orange + /// + Orange = 41, + + /// + /// Marble Blue + /// + MarbleBlue = 42, + + /// + /// Grey Turquoise + /// + GreyTurquoise = 43, + + /// + /// Gray + /// + Gray = 44, + + /// + /// Indigo + /// + Indigo = 45, + + /// + /// Light Gray + /// + LightGray = 46, + + /// + /// White + /// + White = 47 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Ansi/FontStyle.cs b/Oxide.Ext.Discord/Builders/Ansi/FontStyle.cs index 0518981d3..09e329668 100644 --- a/Oxide.Ext.Discord/Builders/Ansi/FontStyle.cs +++ b/Oxide.Ext.Discord/Builders/Ansi/FontStyle.cs @@ -1,26 +1,25 @@ using System; -namespace Oxide.Ext.Discord.Builders.Ansi +namespace Oxide.Ext.Discord.Builders.Ansi; + +/// +/// Font Styles for ANSI text +/// +[Flags] +public enum FontStyle : byte { /// - /// Font Styles for ANSI text + /// Default /// - [Flags] - public enum FontStyle : byte - { - /// - /// Default - /// - Default = 0, + Default = 0, - /// - /// Bold - /// - Bold = 1 << 1, + /// + /// Bold + /// + Bold = 1 << 1, - /// - /// Underline - /// - Underline = 1 << 2 - } + /// + /// Underline + /// + Underline = 1 << 2 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Ansi/TextColor.cs b/Oxide.Ext.Discord/Builders/Ansi/TextColor.cs index d8ab4cb71..3e742d34b 100644 --- a/Oxide.Ext.Discord/Builders/Ansi/TextColor.cs +++ b/Oxide.Ext.Discord/Builders/Ansi/TextColor.cs @@ -1,53 +1,52 @@ -namespace Oxide.Ext.Discord.Builders.Ansi +namespace Oxide.Ext.Discord.Builders.Ansi; + +/// +/// Text Colors for Ansi Text +/// +public enum TextColor : byte { /// - /// Text Colors for Ansi Text - /// - public enum TextColor : byte - { - /// - /// Default - /// - Default = 0, - - /// - /// Gray - /// - Gray = 30, - - /// - /// Red - /// - Red = 31, - - /// - /// Green - /// - Green = 32, - - /// - /// Yellow - /// - Yellow = 33, - - /// - /// Blue - /// - Blue = 34, - - /// - /// Pink - /// - Pink = 35, - - /// - /// Cyan - /// - Cyan = 36, - - /// - /// White - /// - White = 37 - } + /// Default + /// + Default = 0, + + /// + /// Gray + /// + Gray = 30, + + /// + /// Red + /// + Red = 31, + + /// + /// Green + /// + Green = 32, + + /// + /// Yellow + /// + Yellow = 33, + + /// + /// Blue + /// + Blue = 34, + + /// + /// Pink + /// + Pink = 35, + + /// + /// Cyan + /// + Cyan = 36, + + /// + /// White + /// + White = 37 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandBuilder.cs b/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandBuilder.cs index 844c86afa..cc428011a 100644 --- a/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandBuilder.cs +++ b/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandBuilder.cs @@ -6,218 +6,217 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Builder to use when building application commands +/// +public class ApplicationCommandBuilder { + internal readonly CommandCreate Command; + private CommandOptionType? _chosenType; + private readonly ServerLocale _defaultLanguage; + /// - /// Builder to use when building application commands + /// The Name of the command /// - public class ApplicationCommandBuilder - { - internal readonly CommandCreate Command; - private CommandOptionType? _chosenType; - private readonly ServerLocale _defaultLanguage; - - /// - /// The Name of the command - /// - public readonly string CommandName; - - /// - /// Creates a new Application Command Builder - /// - /// Name of the command - /// Description of the command - /// Command type - public ApplicationCommandBuilder(string name, string description, ApplicationCommandType type): this(name, description, type, ServerLocale.Default) {} + public readonly string CommandName; + + /// + /// Creates a new Application Command Builder + /// + /// Name of the command + /// Description of the command + /// Command type + public ApplicationCommandBuilder(string name, string description, ApplicationCommandType type): this(name, description, type, ServerLocale.Default) {} - /// - /// Creates a new Application Command Builder - /// - /// Name of the command - /// Description of the command - /// Command type - /// Language the application command is being created in - public ApplicationCommandBuilder(string name, string description, ApplicationCommandType type, ServerLocale defaultLanguage) - { - if (!defaultLanguage.IsValid) ServerLocaleNotFoundException.ThrowNotFound(defaultLanguage); - InvalidApplicationCommandException.ThrowIfInvalidName(name, false); - InvalidApplicationCommandException.ThrowIfInvalidDescription(description, type); + /// + /// Creates a new Application Command Builder + /// + /// Name of the command + /// Description of the command + /// Command type + /// Language the application command is being created in + public ApplicationCommandBuilder(string name, string description, ApplicationCommandType type, ServerLocale defaultLanguage) + { + if (!defaultLanguage.IsValid) ServerLocaleNotFoundException.ThrowNotFound(defaultLanguage); + InvalidApplicationCommandException.ThrowIfInvalidName(name, false); + InvalidApplicationCommandException.ThrowIfInvalidDescription(description, type); - Command = new CommandCreate(name, description, type, new List()); - _defaultLanguage = defaultLanguage; + Command = new CommandCreate(name, description, type, new List()); + _defaultLanguage = defaultLanguage; - AddNameLocalization(Command.Name, _defaultLanguage); - AddDescriptionLocalization(Command.Description, _defaultLanguage); - CommandName = name; - } + AddNameLocalization(Command.Name, _defaultLanguage); + AddDescriptionLocalization(Command.Description, _defaultLanguage); + CommandName = name; + } - /// - /// Adds default command permissions - /// - /// Default Permissions for the command - /// - public ApplicationCommandBuilder AddDefaultPermissions(PermissionFlags permissions) - { - Command.DefaultMemberPermissions = permissions; - return this; - } + /// + /// Adds default command permissions + /// + /// Default Permissions for the command + /// + public ApplicationCommandBuilder AddDefaultPermissions(PermissionFlags permissions) + { + Command.DefaultMemberPermissions = permissions; + return this; + } - /// - /// Allows the command to be used in a direct message - /// - /// Allows a command to be used in a direct message - /// - public ApplicationCommandBuilder AllowInDirectMessages(bool allow) - { - Command.DmPermission = allow; - return this; - } + /// + /// Allows the command to be used in a direct message + /// + /// Allows a command to be used in a direct message + /// + public ApplicationCommandBuilder AllowInDirectMessages(bool allow) + { + Command.DmPermission = allow; + return this; + } + + /// + /// Adds command name localizations for a given plugin and lang key + /// + /// Plugin containing the localizations + /// Lang Key containing the localized text + /// + [Obsolete("AddNameLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddNameLocalization(string name, string lang) instead")] + public ApplicationCommandBuilder AddNameLocalizations(Plugin plugin, string langKey) + { + Command.NameLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); + return this; + } - /// - /// Adds command name localizations for a given plugin and lang key - /// - /// Plugin containing the localizations - /// Lang Key containing the localized text - /// - [Obsolete("AddNameLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddNameLocalization(string name, string lang) instead")] - public ApplicationCommandBuilder AddNameLocalizations(Plugin plugin, string langKey) + /// + /// Adds Application Command Name Localizations + /// + /// Localized name value + /// Oxide lang the value is in + /// This + public ApplicationCommandBuilder AddNameLocalization(string name, ServerLocale serverLocale) + { + if (Command.NameLocalizations == null) { - Command.NameLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); - return this; + Command.NameLocalizations = new Hash(); } - /// - /// Adds Application Command Name Localizations - /// - /// Localized name value - /// Oxide lang the value is in - /// This - public ApplicationCommandBuilder AddNameLocalization(string name, ServerLocale serverLocale) + DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); + if (discordLocale.IsValid) { - if (Command.NameLocalizations == null) - { - Command.NameLocalizations = new Hash(); - } - - DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); - if (discordLocale.IsValid) - { - Command.NameLocalizations[discordLocale.Id] = name; - } - - return this; + Command.NameLocalizations[discordLocale.Id] = name; } + + return this; + } - /// - /// Adds command description localizations for a given plugin and lang key - /// - /// Plugin containing the localizations - /// Lang Key containing the localized text - /// - [Obsolete("AddDescriptionLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddDescriptionLocalization(string name, string lang) instead")] - public ApplicationCommandBuilder AddDescriptionLocalizations(Plugin plugin, string langKey) - { - Command.DescriptionLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); - return this; - } + /// + /// Adds command description localizations for a given plugin and lang key + /// + /// Plugin containing the localizations + /// Lang Key containing the localized text + /// + [Obsolete("AddDescriptionLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddDescriptionLocalization(string name, string lang) instead")] + public ApplicationCommandBuilder AddDescriptionLocalizations(Plugin plugin, string langKey) + { + Command.DescriptionLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); + return this; + } - /// - /// Adds Application Command Description Localizations - /// - /// Localized description value - /// Oxide lang the value is in - /// This - public ApplicationCommandBuilder AddDescriptionLocalization(string description, ServerLocale serverLocale) + /// + /// Adds Application Command Description Localizations + /// + /// Localized description value + /// Oxide lang the value is in + /// This + public ApplicationCommandBuilder AddDescriptionLocalization(string description, ServerLocale serverLocale) + { + if (Command.DescriptionLocalizations == null) { - if (Command.DescriptionLocalizations == null) - { - Command.DescriptionLocalizations = new Hash(); - } - - DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); - if (discordLocale.IsValid) - { - Command.DescriptionLocalizations[discordLocale.Id] = description; - } - - return this; + Command.DescriptionLocalizations = new Hash(); } - /// - /// Creates a new SubCommandGroup - /// SubCommandGroups contain subcommands - /// Your root command can only contain - /// - /// Name of the command - /// Description of the command - /// Callback with the - /// this - /// Thrown if trying to add a subcommand group to - public ApplicationCommandBuilder AddSubCommandGroup(string name, string description, Action builder) + DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); + if (discordLocale.IsValid) { - InvalidCommandOptionException.ThrowIfInvalidName(name, false); - InvalidCommandOptionException.ThrowIfInvalidDescription(description, false); + Command.DescriptionLocalizations[discordLocale.Id] = description; + } - ApplicationCommandBuilderException.ThrowIfMixingSubCommandGroups(_chosenType); - ApplicationCommandBuilderException.ThrowIfAddingSubCommandToMessageOrUser(this); + return this; + } - _chosenType = CommandOptionType.SubCommandGroup; - ApplicationCommandGroupBuilder group = new ApplicationCommandGroupBuilder(Command.Options, name, description, _defaultLanguage, CommandName); - builder?.Invoke(group); + /// + /// Creates a new SubCommandGroup + /// SubCommandGroups contain subcommands + /// Your root command can only contain + /// + /// Name of the command + /// Description of the command + /// Callback with the + /// this + /// Thrown if trying to add a subcommand group to + public ApplicationCommandBuilder AddSubCommandGroup(string name, string description, Action builder) + { + InvalidCommandOptionException.ThrowIfInvalidName(name, false); + InvalidCommandOptionException.ThrowIfInvalidDescription(description, false); - return this; - } + ApplicationCommandBuilderException.ThrowIfMixingSubCommandGroups(_chosenType); + ApplicationCommandBuilderException.ThrowIfAddingSubCommandToMessageOrUser(this); - /// - /// Adds a sub command to the root command - /// - /// Name of the sub command - /// Description for the sub command - /// Callback with the "/> - /// this - /// Thrown if previous type was not SubCommand or Creation type is not ChatInput - public ApplicationCommandBuilder AddSubCommand(string name, string description, Action builder = null) - { - InvalidCommandOptionException.ThrowIfInvalidName(name, false); - InvalidCommandOptionException.ThrowIfInvalidDescription(description, false); + _chosenType = CommandOptionType.SubCommandGroup; + ApplicationCommandGroupBuilder group = new(Command.Options, name, description, _defaultLanguage, CommandName); + builder?.Invoke(group); + + return this; + } - ApplicationCommandBuilderException.ThrowIfMixingSubCommandGroups(_chosenType); - ApplicationCommandBuilderException.ThrowIfAddingSubCommandToMessageOrUser(this); + /// + /// Adds a sub command to the root command + /// + /// Name of the sub command + /// Description for the sub command + /// Callback with the "/> + /// this + /// Thrown if previous type was not SubCommand or Creation type is not ChatInput + public ApplicationCommandBuilder AddSubCommand(string name, string description, Action builder = null) + { + InvalidCommandOptionException.ThrowIfInvalidName(name, false); + InvalidCommandOptionException.ThrowIfInvalidDescription(description, false); - _chosenType = CommandOptionType.SubCommand; + ApplicationCommandBuilderException.ThrowIfMixingSubCommandGroups(_chosenType); + ApplicationCommandBuilderException.ThrowIfAddingSubCommandToMessageOrUser(this); - ApplicationSubCommandBuilder sub = new ApplicationSubCommandBuilder(Command.Options, name, description, _defaultLanguage, CommandName, null); - builder?.Invoke(sub); - - return this; - } + _chosenType = CommandOptionType.SubCommand; - /// - /// Adds a command option. - /// - /// The type of option. Cannot be SubCommand or SubCommandGroup - /// Name of the option - /// Description for the option - /// Callback with the - /// this - public ApplicationCommandBuilder AddOption(CommandOptionType type, string name, string description, Action builder = null) - { - ApplicationCommandBuilderException.ThrowIfMixingCommandOptions(_chosenType); - ApplicationCommandOptionBuilder option = new ApplicationCommandOptionBuilder(Command.Options, type, name, description, _defaultLanguage, CommandName, null, null); - builder?.Invoke(option); - return this; - } + ApplicationSubCommandBuilder sub = new(Command.Options, name, description, _defaultLanguage, CommandName, null); + builder?.Invoke(sub); + + return this; + } - /// - /// Returns the created command - /// - /// - public CommandCreate Build() => Command; - - /// - /// Returns a built using the provided name / descriptions as the default - /// - /// - public DiscordCommandLocalization BuildCommandLocalization(string lang = DiscordLocales.DefaultServerLanguage) => new DiscordCommandLocalization(Command, ServerLocale.Parse(lang)); + /// + /// Adds a command option. + /// + /// The type of option. Cannot be SubCommand or SubCommandGroup + /// Name of the option + /// Description for the option + /// Callback with the + /// this + public ApplicationCommandBuilder AddOption(CommandOptionType type, string name, string description, Action builder = null) + { + ApplicationCommandBuilderException.ThrowIfMixingCommandOptions(_chosenType); + ApplicationCommandOptionBuilder option = new(Command.Options, type, name, description, _defaultLanguage, CommandName, null, null); + builder?.Invoke(option); + return this; } + + /// + /// Returns the created command + /// + /// + public CommandCreate Build() => Command; + + /// + /// Returns a built using the provided name / descriptions as the default + /// + /// + public DiscordCommandLocalization BuildCommandLocalization(string lang = DiscordLocales.DefaultServerLanguage) => new(Command, ServerLocale.Parse(lang)); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandGroupBuilder.cs b/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandGroupBuilder.cs index 872d82edc..89eff44b9 100644 --- a/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandGroupBuilder.cs +++ b/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandGroupBuilder.cs @@ -4,109 +4,108 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Builder for Sub Command Groups +/// +public class ApplicationCommandGroupBuilder { + private readonly CommandOption _option; + private readonly ServerLocale _defaultLanguage; + /// - /// Builder for Sub Command Groups + /// The Name of the command /// - public class ApplicationCommandGroupBuilder - { - private readonly CommandOption _option; - private readonly ServerLocale _defaultLanguage; + public readonly string CommandName; - /// - /// The Name of the command - /// - public readonly string CommandName; - - /// - /// The Name of the group - /// - public readonly string GroupName; + /// + /// The Name of the group + /// + public readonly string GroupName; - internal ApplicationCommandGroupBuilder(List options, string name, string description, ServerLocale defaultLanguage, string commandName) - { - _defaultLanguage = defaultLanguage; - _option = new CommandOption(name, description, CommandOptionType.SubCommandGroup, new List()); - options.Add(_option); - AddNameLocalization(name, _defaultLanguage); - AddDescriptionLocalization(description, _defaultLanguage); - CommandName = commandName; - GroupName = name; - } + internal ApplicationCommandGroupBuilder(List options, string name, string description, ServerLocale defaultLanguage, string commandName) + { + _defaultLanguage = defaultLanguage; + _option = new CommandOption(name, description, CommandOptionType.SubCommandGroup, new List()); + options.Add(_option); + AddNameLocalization(name, _defaultLanguage); + AddDescriptionLocalization(description, _defaultLanguage); + CommandName = commandName; + GroupName = name; + } - /// - /// Adds command name localizations for a given plugin and lang key - /// - /// Plugin containing the localizations - /// Lang Key containing the localized text - /// - [Obsolete("AddNameLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddNameLocalization(string name, string lang) instead.")] - public ApplicationCommandGroupBuilder AddNameLocalizations(Plugin plugin, string langKey) + /// + /// Adds command name localizations for a given plugin and lang key + /// + /// Plugin containing the localizations + /// Lang Key containing the localized text + /// + [Obsolete("AddNameLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddNameLocalization(string name, string lang) instead.")] + public ApplicationCommandGroupBuilder AddNameLocalizations(Plugin plugin, string langKey) + { + _option.NameLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); + return this; + } + + /// + /// Adds Application Sub Command Group Name Localizations + /// + /// Localized name value + /// Oxide lang the value is in + /// This + public ApplicationCommandGroupBuilder AddNameLocalization(string name, ServerLocale serverLocale) + { + DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); + if (discordLocale.IsValid) { - _option.NameLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); - return this; + _option.NameLocalizations[discordLocale.Id] = name; } - /// - /// Adds Application Sub Command Group Name Localizations - /// - /// Localized name value - /// Oxide lang the value is in - /// This - public ApplicationCommandGroupBuilder AddNameLocalization(string name, ServerLocale serverLocale) - { - DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); - if (discordLocale.IsValid) - { - _option.NameLocalizations[discordLocale.Id] = name; - } + return this; + } - return this; - } + /// + /// Adds command description localizations for a given plugin and lang key + /// + /// Plugin containing the localizations + /// Lang Key containing the localized text + /// + [Obsolete("AddDescriptionLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddDescriptionLocalization(string name, string lang) instead.")] + public ApplicationCommandGroupBuilder AddDescriptionLocalizations(Plugin plugin, string langKey) + { + _option.DescriptionLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); + return this; + } - /// - /// Adds command description localizations for a given plugin and lang key - /// - /// Plugin containing the localizations - /// Lang Key containing the localized text - /// - [Obsolete("AddDescriptionLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddDescriptionLocalization(string name, string lang) instead.")] - public ApplicationCommandGroupBuilder AddDescriptionLocalizations(Plugin plugin, string langKey) + /// + /// Adds Application Command Description Localizations + /// + /// Localized description value + /// Oxide lang the value is in + /// This + private ApplicationCommandGroupBuilder AddDescriptionLocalization(string description, ServerLocale serverLocale) + { + DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); + if (discordLocale.IsValid) { - _option.DescriptionLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); - return this; + _option.DescriptionLocalizations[discordLocale.Id] = description; } - /// - /// Adds Application Command Description Localizations - /// - /// Localized description value - /// Oxide lang the value is in - /// This - private ApplicationCommandGroupBuilder AddDescriptionLocalization(string description, ServerLocale serverLocale) - { - DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); - if (discordLocale.IsValid) - { - _option.DescriptionLocalizations[discordLocale.Id] = description; - } - - return this; - } + return this; + } - /// - /// Adds a sub command to this sub command group - /// - /// Name of the command - /// Description of the command - /// Callback with the - /// this - public ApplicationCommandGroupBuilder AddSubCommand(string name, string description, Action builder = null) - { - ApplicationSubCommandBuilder sub = new ApplicationSubCommandBuilder(_option.Options, name, description, _defaultLanguage, CommandName, GroupName); - builder?.Invoke(sub); - return this; - } + /// + /// Adds a sub command to this sub command group + /// + /// Name of the command + /// Description of the command + /// Callback with the + /// this + public ApplicationCommandGroupBuilder AddSubCommand(string name, string description, Action builder = null) + { + ApplicationSubCommandBuilder sub = new(_option.Options, name, description, _defaultLanguage, CommandName, GroupName); + builder?.Invoke(sub); + return this; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandOptionBuilder.cs b/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandOptionBuilder.cs index 5baa471ac..e4507099b 100644 --- a/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandOptionBuilder.cs +++ b/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationCommandOptionBuilder.cs @@ -6,291 +6,285 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Represents a Subcommand Option Builder for SubCommands +/// +public class ApplicationCommandOptionBuilder { + private readonly CommandOption _option; + /// - /// Represents a Subcommand Option Builder for SubCommands + /// The Name of the command /// - public class ApplicationCommandOptionBuilder - { - private readonly CommandOption _option; - - /// - /// The Name of the command - /// - public readonly string CommandName; + public readonly string CommandName; - /// - /// The Name of the group - /// - public readonly string GroupName; + /// + /// The Name of the group + /// + public readonly string GroupName; - /// - /// The Name of the Sub Command - /// - public readonly string SubCommandName; + /// + /// The Name of the Sub Command + /// + public readonly string SubCommandName; - /// - /// The Name of the Option - /// - public readonly string OptionName; - - /// - /// Constructor - /// - /// - /// - /// - /// - /// - /// - /// - /// - internal ApplicationCommandOptionBuilder(List parent, CommandOptionType type, string name, string description, ServerLocale defaultLanguage, string commandName, string groupName, string subCommandName) - { - InvalidCommandOptionException.ThrowIfInvalidName(name, false); - InvalidCommandOptionException.ThrowIfInvalidDescription(description, false); - InvalidCommandOptionException.ThrowIfInvalidType(type); - - _option = new CommandOption(name, description, type); + /// + /// The Name of the Option + /// + public readonly string OptionName; - parent.Add(_option); - AddNameLocalization(name, defaultLanguage); - AddDescriptionLocalization(description, defaultLanguage); - CommandName = commandName; - GroupName = groupName; - SubCommandName = subCommandName; - OptionName = name; - } + /// + /// Constructor + /// + /// + /// + /// + /// + /// + /// + /// + /// + internal ApplicationCommandOptionBuilder(List parent, CommandOptionType type, string name, string description, ServerLocale defaultLanguage, string commandName, string groupName, string subCommandName) + { + InvalidCommandOptionException.ThrowIfInvalidName(name, false); + InvalidCommandOptionException.ThrowIfInvalidDescription(description, false); + InvalidCommandOptionException.ThrowIfInvalidType(type); - /// - /// Adds command name localizations for a given plugin and lang key - /// - /// Plugin containing the localizations - /// Lang Key containing the localized text - /// - [Obsolete("AddNameLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddNameLocalization(string name, string lang) instead.")] - public ApplicationCommandOptionBuilder AddNameLocalizations(Plugin plugin, string langKey) - { - _option.NameLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); - return this; - } + _option = new CommandOption(name, description, type); - /// - /// Adds Application Command Option Name Localization - /// - /// Localized name value - /// Oxide lang the value is in - /// This - public ApplicationCommandOptionBuilder AddNameLocalization(string name, ServerLocale serverLocale) - { - DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); - if (discordLocale.IsValid) - { - _option.NameLocalizations[discordLocale.Id] = name; - } + parent.Add(_option); + AddNameLocalization(name, defaultLanguage); + AddDescriptionLocalization(description, defaultLanguage); + CommandName = commandName; + GroupName = groupName; + SubCommandName = subCommandName; + OptionName = name; + } - return this; - } + /// + /// Adds command name localizations for a given plugin and lang key + /// + /// Plugin containing the localizations + /// Lang Key containing the localized text + /// + [Obsolete("AddNameLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddNameLocalization(string name, string lang) instead.")] + public ApplicationCommandOptionBuilder AddNameLocalizations(Plugin plugin, string langKey) + { + _option.NameLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); + return this; + } - /// - /// Adds command description localizations for a given plugin and lang key - /// - /// Plugin containing the localizations - /// Lang Key containing the localized text - /// - [Obsolete("AddDescriptionLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddDescriptionLocalization(string name, string lang) instead.")] - public ApplicationCommandOptionBuilder AddDescriptionLocalizations(Plugin plugin, string langKey) + /// + /// Adds Application Command Option Name Localization + /// + /// Localized name value + /// Oxide lang the value is in + /// This + public ApplicationCommandOptionBuilder AddNameLocalization(string name, ServerLocale serverLocale) + { + DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); + if (discordLocale.IsValid) { - _option.DescriptionLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); - return this; + _option.NameLocalizations[discordLocale.Id] = name; } - /// - /// Adds Application Command Option Description Localization - /// - /// Localized description value - /// Oxide lang the value is in - /// This - public ApplicationCommandOptionBuilder AddDescriptionLocalization(string description, ServerLocale serverLocale) - { - DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); - if (discordLocale.IsValid) - { - _option.DescriptionLocalizations[discordLocale.Id] = description; - } + return this; + } - return this; - } + /// + /// Adds command description localizations for a given plugin and lang key + /// + /// Plugin containing the localizations + /// Lang Key containing the localized text + /// + [Obsolete("AddDescriptionLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddDescriptionLocalization(string name, string lang) instead.")] + public ApplicationCommandOptionBuilder AddDescriptionLocalizations(Plugin plugin, string langKey) + { + _option.DescriptionLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); + return this; + } - /// - /// Set the required state for the option - /// - /// If the option is required (Default: true) - /// This - public ApplicationCommandOptionBuilder Required(bool required = true) + /// + /// Adds Application Command Option Description Localization + /// + /// Localized description value + /// Oxide lang the value is in + /// This + public ApplicationCommandOptionBuilder AddDescriptionLocalization(string description, ServerLocale serverLocale) + { + DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); + if (discordLocale.IsValid) { - _option.Required = required; - return this; + _option.DescriptionLocalizations[discordLocale.Id] = description; } - /// - /// Enable auto complete for the option - /// - /// If the option support auto complete (Default: true) - /// This - public ApplicationCommandOptionBuilder AutoComplete(bool autoComplete = true) - { - _option.Autocomplete = autoComplete; - return this; - } + return this; + } - /// - /// Min Value for Integer Option - /// - /// Min Value - /// This - public ApplicationCommandOptionBuilder MinValue(int minValue) - { - InvalidCommandOptionException.ThrowIfInvalidMinIntegerType(_option.Type); - _option.MinValue = minValue; - return this; - } + /// + /// Set the required state for the option + /// + /// If the option is required (Default: true) + /// This + public ApplicationCommandOptionBuilder Required(bool required = true) + { + _option.Required = required; + return this; + } - /// - /// Min Value for Number Option - /// - /// Min Value - /// This - public ApplicationCommandOptionBuilder MinValue(double minValue) - { - InvalidCommandOptionException.ThrowIfInvalidMinNumberType(_option.Type); - _option.MinValue = minValue; - return this; - } + /// + /// Enable auto complete for the option + /// + /// If the option supports auto complete (Default: true) + /// This + public ApplicationCommandOptionBuilder AutoComplete(bool autoComplete = true) + { + _option.Autocomplete = autoComplete; + return this; + } - /// - /// Max Value for Integer Option - /// - /// Max Value - /// This - public ApplicationCommandOptionBuilder MaxValue(int maxValue) - { - InvalidCommandOptionException.ThrowIfInvalidMaxIntegerType(_option.Type); - _option.MaxValue = maxValue; - return this; - } + /// + /// Min Value for Integer Option + /// + /// Min Value + /// This + public ApplicationCommandOptionBuilder MinValue(int minValue) + { + InvalidCommandOptionException.ThrowIfInvalidMinIntegerType(_option.Type); + _option.MinValue = minValue; + return this; + } - /// - /// Max Value for Number Option - /// - /// Max Value - /// This - public ApplicationCommandOptionBuilder MaxValue(double maxValue) - { - InvalidCommandOptionException.ThrowIfInvalidMaxNumberType(_option.Type); - _option.MaxValue = maxValue; - return this; - } + /// + /// Min Value for Number Option + /// + /// Min Value + /// This + public ApplicationCommandOptionBuilder MinValue(double minValue) + { + InvalidCommandOptionException.ThrowIfInvalidMinNumberType(_option.Type); + _option.MinValue = minValue; + return this; + } - /// - /// Min Length for String Option - /// Max Of 6000 - /// - /// Min Length for the string - /// This - public ApplicationCommandOptionBuilder MinLength(int minLength) - { - InvalidCommandOptionException.ThrowIfInvalidMinLengthType(_option.Type); - InvalidCommandOptionException.ThrowIfInvalidMinLength(minLength); - _option.MinLength = minLength; - return this; - } + /// + /// Max Value for Integer Option + /// + /// Max Value + /// This + public ApplicationCommandOptionBuilder MaxValue(int maxValue) + { + InvalidCommandOptionException.ThrowIfInvalidMaxIntegerType(_option.Type); + _option.MaxValue = maxValue; + return this; + } - /// - /// Max Length for String Option - /// Max Of 6000 - /// - /// Max Length - /// This - public ApplicationCommandOptionBuilder MaxLength(int maxLength) - { - InvalidCommandOptionException.ThrowIfInvalidMaxLengthType(_option.Type); - InvalidCommandOptionException.ThrowIfInvalidMaxLength(maxLength); - _option.MaxLength = maxLength; - return this; - } + /// + /// Max Value for Number Option + /// + /// Max Value + /// This + public ApplicationCommandOptionBuilder MaxValue(double maxValue) + { + InvalidCommandOptionException.ThrowIfInvalidMaxNumberType(_option.Type); + _option.MaxValue = maxValue; + return this; + } - /// - /// Set's the channel types for the option - /// - /// Types of channels the option allows - /// This - /// Thrown if is not Channel - public ApplicationCommandOptionBuilder ChannelTypes(List types) - { - InvalidCommandOptionException.ThrowIfInvalidChannelType(_option.Type); - _option.ChannelTypes = types; - return this; - } + /// + /// Min Length for String Option + /// Max Of 6000 + /// + /// Min Length for the string + /// This + public ApplicationCommandOptionBuilder MinLength(int minLength) + { + InvalidCommandOptionException.ThrowIfInvalidMinLengthType(_option.Type); + InvalidCommandOptionException.ThrowIfInvalidMinLength(minLength); + _option.MinLength = minLength; + return this; + } - /// - /// Adds a choice to this option of type string - /// - /// Name of the choice - /// Value of the choice - /// Localizations for the name - /// This - /// Thrown if option type is not string - public ApplicationCommandOptionBuilder AddChoice(string name, string value, Hash nameLocalizations = null) - { - InvalidCommandOptionChoiceException.ThrowIfInvalidType(_option.Type, CommandOptionType.String); - InvalidCommandOptionChoiceException.ThrowIfInvalidStringValue(name); - return AddChoiceInternal(name, value, nameLocalizations); - } + /// + /// Max Length for String Option + /// Max Of 6000 + /// + /// Max Length + /// This + public ApplicationCommandOptionBuilder MaxLength(int maxLength) + { + InvalidCommandOptionException.ThrowIfInvalidMaxLengthType(_option.Type); + InvalidCommandOptionException.ThrowIfInvalidMaxLength(maxLength); + _option.MaxLength = maxLength; + return this; + } - /// - /// Adds a choice to this option of type int - /// - /// Name of the choice - /// Value of the choice - /// Localizations for the name - /// This - /// Thrown if option type is not int - public ApplicationCommandOptionBuilder AddChoice(string name, int value, Hash nameLocalizations = null) - { - InvalidCommandOptionChoiceException.ThrowIfInvalidType(_option.Type, CommandOptionType.Integer); - return AddChoiceInternal(name, value, nameLocalizations); - } + /// + /// Set's the channel types for the option + /// + /// Types of channels the option allows + /// This + /// Thrown if is not Channel + public ApplicationCommandOptionBuilder ChannelTypes(List types) + { + InvalidCommandOptionException.ThrowIfInvalidChannelType(_option.Type); + _option.ChannelTypes = types; + return this; + } - /// - /// Adds a choice to this option of type double - /// - /// Name of the choice - /// Value of the choice - /// Localizations for the name - /// This - /// Thrown if option type is not double - public ApplicationCommandOptionBuilder AddChoice(string name, double value, Hash nameLocalizations = null) - { - InvalidCommandOptionChoiceException.ThrowIfInvalidType(_option.Type, CommandOptionType.Number); - return AddChoiceInternal(name, value, nameLocalizations); - } + /// + /// Adds a choice to this option of type string + /// + /// Name of the choice + /// Value of the choice + /// Localizations for the name + /// This + /// Thrown if the option type is not string + public ApplicationCommandOptionBuilder AddChoice(string name, string value, Hash nameLocalizations = null) + { + InvalidCommandOptionChoiceException.ThrowIfInvalidType(_option.Type, CommandOptionType.String); + InvalidCommandOptionChoiceException.ThrowIfInvalidStringValue(name); + return AddChoiceInternal(name, value, nameLocalizations); + } - private ApplicationCommandOptionBuilder AddChoiceInternal(string name, object value, Hash nameLocalizations) - { - InvalidCommandOptionChoiceException.ThrowIfInvalidName(name, false); + /// + /// Adds a choice to this option of type int + /// + /// Name of the choice + /// Value of the choice + /// Localizations for the name + /// This + /// Thrown if the option type is not int + public ApplicationCommandOptionBuilder AddChoice(string name, int value, Hash nameLocalizations = null) + { + InvalidCommandOptionChoiceException.ThrowIfInvalidType(_option.Type, CommandOptionType.Integer); + return AddChoiceInternal(name, value, nameLocalizations); + } - if (_option.Choices == null) - { - _option.Choices = new List(); - } + /// + /// Adds a choice to this option of type double + /// + /// Name of the choice + /// Value of the choice + /// Localizations for the name + /// This + /// Thrown if the option type is not double + public ApplicationCommandOptionBuilder AddChoice(string name, double value, Hash nameLocalizations = null) + { + InvalidCommandOptionChoiceException.ThrowIfInvalidType(_option.Type, CommandOptionType.Number); + return AddChoiceInternal(name, value, nameLocalizations); + } - InvalidCommandOptionChoiceException.ThrowIfMaxChoices(_option.Choices.Count); + private ApplicationCommandOptionBuilder AddChoiceInternal(string name, object value, Hash nameLocalizations) + { + InvalidCommandOptionChoiceException.ThrowIfInvalidName(name, false); + _option.Choices ??= []; + InvalidCommandOptionChoiceException.ThrowIfMaxChoices(_option.Choices.Count); - _option.Choices.Add(new CommandOptionChoice(name, value, nameLocalizations)); + _option.Choices.Add(new CommandOptionChoice(name, value, nameLocalizations)); - return this; - } + return this; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationSubCommandBuilder.cs b/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationSubCommandBuilder.cs index a7d0fc504..77a587076 100644 --- a/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationSubCommandBuilder.cs +++ b/Oxide.Ext.Discord/Builders/ApplicationCommands/ApplicationSubCommandBuilder.cs @@ -5,127 +5,126 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Application Sub Command Builder +/// +public class ApplicationSubCommandBuilder { + private readonly CommandOption _subCommand; + private readonly ServerLocale _defaultLanguage; + /// - /// Application Sub Command Builder + /// The Name of the command /// - public class ApplicationSubCommandBuilder - { - private readonly CommandOption _subCommand; - private readonly ServerLocale _defaultLanguage; - - /// - /// The Name of the command - /// - public readonly string CommandName; + public readonly string CommandName; - /// - /// The Name of the group - /// - public readonly string GroupName; + /// + /// The Name of the group + /// + public readonly string GroupName; - /// - /// The Name of the Sub Command - /// - public readonly string SubCommandName; + /// + /// The Name of the Sub Command + /// + public readonly string SubCommandName; - /// - /// Constructor - /// - /// Options for the sub command - /// Name of the sub command - /// Description of the sub command - /// - /// - /// - internal ApplicationSubCommandBuilder(List options, string name, string description, ServerLocale defaultLanguage, string commandName, string groupName) - { - _subCommand = new CommandOption(name, description, CommandOptionType.SubCommand, new List()); - options.Add(_subCommand); - _defaultLanguage = defaultLanguage; - AddNameLocalization(name, _defaultLanguage); - AddDescriptionLocalization(description, _defaultLanguage); - CommandName = commandName; - GroupName = groupName; - SubCommandName = name; - } + /// + /// Constructor + /// + /// Options for the sub command + /// Name of the sub command + /// Description of the sub command + /// + /// + /// + internal ApplicationSubCommandBuilder(List options, string name, string description, ServerLocale defaultLanguage, string commandName, string groupName) + { + _subCommand = new CommandOption(name, description, CommandOptionType.SubCommand, new List()); + options.Add(_subCommand); + _defaultLanguage = defaultLanguage; + AddNameLocalization(name, _defaultLanguage); + AddDescriptionLocalization(description, _defaultLanguage); + CommandName = commandName; + GroupName = groupName; + SubCommandName = name; + } - /// - /// Adds command name localizations for a given plugin and lang key - /// - /// Plugin containing the localizations - /// Lang Key containing the localized text - /// - [Obsolete("AddNameLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddNameLocalization(string name, string lang) instead.")] - public ApplicationSubCommandBuilder AddNameLocalizations(Plugin plugin, string langKey) + /// + /// Adds command name localizations for a given plugin and lang key + /// + /// Plugin containing the localizations + /// Lang Key containing the localized text + /// + [Obsolete("AddNameLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddNameLocalization(string name, string lang) instead.")] + public ApplicationSubCommandBuilder AddNameLocalizations(Plugin plugin, string langKey) + { + _subCommand.NameLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); + return this; + } + + /// + /// Adds Application Sub Command Name Localization + /// + /// Localized name value + /// Oxide lang the value is in + /// This + public ApplicationSubCommandBuilder AddNameLocalization(string name, ServerLocale serverLocale) + { + DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); + if (discordLocale.IsValid) { - _subCommand.NameLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); - return this; + _subCommand.NameLocalizations[discordLocale.Id] = name; } - - /// - /// Adds Application Sub Command Name Localization - /// - /// Localized name value - /// Oxide lang the value is in - /// This - public ApplicationSubCommandBuilder AddNameLocalization(string name, ServerLocale serverLocale) - { - DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); - if (discordLocale.IsValid) - { - _subCommand.NameLocalizations[discordLocale.Id] = name; - } - return this; - } + return this; + } - /// - /// Adds command description localizations for a given plugin and lang key - /// - /// Plugin containing the localizations - /// Lang Key containing the localized text - /// - [Obsolete("AddDescriptionLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddDescriptionLocalization(string name, string lang) instead.")] - public ApplicationSubCommandBuilder AddDescriptionLocalizations(Plugin plugin, string langKey) - { - _subCommand.DescriptionLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); - return this; - } + /// + /// Adds command description localizations for a given plugin and lang key + /// + /// Plugin containing the localizations + /// Lang Key containing the localized text + /// + [Obsolete("AddDescriptionLocalizations(Plugin plugin, string langKey) has been deprecated and will be removed in the future. Please use AddDescriptionLocalization(string name, string lang) instead.")] + public ApplicationSubCommandBuilder AddDescriptionLocalizations(Plugin plugin, string langKey) + { + _subCommand.DescriptionLocalizations = DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey); + return this; + } - /// - /// Adds Application Sub Command Description Localizations - /// - /// Localized description value - /// Oxide lang the value is in - /// This - public ApplicationSubCommandBuilder AddDescriptionLocalization(string description, ServerLocale serverLocale) - { - DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); - if (discordLocale.IsValid) - { - _subCommand.DescriptionLocalizations[discordLocale.Id] = description; - } - - return this; + /// + /// Adds Application Sub Command Description Localizations + /// + /// Localized description value + /// Oxide lang the value is in + /// This + public ApplicationSubCommandBuilder AddDescriptionLocalization(string description, ServerLocale serverLocale) + { + DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); + if (discordLocale.IsValid) + { + _subCommand.DescriptionLocalizations[discordLocale.Id] = description; } + + return this; + } - /// - /// Adds a new option - /// - /// Option data type (Cannot be SubCommand or SubCommandGroup) - /// Name of the option - /// Description of the option - /// Callback with the - /// This - /// Thrown if type is or - public ApplicationSubCommandBuilder AddOption(CommandOptionType type, string name, string description, Action builder = null) - { - ApplicationCommandBuilderException.ThrowIfInvalidCommandOptionType(type); - ApplicationCommandOptionBuilder option = new ApplicationCommandOptionBuilder(_subCommand.Options, type, name, description, _defaultLanguage, CommandName, GroupName, SubCommandName); - builder?.Invoke(option); - return this; - } + /// + /// Adds a new option + /// + /// Option data type (Cannot be SubCommand or SubCommandGroup) + /// Name of the option + /// Description of the option + /// Callback with the + /// This + /// Thrown if type is or + public ApplicationSubCommandBuilder AddOption(CommandOptionType type, string name, string description, Action builder = null) + { + ApplicationCommandBuilderException.ThrowIfInvalidCommandOptionType(type); + ApplicationCommandOptionBuilder option = new(_subCommand.Options, type, name, description, _defaultLanguage, CommandName, GroupName, SubCommandName); + builder?.Invoke(option); + return this; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/DiscordEmbedBuilder.cs b/Oxide.Ext.Discord/Builders/DiscordEmbedBuilder.cs index 6add3e7f1..6d290f8a4 100644 --- a/Oxide.Ext.Discord/Builders/DiscordEmbedBuilder.cs +++ b/Oxide.Ext.Discord/Builders/DiscordEmbedBuilder.cs @@ -4,313 +4,309 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Builds a new DiscordEmbed +/// +public class DiscordEmbedBuilder { + private readonly DiscordEmbed _embed; + /// - /// Builds a new DiscordEmbed + /// Constructor for the builder creating a new embed /// - public class DiscordEmbedBuilder - { - private readonly DiscordEmbed _embed; + public DiscordEmbedBuilder() : this(new DiscordEmbed()) { } - /// - /// Constructor for the builder creating a new embed - /// - public DiscordEmbedBuilder() : this(new DiscordEmbed()) { } - - /// - /// Constructor for the builder using an existing embed - /// - /// - public DiscordEmbedBuilder(DiscordEmbed embed) - { - _embed = embed; - } + /// + /// Constructor for the builder using an existing embed + /// + /// + public DiscordEmbedBuilder(DiscordEmbed embed) + { + _embed = embed; + } - /// - /// Adds a title to the embed message - /// - /// Title to add - /// This - public DiscordEmbedBuilder AddTitle(string title) - { - InvalidEmbedException.ThrowIfInvalidTitle(title); - _embed.Title = title; - return this; - } + /// + /// Adds a title to the embed message + /// + /// Title to add + /// This + public DiscordEmbedBuilder AddTitle(string title) + { + InvalidEmbedException.ThrowIfInvalidTitle(title); + _embed.Title = title; + return this; + } - /// - /// Adds a description to the embed message - /// - /// description to add - /// This - public DiscordEmbedBuilder AddDescription(string description) - { - InvalidEmbedException.ThrowIfInvalidDescription(description); - _embed.Description = description; - return this; - } + /// + /// Adds a description to the embed message + /// + /// description to add + /// This + public DiscordEmbedBuilder AddDescription(string description) + { + InvalidEmbedException.ThrowIfInvalidDescription(description); + _embed.Description = description; + return this; + } - /// - /// Adds a url to the embed message - /// - /// - /// This - public DiscordEmbedBuilder AddUrl(string url) - { - _embed.Url = url; - return this; - } + /// + /// Adds a url to the embed message + /// + /// + /// This + public DiscordEmbedBuilder AddUrl(string url) + { + _embed.Url = url; + return this; + } - /// - /// Adds an author to the embed message. The author will appear above the title - /// - /// Name of the author - /// Url to go to when the authors name is clicked on - /// Icon Url to use for the author - /// Backup icon url. Can be left null if you only have one icon url - /// This - public DiscordEmbedBuilder AddAuthor(string name, string url = null, string iconUrl = null, string proxyIconUrl = null) - { - InvalidEmbedException.ThrowIfInvalidAuthorName(name); - _embed.Author = new EmbedAuthor(name, url, iconUrl, proxyIconUrl); - return this; - } + /// + /// Adds an author to the embed message. The author will appear above the title + /// + /// Name of the author + /// Url to go to when the author's name is clicked on + /// Icon Url to use for the author + /// Backup icon url. Can be left null if you only have one icon url + /// This + public DiscordEmbedBuilder AddAuthor(string name, string url = null, string iconUrl = null, string proxyIconUrl = null) + { + InvalidEmbedException.ThrowIfInvalidAuthorName(name); + _embed.Author = new EmbedAuthor(name, url, iconUrl, proxyIconUrl); + return this; + } - /// - /// Adds a footer to the embed message - /// - /// Text to be added to the footer - /// Icon url to add in the footer. Appears to the left of the text - /// Backup icon url. Can be left null if you only have one icon url - /// This - public DiscordEmbedBuilder AddFooter(string text, string iconUrl = null, string proxyIconUrl = null) - { - InvalidEmbedException.ThrowIfInvalidFooterText(text); - _embed.Footer = new EmbedFooter(text, iconUrl, proxyIconUrl); - return this; - } + /// + /// Adds a footer to the embed message + /// + /// Text to be added to the footer + /// Icon url to add in the footer. Appears to the left of the text + /// Backup icon url. Can be left null if you only have one icon url + /// This + public DiscordEmbedBuilder AddFooter(string text, string iconUrl = null, string proxyIconUrl = null) + { + InvalidEmbedException.ThrowIfInvalidFooterText(text); + _embed.Footer = new EmbedFooter(text, iconUrl, proxyIconUrl); + return this; + } - /// - /// Adds a Discord Color to the embed - /// - /// - /// This - public DiscordEmbedBuilder AddColor(DiscordColor color) - { - _embed.Color = color; - return this; - } + /// + /// Adds a Discord Color to the embed + /// + /// + /// This + public DiscordEmbedBuilder AddColor(DiscordColor color) + { + _embed.Color = color; + return this; + } - /// - /// Adds an int based color to the embed. Color appears as a bar on the left side of the message - /// - /// - /// This - public DiscordEmbedBuilder AddColor(uint color) - { - _embed.Color = new DiscordColor(color); - return this; - } + /// + /// Adds an int based color to the embed. Color appears as a bar on the left side of the message + /// + /// + /// This + public DiscordEmbedBuilder AddColor(uint color) + { + _embed.Color = new DiscordColor(color); + return this; + } - /// - /// Adds a hex based color. Color appears as a bar on the left side of the message - /// - /// Color in string hex format - /// This - /// Exception thrown if color is outside of range - public DiscordEmbedBuilder AddColor(string color) - { - _embed.Color = new DiscordColor(uint.Parse(color.TrimStart('#'), NumberStyles.AllowHexSpecifier)); - return this; - } + /// + /// Adds a hex based color. Color appears as a bar on the left side of the message + /// + /// Color in string hex format + /// This + /// Exception thrown if color is outside of range + public DiscordEmbedBuilder AddColor(string color) + { + _embed.Color = new DiscordColor(uint.Parse(color.TrimStart('#'), NumberStyles.AllowHexSpecifier)); + return this; + } - /// - /// Adds a RGB based color. Color appears as a bar on the left side of the message - /// - /// Red value - /// Green value - /// Blue value - /// This - public DiscordEmbedBuilder AddColor(byte red, byte green, byte blue) - { - _embed.Color = new DiscordColor(red, green, blue); - return this; - } + /// + /// Adds a RGB based color. Color appears as a bar on the left side of the message + /// + /// Red value + /// Green value + /// Blue value + /// This + public DiscordEmbedBuilder AddColor(byte red, byte green, byte blue) + { + _embed.Color = new DiscordColor(red, green, blue); + return this; + } - /// - /// Adds a RGB based color. Color appears as a bar on the left side of the message - /// - /// Red value between 0 - 255 - /// Green value between 0 - 255 - /// Blue value between 0 - 255 - /// This - /// Thrown if red, green, or blue is outside of range - public DiscordEmbedBuilder AddColor(int red, int green, int blue) - { - _embed.Color = new DiscordColor(red, green, blue); - return this; - } + /// + /// Adds a RGB based color. Color appears as a bar on the left side of the message + /// + /// Red value between 0-255 + /// Green value between 0-255 + /// Blue value between 0-255 + /// This + /// Thrown if red, green, or blue is outside of range + public DiscordEmbedBuilder AddColor(int red, int green, int blue) + { + _embed.Color = new DiscordColor(red, green, blue); + return this; + } - /// - /// Adds a RGB based color. Color appears as a bar on the left side of the message - /// - /// Red value between 0 - 1 - /// Green value between 0 - 1 - /// Blue value between 0 - 1 - /// This - /// Thrown if red, green, or blue is outside of range - public DiscordEmbedBuilder AddColor(float red, float green, float blue) - { - _embed.Color = new DiscordColor(red, green, blue); - return this; - } + /// + /// Adds a RGB based color. Color appears as a bar on the left side of the message + /// + /// Red value between 0-1 + /// Green value between 0-1 + /// Blue value between 0-1 + /// This + /// Thrown if red, green, or blue is outside of range + public DiscordEmbedBuilder AddColor(float red, float green, float blue) + { + _embed.Color = new DiscordColor(red, green, blue); + return this; + } - /// - /// Adds a RGB based color. Color appears as a bar on the left side of the message - /// - /// Red value between 0 - 1 - /// Green value between 0 - 1 - /// Blue value between 0 - 1 - /// This - /// Thrown if red, green, or blue is outside of range - public DiscordEmbedBuilder AddColor(double red, double green, double blue) - { - _embed.Color = new DiscordColor(red, green, blue); - return this; - } + /// + /// Adds a RGB based color. Color appears as a bar on the left side of the message + /// + /// Red value between 0-1 + /// Green value between 0-1 + /// Blue value between 0-1 + /// This + /// Thrown if red, green, or blue is outside of range + public DiscordEmbedBuilder AddColor(double red, double green, double blue) + { + _embed.Color = new DiscordColor(red, green, blue); + return this; + } - /// - /// Adds a timestamp to an embed with the current time - /// - /// This - public DiscordEmbedBuilder AddNowTimestamp() - { - _embed.Timestamp = DateTime.UtcNow; - return this; - } + /// + /// Adds a timestamp to an embed with the current time + /// + /// This + public DiscordEmbedBuilder AddNowTimestamp() + { + _embed.Timestamp = DateTime.UtcNow; + return this; + } - /// - /// Adds a timestamp to an embed with the given time - /// - /// Timestamp to set for the embed - /// This - public DiscordEmbedBuilder AddTimestamp(DateTime timestamp) - { - _embed.Timestamp = timestamp; - return this; - } + /// + /// Adds a timestamp to an embed with the given time + /// + /// Timestamp to set for the embed + /// This + public DiscordEmbedBuilder AddTimestamp(DateTime timestamp) + { + _embed.Timestamp = timestamp; + return this; + } - /// - /// Adds a blank field. - /// If inline it will add a blank column. - /// If not inline will add a blank row - /// - /// If the field is inline - /// This - public DiscordEmbedBuilder AddBlankField(bool inline) - { - return AddField(null, null, inline); - } + /// + /// Adds a blank field. + /// If inline, it will add a blank column. + /// If not, inline will add a blank row + /// + /// If the field is inline + /// This + public DiscordEmbedBuilder AddBlankField(bool inline) + { + return AddField(null, null, inline); + } - /// - /// Adds a new field with the name as the title and value as the value. - /// If inline will add a new column. If row will add in a new row. - /// - /// Name of the field - /// Value of the field - /// If the field should be inlined - /// This - public DiscordEmbedBuilder AddField(string name, string value, bool inline) - { - if (_embed.Fields == null) - { - _embed.Fields = new List(); - } + /// + /// Adds a new field with the name as the title and value as the value. + /// If inline add a new column. If row adds in a new row. + /// + /// Name of the field + /// Value of the field + /// If the field should be inlined + /// This + public DiscordEmbedBuilder AddField(string name, string value, bool inline) + { + _embed.Fields ??= []; - InvalidEmbedException.ThrowIfInvalidFieldCount(_embed.Fields.Count); - InvalidEmbedException.ThrowIfInvalidFieldName(name); - InvalidEmbedException.ThrowIfInvalidFieldValue(value); + InvalidEmbedException.ThrowIfInvalidFieldCount(_embed.Fields.Count); + InvalidEmbedException.ThrowIfInvalidFieldName(name); + InvalidEmbedException.ThrowIfInvalidFieldValue(value); - _embed.Fields.Add(new EmbedField(name, value, inline)); - return this; - } + _embed.Fields.Add(new EmbedField(name, value, inline)); + return this; + } - /// - /// Adds an image to the embed. The url should point to the url of the image. - /// If using attachment image you can make the url: "attachment://{image name}.{image extension} - /// - /// Url for the image - /// width of the image - /// height of the image - /// Backup url for the image - /// This - public DiscordEmbedBuilder AddImage(string url, int? width = null, int? height = null, string proxyUrl = null) - { - InvalidEmbedException.ThrowIfInvalidUrl(url); - _embed.Image = new EmbedImage(url, width, height, proxyUrl); - return this; - } + /// + /// Adds an image to the embed. The url should point to the url of the image. + /// If using attachment image, you can make the url: "attachment://{image name}.{image extension} + /// + /// Url for the image + /// width of the image + /// height of the image + /// Backup url for the image + /// This + public DiscordEmbedBuilder AddImage(string url, int? width = null, int? height = null, string proxyUrl = null) + { + InvalidEmbedException.ThrowIfInvalidUrl(url); + _embed.Image = new EmbedImage(url, width, height, proxyUrl); + return this; + } - /// - /// Adds a thumbnail in the top right corner of the embed - /// If using attachment image you can make the url: "attachment://{image name}.{image extension} - /// - /// Url for the image - /// width of the image - /// height of the image - /// Backup url for the image - /// This - public DiscordEmbedBuilder AddThumbnail(string url, int? width = null, int? height = null, string proxyUrl = null) - { - InvalidEmbedException.ThrowIfInvalidUrl(url); - _embed.Thumbnail = new EmbedThumbnail(url, width, height, proxyUrl); - return this; - } + /// + /// Adds a thumbnail in the top right corner of the embed, + /// If using attachment image, you can make the url: "attachment://{image name}.{image extension} + /// + /// Url for the image + /// width of the image + /// height of the image + /// Backup url for the image + /// This + public DiscordEmbedBuilder AddThumbnail(string url, int? width = null, int? height = null, string proxyUrl = null) + { + InvalidEmbedException.ThrowIfInvalidUrl(url); + _embed.Thumbnail = new EmbedThumbnail(url, width, height, proxyUrl); + return this; + } - /// - /// Adds a video to the embed - /// - /// Url for the video - /// Width of the video - /// Height of the video - /// Proxy Url for the video - /// This - public DiscordEmbedBuilder AddVideo(string url, int? width = null, int? height = null, string proxyUrl = null) - { - InvalidEmbedException.ThrowIfInvalidUrl(url); - _embed.Video = new EmbedVideo(url, width, height, proxyUrl); - return this; - } + /// + /// Adds a video to the embed + /// + /// Url for the video + /// Width of the video + /// Height of the video + /// Proxy Url for the video + /// This + public DiscordEmbedBuilder AddVideo(string url, int? width = null, int? height = null, string proxyUrl = null) + { + InvalidEmbedException.ThrowIfInvalidUrl(url); + _embed.Video = new EmbedVideo(url, width, height, proxyUrl); + return this; + } - /// - /// Adds a provider to the embed - /// - /// Name for the provider - /// Url for the provider - /// This - public DiscordEmbedBuilder AddProvider(string name, string url) - { - _embed.Provider = new EmbedProvider(name, url); - return this; - } + /// + /// Adds a provider to the embed + /// + /// Name for the provider + /// Url for the provider + /// This + public DiscordEmbedBuilder AddProvider(string name, string url) + { + _embed.Provider = new EmbedProvider(name, url); + return this; + } - /// - /// Returns the built embed - /// - /// - public DiscordEmbed Build() - { - return _embed; - } + /// + /// Returns the built embed + /// + /// + public DiscordEmbed Build() + { + return _embed; + } - /// - /// Returns the built embed in a list - /// - /// List of - public List BuildList() - { - return new List {_embed}; - } + /// + /// Returns the built embed in a list + /// + /// List of + public List BuildList() + { + return [_embed]; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/AutoCompleteSearchMode.cs b/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/AutoCompleteSearchMode.cs index c0737b76f..592505a50 100644 --- a/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/AutoCompleteSearchMode.cs +++ b/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/AutoCompleteSearchMode.cs @@ -1,23 +1,22 @@ -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// AutoComplete Search Mode for +/// +public enum AutoCompleteSearchMode : byte { /// - /// AutoComplete Search Mode for + /// Filter using StartsWith /// - public enum AutoCompleteSearchMode : byte - { - /// - /// Filter using StartsWith - /// - StartsWith, + StartsWith, - /// - /// Filter using Contains - /// - Contains, + /// + /// Filter using Contains + /// + Contains, - /// - /// Filter using EndsWith - /// - EndsWith - } + /// + /// Filter using EndsWith + /// + EndsWith } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/PlayerDisplayNameMode.cs b/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/PlayerDisplayNameMode.cs index 7cf2dc74f..e80b68096 100644 --- a/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/PlayerDisplayNameMode.cs +++ b/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/PlayerDisplayNameMode.cs @@ -1,31 +1,30 @@ using System; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Player Name Formatting options for +/// +[Flags] +public enum PlayerDisplayNameMode : sbyte { /// - /// Player Name Formatting options for + /// Defaults search options /// - [Flags] - public enum PlayerDisplayNameMode : sbyte - { - /// - /// Defaults search options - /// - Default = 0, + Default = 0, - /// - /// Include Clan Name in search - /// - Clan = 1 << 0, + /// + /// Include Clan Name in search + /// + Clan = 1 << 0, - /// - /// Include Player ID - /// - PlayerId = 1 << 1, + /// + /// Include Player ID + /// + PlayerId = 1 << 1, - /// - /// All display name options - /// - All = Default | Clan | PlayerId - } + /// + /// All display name options + /// + All = Default | Clan | PlayerId } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/PlayerNameFormatter.cs b/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/PlayerNameFormatter.cs index f951c8279..e7a3e901c 100644 --- a/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/PlayerNameFormatter.cs +++ b/Oxide.Ext.Discord/Builders/Interactions/AutoComplete/PlayerNameFormatter.cs @@ -2,61 +2,60 @@ using Oxide.Core.Libraries.Covalence; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Formatter for player names +/// +public class PlayerNameFormatter { + private readonly PlayerDisplayNameMode _mode; + private readonly Func _customNameFunc; + /// - /// Formatter for player names + /// Default Player Name Formatter /// - public class PlayerNameFormatter - { - private readonly PlayerDisplayNameMode _mode; - private readonly Func _customNameFunc; - - /// - /// Default Player Name Formatter - /// - public static readonly PlayerNameFormatter Default = Create(PlayerDisplayNameMode.Default); + public static readonly PlayerNameFormatter Default = Create(PlayerDisplayNameMode.Default); - /// - /// Include clan name in the player name - /// - public static readonly PlayerNameFormatter ClanName = Create(PlayerDisplayNameMode.Clan); + /// + /// Include clan name in the player name + /// + public static readonly PlayerNameFormatter ClanName = Create(PlayerDisplayNameMode.Clan); - /// - /// Include Player Id in the player name - /// - public static readonly PlayerNameFormatter PlayerId = Create(PlayerDisplayNameMode.PlayerId); + /// + /// Include Player ID in the player name + /// + public static readonly PlayerNameFormatter PlayerId = Create(PlayerDisplayNameMode.PlayerId); - /// - /// Include all name options in the player name - /// - public static readonly PlayerNameFormatter All = Create(PlayerDisplayNameMode.All); + /// + /// Include all name options in the player name + /// + public static readonly PlayerNameFormatter All = Create(PlayerDisplayNameMode.All); - private PlayerNameFormatter(PlayerDisplayNameMode mode, Func customNameFunc) - { - _mode = mode; - _customNameFunc = customNameFunc; - } + private PlayerNameFormatter(PlayerDisplayNameMode mode, Func customNameFunc) + { + _mode = mode; + _customNameFunc = customNameFunc; + } - /// - /// Create a new Player Name formatter with the given - /// - /// Mode to use for Player Display Name - /// A new - private static PlayerNameFormatter Create(PlayerDisplayNameMode mode) => new PlayerNameFormatter(mode, null); + /// + /// Create a new Player Name formatter with the given + /// + /// Mode to use for Player Display Name + /// A new + private static PlayerNameFormatter Create(PlayerDisplayNameMode mode) => new(mode, null); - /// - /// Create a new Player Name formatter with the given Custom Name Function - /// - /// Function to use for formatting the name - /// A new - public static PlayerNameFormatter Create(Func customNameFunc) => new PlayerNameFormatter(PlayerDisplayNameMode.Default, customNameFunc); + /// + /// Create a new Player Name formatter with the given Custom Name Function + /// + /// Function to use for formatting the name + /// A new + public static PlayerNameFormatter Create(Func customNameFunc) => new(PlayerDisplayNameMode.Default, customNameFunc); - /// - /// Formats the player name - /// - /// Player to have their name formatted - /// Formatted player name - public string Format(IPlayer player) => _customNameFunc != null ? _customNameFunc(player) : DiscordExtensionCore.Instance.GetPlayerName(player, _mode); - } + /// + /// Formats the player name + /// + /// Player to have their name formatted + /// Formatted player name + public string Format(IPlayer player) => _customNameFunc != null ? _customNameFunc(player) : DiscordExtensionCore.Instance.GetPlayerName(player, _mode); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Interactions/BaseInteractionMessageBuilder.cs b/Oxide.Ext.Discord/Builders/Interactions/BaseInteractionMessageBuilder.cs index 7057116d9..5c7d16502 100644 --- a/Oxide.Ext.Discord/Builders/Interactions/BaseInteractionMessageBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Interactions/BaseInteractionMessageBuilder.cs @@ -1,35 +1,34 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Represents a builder for +/// +/// +/// +public abstract class BaseInteractionMessageBuilder : BaseMessageBuilder + where TMessage : BaseInteractionMessage + where TBuilder : BaseInteractionMessageBuilder { /// - /// Represents a builder for + /// Constructor /// - /// - /// - public abstract class BaseInteractionMessageBuilder : BaseMessageBuilder - where TMessage : BaseInteractionMessage - where TBuilder : BaseInteractionMessageBuilder + /// Interaction this builder is for + /// Message to be created + protected BaseInteractionMessageBuilder(DiscordInteraction interaction, TMessage message) : base(message) { - /// - /// Constructor - /// - /// Interaction this builder is for - /// Message to be created - protected BaseInteractionMessageBuilder(DiscordInteraction interaction, TMessage message) : base(message) - { - InteractionResponseBuilderException.ThrowIfInteractionIsAutoComplete(interaction.Type); - } + InteractionResponseBuilderException.ThrowIfInteractionIsAutoComplete(interaction.Type); + } - /// - /// Marks the response as Ephemeral so only the person who executed the command can see - /// - /// - public TBuilder AsEphemeral() - { - Message.Flags |= MessageFlags.Ephemeral; - return Builder; - } + /// + /// Marks the response as Ephemeral so only the person who executed the command can see + /// + /// + public TBuilder AsEphemeral() + { + Message.Flags |= MessageFlags.Ephemeral; + return Builder; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Interactions/InteractionAutoCompleteBuilder.cs b/Oxide.Ext.Discord/Builders/Interactions/InteractionAutoCompleteBuilder.cs index 90dddd5dc..e9388ee02 100644 --- a/Oxide.Ext.Discord/Builders/Interactions/InteractionAutoCompleteBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Interactions/InteractionAutoCompleteBuilder.cs @@ -8,416 +8,408 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Builder for Auto Complete Interaction +/// +public class InteractionAutoCompleteBuilder { + private readonly InteractionAutoCompleteMessage _message; + /// - /// Builder for Auto Complete Interaction + /// Number of added choices /// - public class InteractionAutoCompleteBuilder - { - private readonly InteractionAutoCompleteMessage _message; - - /// - /// Number of added choices - /// - public int Count => _message.Choices.Count; + public int Count => _message.Choices.Count; - /// - /// Constructor - /// - /// Interaction this build is for - /// Starting - public InteractionAutoCompleteBuilder(DiscordInteraction interaction, InteractionAutoCompleteMessage message = null) - { - InteractionResponseBuilderException.ThrowIfInteractionIsNotAutoComplete(interaction.Type); - _message = message ?? new InteractionAutoCompleteMessage(); - if (_message.Choices == null) - { - _message.Choices = new List(); - } - } + /// + /// Constructor + /// + /// Interaction this build is for + /// Starting + public InteractionAutoCompleteBuilder(DiscordInteraction interaction, InteractionAutoCompleteMessage message = null) + { + InteractionResponseBuilderException.ThrowIfInteractionIsNotAutoComplete(interaction.Type); + _message = message ?? new InteractionAutoCompleteMessage(); + _message.Choices ??= []; + } - /// - /// Adds a to the response - /// - /// Name of the choice - /// Value of the choice - /// This - public InteractionAutoCompleteBuilder AddChoice(string name, object value) - { - InvalidAutoCompleteChoiceException.ThrowIfInvalidName(name); - InvalidAutoCompleteChoiceException.ThrowIfInvalidValue(value); - return AddChoice(new CommandOptionChoice(name, value)); - } + /// + /// Adds a to the response + /// + /// Name of the choice + /// Value of the choice + /// This + public InteractionAutoCompleteBuilder AddChoice(string name, object value) + { + InvalidAutoCompleteChoiceException.ThrowIfInvalidName(name); + InvalidAutoCompleteChoiceException.ThrowIfInvalidValue(value); + return AddChoice(new CommandOptionChoice(name, value)); + } - /// - /// Adds a to the response - /// - /// Name of the choice - /// Value of the choice - /// Plugin to lookup the langkey for - /// Lang key for the name - /// This - public InteractionAutoCompleteBuilder AddChoice(string name, object value, Plugin plugin, string langKey) - { - InvalidAutoCompleteChoiceException.ThrowIfInvalidName(name); - InvalidAutoCompleteChoiceException.ThrowIfInvalidValue(value); - return AddChoice(new CommandOptionChoice(name, value, DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey))); - } + /// + /// Adds a to the response + /// + /// Name of the choice + /// Value of the choice + /// Plugin to lookup the langkey for + /// Lang key for the name + /// This + public InteractionAutoCompleteBuilder AddChoice(string name, object value, Plugin plugin, string langKey) + { + InvalidAutoCompleteChoiceException.ThrowIfInvalidName(name); + InvalidAutoCompleteChoiceException.ThrowIfInvalidValue(value); + return AddChoice(new CommandOptionChoice(name, value, DiscordLocales.Instance.GetDiscordLocalizations(plugin, langKey))); + } - /// - /// Adds a to the response - /// - /// Choice to be added - /// This - public InteractionAutoCompleteBuilder AddChoice(CommandOptionChoice choice) - { - if (choice == null) throw new ArgumentNullException(nameof(choice)); - InvalidCommandOptionChoiceException.ThrowIfMaxChoices(_message.Choices.Count + 1); - _message.Choices.Add(choice); - return this; - } + /// + /// Adds a to the response + /// + /// Choice to be added + /// This + public InteractionAutoCompleteBuilder AddChoice(CommandOptionChoice choice) + { + if (choice == null) throw new ArgumentNullException(nameof(choice)); + InvalidCommandOptionChoiceException.ThrowIfMaxChoices(_message.Choices.Count + 1); + _message.Choices.Add(choice); + return this; + } - /// - /// Adds a collection of to the response - /// - /// Choices to be added - /// This - public InteractionAutoCompleteBuilder AddChoices(ICollection choices) - { - if (choices == null) throw new ArgumentNullException(nameof(choices)); + /// + /// Adds a collection of to the response + /// + /// Choices to be added + /// This + public InteractionAutoCompleteBuilder AddChoices(ICollection choices) + { + if (choices == null) throw new ArgumentNullException(nameof(choices)); - InvalidCommandOptionChoiceException.ThrowIfMaxChoices(_message.Choices.Count + choices.Count); - _message.Choices.AddRange(choices); - return this; - } + InvalidCommandOptionChoiceException.ThrowIfMaxChoices(_message.Choices.Count + choices.Count); + _message.Choices.AddRange(choices); + return this; + } - /// - /// Returns if the Auto Complete can add any more choices - /// - /// - public bool CanAddChoice() => Count < 25; + /// + /// Returns if the Auto Complete can add any more choices + /// + /// + public bool CanAddChoice() => Count < 25; - /// - /// Returns the built message - /// - /// - public InteractionAutoCompleteMessage Build() => _message; + /// + /// Returns the built message + /// + /// + public InteractionAutoCompleteMessage Build() => _message; - #region Oxide - /// - /// Adds Oxide Groups to the AutoComplete - /// - /// String to filter by - /// to use - /// Filter search mode - public void AddGroups(string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - AddList(OxideLibrary.Instance.Permission.GetGroups(), filter, comparison, search); - } + #region Oxide + /// + /// Adds Oxide Groups to the AutoComplete + /// + /// String to filter by + /// to use + /// Filter search mode + public void AddGroups(string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + AddList(OxideLibrary.Instance.Permission.GetGroups(), filter, comparison, search); + } - /// - /// Adds Oxide Permissions to the AutoComplete - /// - /// String to filter by - /// to use - /// Filter search mode - public void AddPermissions(string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - AddList(OxideLibrary.Instance.Permission.GetPermissions(), filter, comparison, search); - } + /// + /// Adds Oxide Permissions to the AutoComplete + /// + /// String to filter by + /// to use + /// Filter search mode + public void AddPermissions(string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + AddList(OxideLibrary.Instance.Permission.GetPermissions(), filter, comparison, search); + } - /// - /// Adds The List of Groups that have this permission - /// - /// Permission to get groups for - /// String to filter by - /// to use - /// Filter search mode - public void AddGroupsWithPermission(string permission, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - AddList(OxideLibrary.Instance.Permission.GetPermissionGroups(permission), filter, comparison, search); - } + /// + /// Adds The List of Groups that have this permission + /// + /// Permission to get groups for + /// String to filter by + /// to use + /// Filter search mode + public void AddGroupsWithPermission(string permission, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + AddList(OxideLibrary.Instance.Permission.GetPermissionGroups(permission), filter, comparison, search); + } - /// - /// Adds The List of Groups that have this permission - /// - /// Permission to get groups for - /// String to filter by - /// to use - /// Filter search mode - public void AddGroupsWithoutPermission(string permission, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - string[] groups = OxideLibrary.Instance.Permission.GetPermissionGroups(permission); - AddList(OxideLibrary.Instance.Permission.GetGroups().Except(groups), filter, comparison, search); - } + /// + /// Adds The List of Groups that have this permission + /// + /// Permission to get groups for + /// String to filter by + /// to use + /// Filter search mode + public void AddGroupsWithoutPermission(string permission, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + string[] groups = OxideLibrary.Instance.Permission.GetPermissionGroups(permission); + AddList(OxideLibrary.Instance.Permission.GetGroups().Except(groups), filter, comparison, search); + } - /// - /// Adds List of Permissions that are in the given group - /// - /// Group to get permissions for - /// Permission filter - /// to use - /// Filter search mode - public void AddPermissionsInGroup(string group, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - AddList(OxideLibrary.Instance.Permission.GetGroupPermissions(group), filter, comparison, search); - } + /// + /// Adds List of Permissions that are in the given group + /// + /// Group to get permissions for + /// Permission filter + /// to use + /// Filter search mode + public void AddPermissionsInGroup(string group, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + AddList(OxideLibrary.Instance.Permission.GetGroupPermissions(group), filter, comparison, search); + } - /// - /// Adds a List of Permissions that are not in a given group - /// - /// Group that doesn't have the permissions - /// Permission filter - /// to use - /// Filter search mode - public void AddPermissionsNotInGroup(string group, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - string[] perms = OxideLibrary.Instance.Permission.GetPermissions(); - AddList(perms.Except(OxideLibrary.Instance.Permission.GetGroupPermissions(group)), filter, comparison, search); - } + /// + /// Adds a List of Permissions that are not in a given group + /// + /// Group that doesn't have the permissions + /// Permission filter + /// to use + /// Filter search mode + public void AddPermissionsNotInGroup(string group, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + string[] perms = OxideLibrary.Instance.Permission.GetPermissions(); + AddList(perms.Except(OxideLibrary.Instance.Permission.GetGroupPermissions(group)), filter, comparison, search); + } - /// - /// Adds The List of Groups that playerId has - /// - /// Player ID to get groups for - /// String to filter by - /// to use - /// Filter search mode - public void AddGroupsWithPlayer(string playerId, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - AddList(OxideLibrary.Instance.Permission.GetUserGroups(playerId), filter, comparison, search); - } + /// + /// Adds The List of Groups that playerId has + /// + /// Player ID to get groups for + /// String to filter by + /// to use + /// Filter search mode + public void AddGroupsWithPlayer(string playerId, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + AddList(OxideLibrary.Instance.Permission.GetUserGroups(playerId), filter, comparison, search); + } - /// - /// Adds The List of Groups that playerId has - /// - /// Player ID to get groups for - /// String to filter by - /// to use - /// Filter search mode - public void AddGroupsWithoutPlayer(string playerId, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - string[] groups = OxideLibrary.Instance.Permission.GetGroups(); - AddList(groups.Except(OxideLibrary.Instance.Permission.GetUserGroups(playerId)), filter, comparison, search); - } + /// + /// Adds The List of Groups that playerId has + /// + /// Player ID to get groups for + /// String to filter by + /// to use + /// Filter search mode + public void AddGroupsWithoutPlayer(string playerId, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + string[] groups = OxideLibrary.Instance.Permission.GetGroups(); + AddList(groups.Except(OxideLibrary.Instance.Permission.GetUserGroups(playerId)), filter, comparison, search); + } - /// - /// Adds The List of Permissions that playerId has - /// - /// Player ID to get permissions for - /// String to filter by - /// to use - /// Filter search mode - public void AddPermissionsPlayerIn(string playerId, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - AddList(OxideLibrary.Instance.Permission.GetUserPermissions(playerId), filter, comparison, search); - } + /// + /// Adds The List of Permissions that playerId has + /// + /// Player ID to get permissions for + /// String to filter by + /// to use + /// Filter search mode + public void AddPermissionsPlayerIn(string playerId, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + AddList(OxideLibrary.Instance.Permission.GetUserPermissions(playerId), filter, comparison, search); + } - /// - /// Adds The List of Permissions that playerId does not have - /// - /// Player ID to get permissions for - /// String to filter by - /// to use - /// Filter search mode - public void AddPermissionsPlayerNotIn(string playerId, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - string[] perms = OxideLibrary.Instance.Permission.GetPermissions(); - AddList(perms.Except(OxideLibrary.Instance.Permission.GetUserPermissions(playerId)), filter, comparison, search); - } + /// + /// Adds The List of Permissions that playerId does not have + /// + /// Player ID to get permissions for + /// String to filter by + /// to use + /// Filter search mode + public void AddPermissionsPlayerNotIn(string playerId, string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + string[] perms = OxideLibrary.Instance.Permission.GetPermissions(); + AddList(perms.Except(OxideLibrary.Instance.Permission.GetUserPermissions(playerId)), filter, comparison, search); + } - /// - /// Adds Online Players to the list - /// - /// String to filter by - /// Formatter for the player name - public void AddOnlinePlayers(string filter = null, PlayerNameFormatter formatter = null) - { - AddPlayerList(ServerPlayerCache.Instance.GetOnlinePlayers(filter), formatter ?? PlayerNameFormatter.Default, null); - } + /// + /// Adds Online Players to the list + /// + /// String to filter by + /// Formatter for the player name + public void AddOnlinePlayers(string filter = null, PlayerNameFormatter formatter = null) + { + AddPlayerList(ServerPlayerCache.Instance.GetOnlinePlayers(filter), formatter ?? PlayerNameFormatter.Default, null); + } - /// - /// Adds Online Players to the list - /// - /// String to filter by - /// Formatter for the player name - public void AddOfflinePlayers(string filter = null, PlayerNameFormatter formatter = null) - { - AddPlayerList(ServerPlayerCache.Instance.GetAllPlayers(filter).Where(p => !p.IsConnected), formatter ?? PlayerNameFormatter.Default, null); - } + /// + /// Adds Online Players to the list + /// + /// String to filter by + /// Formatter for the player name + public void AddOfflinePlayers(string filter = null, PlayerNameFormatter formatter = null) + { + AddPlayerList(ServerPlayerCache.Instance.GetAllPlayers(filter).Where(p => !p.IsConnected), formatter ?? PlayerNameFormatter.Default, null); + } - /// - /// Adds Online Players to the list first - /// If there is still space add Offline Players - /// - /// String to filter by - /// Formatter for the player name - public void AddAllOnlineFirstPlayers(string filter = null, PlayerNameFormatter formatter = null) - { - HashSet addedList = DiscordPool.Internal.GetHashSet(); - AddPlayerList(ServerPlayerCache.Instance.GetOnlinePlayers(filter), formatter ?? PlayerNameFormatter.Default, addedList); - AddPlayerList(ServerPlayerCache.Instance.GetAllPlayers(filter), formatter ?? PlayerNameFormatter.Default, addedList); - DiscordPool.Internal.FreeHashSet(addedList); - } + /// + /// Adds Online Players to the list first + /// If there is still space add Offline Players + /// + /// String to filter by + /// Formatter for the player name + public void AddAllOnlineFirstPlayers(string filter = null, PlayerNameFormatter formatter = null) + { + HashSet addedList = DiscordPool.Internal.GetHashSet(); + AddPlayerList(ServerPlayerCache.Instance.GetOnlinePlayers(filter), formatter ?? PlayerNameFormatter.Default, addedList); + AddPlayerList(ServerPlayerCache.Instance.GetAllPlayers(filter), formatter ?? PlayerNameFormatter.Default, addedList); + DiscordPool.Internal.FreeHashSet(addedList); + } - /// - /// Adds Any Player to the list - /// - /// String to filter by - /// Formatter for the player name - public void AddAllPlayers(string filter = null, PlayerNameFormatter formatter = null) - { - AddPlayerList(ServerPlayerCache.Instance.GetAllPlayers(filter), formatter ?? PlayerNameFormatter.Default, null); - } + /// + /// Adds Any Player to the list + /// + /// String to filter by + /// Formatter for the player name + public void AddAllPlayers(string filter = null, PlayerNameFormatter formatter = null) + { + AddPlayerList(ServerPlayerCache.Instance.GetAllPlayers(filter), formatter ?? PlayerNameFormatter.Default, null); + } - /// - /// Add a custom list of players that are filtered by player name or player ID - /// - /// Filter to filter by - /// Custom list of players - /// Formatter for the player name - /// List of already added players - /// Mode to match on player name - public void AddPlayerList(string filter, IEnumerable list, PlayerNameFormatter formatter, HashSet addedList = null, AutoCompleteSearchMode search = AutoCompleteSearchMode.Contains) + /// + /// Add a custom list of players that are filtered by player name or player ID + /// + /// Filter to filter by + /// Custom list of players + /// Formatter for the player name + /// List of already added players + /// Mode to match on player name + public void AddPlayerList(string filter, IEnumerable list, PlayerNameFormatter formatter, HashSet addedList = null, AutoCompleteSearchMode search = AutoCompleteSearchMode.Contains) + { + if (!CanAddChoice()) { - if (!CanAddChoice()) - { - return; - } + return; + } - foreach (IPlayer player in list) + foreach (IPlayer player in list) + { + if (!IsMatch(player.Name, filter, StringComparison.OrdinalIgnoreCase, search) && player.Id != filter) { - if (!IsMatch(player.Name, filter, StringComparison.OrdinalIgnoreCase, search) && player.Id != filter) - { - continue; - } - - if (!AddPlayer(player, formatter, addedList)) - { - return; - } + continue; } - } - /// - /// Adds a player by player Id to the list - /// - /// Player ID to add - /// Formatter for the player name - public void AddByPlayerId(string playerId, PlayerNameFormatter formatter = null) - { - IPlayer player = ServerPlayerCache.Instance.GetPlayerById(playerId); - if (player != null) + if (!AddPlayer(player, formatter, addedList)) { - AddPlayer(player, formatter ?? PlayerNameFormatter.Default, null); + return; } } + } - /// - /// Adds a list of plugins that can be loaded - /// - /// String to filter by - /// to use - /// Filter search mode - public void AddLoadablePlugins(string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + /// + /// Adds a player by player ID to the list + /// + /// Player ID to add + /// Formatter for the player name + public void AddByPlayerId(string playerId, PlayerNameFormatter formatter = null) + { + IPlayer player = ServerPlayerCache.Instance.GetPlayerById(playerId); + if (player != null) { - AddList(DiscordPluginCache.Instance.GetLoadablePlugins(), filter, comparison, search); + AddPlayer(player, formatter ?? PlayerNameFormatter.Default, null); } + } - /// - /// Adds a list of plugins that are currently loaded - /// - /// String to filter by - /// to use - /// Filter search mode - public void AddLoadedPlugins(string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) - { - AddList(DiscordPluginCache.Instance.GetLoadedPlugins(), filter, comparison, search); - } + /// + /// Adds a list of plugins that can be loaded + /// + /// String to filter by + /// to use + /// Filter search mode + public void AddLoadablePlugins(string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + AddList(DiscordPluginCache.Instance.GetLoadablePlugins(), filter, comparison, search); + } - private void AddList(IEnumerable list, string filter, StringComparison comparison, AutoCompleteSearchMode search) + /// + /// Adds a list of plugins that are currently loaded + /// + /// String to filter by + /// to use + /// Filter search mode + public void AddLoadedPlugins(string filter = null, StringComparison comparison = StringComparison.OrdinalIgnoreCase, AutoCompleteSearchMode search = AutoCompleteSearchMode.StartsWith) + { + AddList(DiscordPluginCache.Instance.GetLoadedPlugins(), filter, comparison, search); + } + + private void AddList(IEnumerable list, string filter, StringComparison comparison, AutoCompleteSearchMode search) + { + if (!CanAddChoice()) { - if (!CanAddChoice()) - { - return; - } + return; + } - List choices = _message.Choices; - foreach (string value in list) + List choices = _message.Choices; + foreach (string value in list) + { + if (IsMatch(value, filter, comparison, search)) { - if (IsMatch(value, filter, comparison, search)) + choices.Add(new CommandOptionChoice(value, value)); + if (!CanAddChoice()) { - choices.Add(new CommandOptionChoice(value, value)); - if (!CanAddChoice()) - { - return; - } + return; } } } + } - /// - /// Adds a list of players from a custom list - /// - /// Custom list of players - /// Formatter for the player name - /// List of already added players - public void AddPlayerList(IEnumerable list, PlayerNameFormatter formatter, HashSet addedList) + /// + /// Adds a list of players from a custom list + /// + /// Custom list of players + /// Formatter for the player name + /// List of already added players + public void AddPlayerList(IEnumerable list, PlayerNameFormatter formatter, HashSet addedList) + { + if (!CanAddChoice()) { - if (!CanAddChoice()) - { - return; - } + return; + } - foreach (IPlayer player in list) + foreach (IPlayer player in list) + { + if (!AddPlayer(player, formatter, addedList)) { - if (!AddPlayer(player, formatter, addedList)) - { - return; - } + return; } } + } - private bool AddPlayer(IPlayer player, PlayerNameFormatter formatter, HashSet addedList) + private bool AddPlayer(IPlayer player, PlayerNameFormatter formatter, HashSet addedList) + { + if (!CanAddChoice()) { + return false; + } + + string name = formatter.Format(player); + if (addedList == null || addedList.Add(player.Id)) + { + _message.Choices.Add(new CommandOptionChoice(name, player.Id)); if (!CanAddChoice()) { return false; } + } - string name = formatter.Format(player); - if (addedList == null || addedList.Add(player.Id)) - { - _message.Choices.Add(new CommandOptionChoice(name, player.Id)); - if (!CanAddChoice()) - { - return false; - } - } - + return true; + } + + private static bool IsMatch(string value, string filter, StringComparison comparison, AutoCompleteSearchMode search) + { + if (string.IsNullOrEmpty(filter)) + { return true; } - private static bool IsMatch(string value, string filter, StringComparison comparison, AutoCompleteSearchMode search) + return search switch { - if (string.IsNullOrEmpty(filter)) - { - return true; - } - - switch (search) - { - case AutoCompleteSearchMode.StartsWith: - return value.StartsWith(filter, comparison); - case AutoCompleteSearchMode.Contains: - return value.IndexOf(filter, comparison) != -1; - case AutoCompleteSearchMode.EndsWith: - return value.EndsWith(filter, comparison); - default: - throw new ArgumentOutOfRangeException(nameof(search), search, null); - } - } - #endregion + AutoCompleteSearchMode.StartsWith => value.StartsWith(filter, comparison), + AutoCompleteSearchMode.Contains => value.IndexOf(filter, comparison) != -1, + AutoCompleteSearchMode.EndsWith => value.EndsWith(filter, comparison), + _ => throw new ArgumentOutOfRangeException(nameof(search), search, null) + }; } + #endregion } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Interactions/InteractionFollowupBuilder.cs b/Oxide.Ext.Discord/Builders/Interactions/InteractionFollowupBuilder.cs index 559997a4e..8418f4566 100644 --- a/Oxide.Ext.Discord/Builders/Interactions/InteractionFollowupBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Interactions/InteractionFollowupBuilder.cs @@ -1,23 +1,22 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Represents a builder for +/// +public class InteractionFollowupBuilder : BaseInteractionMessageBuilder { /// - /// Represents a builder for + /// Constructor for creating a new CommandFollowupCreate /// - public class InteractionFollowupBuilder : BaseInteractionMessageBuilder - { - /// - /// Constructor for creating a new CommandFollowupCreate - /// - /// Interaction this followup is for - public InteractionFollowupBuilder(DiscordInteraction interaction) : this(interaction, new CommandFollowupCreate()) { } + /// Interaction this followup is for + public InteractionFollowupBuilder(DiscordInteraction interaction) : this(interaction, new CommandFollowupCreate()) { } - /// - /// Constructor for using an existing CommandFollowupCreate - /// - /// Interaction this followup is for - /// Message to use - public InteractionFollowupBuilder(DiscordInteraction interaction, CommandFollowupCreate message) : base(interaction, message) { } - } + /// + /// Constructor for using an existing CommandFollowupCreate + /// + /// Interaction this followup is for + /// Message to use + public InteractionFollowupBuilder(DiscordInteraction interaction, CommandFollowupCreate message) : base(interaction, message) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Interactions/InteractionModalBuilder.cs b/Oxide.Ext.Discord/Builders/Interactions/InteractionModalBuilder.cs index c71d7238a..fafe5151d 100644 --- a/Oxide.Ext.Discord/Builders/Interactions/InteractionModalBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Interactions/InteractionModalBuilder.cs @@ -1,108 +1,103 @@ -using System.Collections.Generic; using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Builds a Modal Interaction Response Message +/// +public class InteractionModalBuilder { + private readonly InteractionModalMessage _message; + /// - /// Builds a Modal Interaction Response Message + /// Constructor /// - public class InteractionModalBuilder - { - private readonly InteractionModalMessage _message; - - /// - /// Constructor - /// - /// Interaction this build is for - public InteractionModalBuilder(DiscordInteraction interaction) : this(interaction, new InteractionModalMessage()) { } + /// Interaction this build is for + public InteractionModalBuilder(DiscordInteraction interaction) : this(interaction, new InteractionModalMessage()) { } - /// - /// Constructor - /// - /// Interaction this build is for - /// Starting - public InteractionModalBuilder(DiscordInteraction interaction, InteractionModalMessage message) - { - InteractionResponseBuilderException.ThrowIfInteractionIsAutoComplete(interaction.Type); - InteractionResponseBuilderException.ThrowIfInteractionIsModalSubmit(interaction.Type); - _message = message; - if (_message.Components == null) - { - _message.Components = new List(); - } - } + /// + /// Constructor + /// + /// Interaction this build is for + /// Starting + public InteractionModalBuilder(DiscordInteraction interaction, InteractionModalMessage message) + { + InteractionResponseBuilderException.ThrowIfInteractionIsAutoComplete(interaction.Type); + InteractionResponseBuilderException.ThrowIfInteractionIsModalSubmit(interaction.Type); + _message = message; + _message.Components ??= []; + } - /// - /// Adds a custom ID for the modal - /// - /// Custom ID for the modal - public InteractionModalBuilder AddModalCustomId(string customId) - { - InvalidMessageComponentException.ThrowIfInvalidCustomId(customId); - _message.CustomId = customId; - return this; - } + /// + /// Adds a custom ID for the modal + /// + /// Custom ID for the modal + public InteractionModalBuilder AddModalCustomId(string customId) + { + InvalidMessageComponentException.ThrowIfInvalidCustomId(customId); + _message.CustomId = customId; + return this; + } - /// - /// Adds a custom ID for the modal - /// - /// Title for the Modal - public InteractionModalBuilder AddModalTitle(string title) - { - InvalidMessageComponentException.ThrowIfInvalidModalTitle(title); - _message.Title = title; - return this; - } + /// + /// Adds a custom ID for the modal + /// + /// Title for the Modal + public InteractionModalBuilder AddModalTitle(string title) + { + InvalidMessageComponentException.ThrowIfInvalidModalTitle(title); + _message.Title = title; + return this; + } - /// - /// Adds a select menu to a new action row - /// - /// Unique ID for the select menu - /// Label for the input text - /// Style of the Input Text - /// Default value for the Input Text - /// Is the Input Text Required to be filled out - /// Text to display if no value is selected yet - /// The min number of options you must select - /// The max number of options you can select - /// - public InteractionModalBuilder AddInputText(string customId, string label, InputTextStyles style, string value = null, bool? required = null, string placeholder = null, int? minLength = null, int? maxLength = null) - { - InvalidMessageComponentException.ThrowIfInvalidCustomId(customId); - InvalidMessageComponentException.ThrowIfInvalidTextInputLabel(label); - InvalidMessageComponentException.ThrowIfInvalidTextInputValue(value); - InvalidMessageComponentException.ThrowIfInvalidTextInputLength(minLength, maxLength); - InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(_message.Components.Count); + /// + /// Adds a select menu to a new action row + /// + /// Unique ID for the select menu + /// Label for the input text + /// Style of the Input Text + /// Default value for the Input Text + /// Is the Input Text Required to be filled out + /// Text to display if no value is selected yet + /// The min number of options you must select + /// The max number of options you can select + /// + public InteractionModalBuilder AddInputText(string customId, string label, InputTextStyles style, string value = null, bool? required = null, string placeholder = null, int? minLength = null, int? maxLength = null) + { + InvalidMessageComponentException.ThrowIfInvalidCustomId(customId); + InvalidMessageComponentException.ThrowIfInvalidTextInputLabel(label); + InvalidMessageComponentException.ThrowIfInvalidTextInputValue(value); + InvalidMessageComponentException.ThrowIfInvalidTextInputLength(minLength, maxLength); + InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(_message.Components.Count); - _message.Components.Add(new ActionRowComponent + _message.Components.Add(new ActionRowComponent + { + Components = { - Components = + new InputTextComponent { - new InputTextComponent - { - CustomId = customId, - Label = label, - Style = style, - Value = value, - Required = required, - Placeholder = placeholder, - MinLength = minLength, - MaxLength = maxLength, - } + CustomId = customId, + Label = label, + Style = style, + Value = value, + Required = required, + Placeholder = placeholder, + MinLength = minLength, + MaxLength = maxLength, } - }); + } + }); - return this; - } + return this; + } - /// - /// Returns a built Modal Response Message - /// - /// - public InteractionModalMessage Build() - { - return _message; - } + /// + /// Returns a built Modal Response Message + /// + /// + public InteractionModalMessage Build() + { + return _message; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Interactions/InteractionResponseBuilder.cs b/Oxide.Ext.Discord/Builders/Interactions/InteractionResponseBuilder.cs index 9ebc8a70e..24bfa020e 100644 --- a/Oxide.Ext.Discord/Builders/Interactions/InteractionResponseBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Interactions/InteractionResponseBuilder.cs @@ -1,23 +1,22 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Represents a builder for +/// +public class InteractionResponseBuilder : BaseInteractionMessageBuilder { /// - /// Represents a builder for + /// Constructor for creating a new InteractionCallbackData /// - public class InteractionResponseBuilder : BaseInteractionMessageBuilder - { - /// - /// Constructor for creating a new InteractionCallbackData - /// - /// Interaction this followup is for - public InteractionResponseBuilder(DiscordInteraction interaction) : this(interaction, new InteractionCallbackData()) { } + /// Interaction this followup is for + public InteractionResponseBuilder(DiscordInteraction interaction) : this(interaction, new InteractionCallbackData()) { } - /// - /// Constructor for using an existing InteractionCallbackData - /// - /// Interaction this followup is for - /// Message to use - public InteractionResponseBuilder(DiscordInteraction interaction, InteractionCallbackData message) : base(interaction, message) { } - } + /// + /// Constructor for using an existing InteractionCallbackData + /// + /// Interaction this followup is for + /// Message to use + public InteractionResponseBuilder(DiscordInteraction interaction, InteractionCallbackData message) : base(interaction, message) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/MessageComponents/MessageComponentBuilder.cs b/Oxide.Ext.Discord/Builders/MessageComponents/MessageComponentBuilder.cs index 2c31e382b..21a1b7d1c 100644 --- a/Oxide.Ext.Discord/Builders/MessageComponents/MessageComponentBuilder.cs +++ b/Oxide.Ext.Discord/Builders/MessageComponents/MessageComponentBuilder.cs @@ -3,212 +3,194 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Builder for Message Components +/// +public class MessageComponentBuilder { + private readonly List _components = new(); + private ActionRowComponent _current; + /// - /// Builder for Message Components + /// Creates a new MessageComponentBuilder /// - public class MessageComponentBuilder + public MessageComponentBuilder() { - private readonly List _components = new List(); - private ActionRowComponent _current; - - /// - /// Creates a new MessageComponentBuilder - /// - public MessageComponentBuilder() - { - _current = new ActionRowComponent(); - _components.Add(_current); - } + _current = new ActionRowComponent(); + _components.Add(_current); + } - /// - /// Adds an action button to the current action row - /// - /// Button Style Button Styles - /// The text of the button - /// The unique id of the button. Used to identify which button was clicked - /// If this button is disabled - /// Should the button be added to a new row - /// Emoji to display with the button - /// - /// - /// Throw if the button style is link or if the button goes outside the max number of action rows - /// - public MessageComponentBuilder AddActionButton(ButtonStyle style, string label, string customId, bool disabled = false, bool addToNewRow = false, DiscordEmoji emoji = null) - { - InvalidMessageComponentException.ThrowIfInvalidButtonLabel(label); - MessageComponentBuilderException.ThrowIfInvalidActionButtonStyle(style); - InvalidMessageComponentException.ThrowIfInvalidCustomId(customId); + /// + /// Adds an action button to the current action row + /// + /// Button Style Button Styles + /// The text of the button + /// The unique id of the button. Used to identify which button was clicked + /// If this button is disabled + /// Should the button be added to a new row + /// Emoji to display with the button + /// + /// + /// Throw if the button style is a link or if the button goes outside the max number of action rows + /// + public MessageComponentBuilder AddActionButton(ButtonStyle style, string label, string customId, bool disabled = false, bool addToNewRow = false, DiscordEmoji emoji = null) + { + InvalidMessageComponentException.ThrowIfInvalidButtonLabel(label); + MessageComponentBuilderException.ThrowIfInvalidActionButtonStyle(style); + InvalidMessageComponentException.ThrowIfInvalidCustomId(customId); - UpdateActionRow(addToNewRow); - _current.Components.Add(new ButtonComponent - { - Style = style, - Label = label, - CustomId = customId, - Disabled = disabled, - Emoji = emoji - }); - return this; - } - - /// - /// Adds a dummy button that doesn't do anything - /// - /// The text of the button - /// If this button is disabled - /// - /// Throw if the button goes outside the max number of action rows - public MessageComponentBuilder AddDummyButton(string label, bool disabled = true) + UpdateActionRow(addToNewRow); + _current.Components.Add(new ButtonComponent { - return AddActionButton(ButtonStyle.Secondary, label, $"DUMMY_{_components.Count * 5 + _current.Components.Count}", disabled); - } + Style = style, + Label = label, + CustomId = customId, + Disabled = disabled, + Emoji = emoji + }); + return this; + } + + /// + /// Adds a dummy button that doesn't do anything + /// + /// The text of the button + /// If this button is disabled + /// + /// Throw if the button goes outside the max number of action rows + public MessageComponentBuilder AddDummyButton(string label, bool disabled = true) + { + return AddActionButton(ButtonStyle.Secondary, label, $"DUMMY_{_components.Count * 5 + _current.Components.Count}", disabled); + } - /// - /// Adds a link button to the current action row - /// - /// Text on the button - /// URL for the button - /// if the button should be disabled - /// Show the button be added to a new row - /// Emoji to display on the button - /// - /// Thrown if the button goes outside the max number of action rows - public MessageComponentBuilder AddLinkButton(string label, string url, bool disabled = false, bool addToNewRow = false, DiscordEmoji emoji = null) - { - InvalidMessageComponentException.ThrowIfInvalidButtonUrl(url); + /// + /// Adds a link button to the current action row + /// + /// Text on the button + /// URL for the button + /// if the button should be disabled + /// Show the button be added to a new row + /// Emoji to display on the button + /// + /// Thrown if the button goes outside the max number of action rows + public MessageComponentBuilder AddLinkButton(string label, string url, bool disabled = false, bool addToNewRow = false, DiscordEmoji emoji = null) + { + InvalidMessageComponentException.ThrowIfInvalidButtonUrl(url); - UpdateActionRow(addToNewRow); - _current.Components.Add(new ButtonComponent - { - Style = ButtonStyle.Link, - Label = label, - Url = url, - Disabled = disabled, - Emoji = emoji - }); - return this; - } - - /// - /// Adds a select menu to a new action row - /// - /// Select Menu Message Component Type - /// Unique ID for the select menu - /// Text to display if no value is selected yet - /// The min number of options you must select - /// The max number of options you can select - /// If the select menu should be disabled - /// - public SelectMenuComponentBuilder AddSelectMenu(MessageComponentType type, string customId, string placeholder, int minValues = 1, int maxValues = 1, bool disabled = false) + UpdateActionRow(addToNewRow); + _current.Components.Add(new ButtonComponent { - InvalidMessageComponentException.ThrowIfInvalidCustomId(customId); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuPlaceholder(placeholder); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuMinValues(minValues); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuMaxValues(maxValues); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuValueRange(minValues, maxValues); - - UpdateActionRow(false); + Style = ButtonStyle.Link, + Label = label, + Url = url, + Disabled = disabled, + Emoji = emoji + }); + return this; + } - BaseSelectMenuComponent select; - switch (type) - { - case MessageComponentType.StringSelect: - select = new StringSelectComponent(); - break; - - case MessageComponentType.UserSelect: - select = new UserSelectComponent(); - break; - - case MessageComponentType.RoleSelect: - select = new RoleSelectComponent(); - break; - - case MessageComponentType.MentionableSelect: - select = new MentionableSelectComponent(); - break; - - case MessageComponentType.ChannelSelect: - select = new ChannelSelectComponent(); - break; - - default: - throw new ArgumentOutOfRangeException(nameof(type), type, null); - } - - select.CustomId = customId; - select.Placeholder = placeholder; - select.MinValues = minValues; - select.MaxValues = maxValues; - select.Disabled = disabled; + /// + /// Adds a select menu to a new action row + /// + /// Select Menu Message Component Type + /// Unique ID for the select menu + /// Text to display if no value is selected yet + /// The min number of options you must select + /// The max number of options you can select + /// If the select menu should be disabled + /// + public SelectMenuComponentBuilder AddSelectMenu(MessageComponentType type, string customId, string placeholder, int minValues = 1, int maxValues = 1, bool disabled = false) + { + InvalidMessageComponentException.ThrowIfInvalidCustomId(customId); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuPlaceholder(placeholder); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuMinValues(minValues); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuMaxValues(maxValues); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuValueRange(minValues, maxValues); - _current.Components.Add(select); - return new SelectMenuComponentBuilder(select, this); - } + UpdateActionRow(false); - /// - /// Adds a select menu to a new action row - /// - /// Unique ID for the select menu - /// Label for the input text - /// Style of the Input Text - /// Default value for the Input Text - /// Is the Input Text Required to be filled out - /// Text to display if no value is selected yet - /// The min number of options you must select - /// The max number of options you can select - /// - public MessageComponentBuilder AddInputText(string customId, string label, InputTextStyles style, string value = null, bool? required = null, string placeholder = null, int? minLength = null, int? maxLength = null) + BaseSelectMenuComponent select = type switch { - InvalidMessageComponentException.ThrowIfInvalidCustomId(customId); - InvalidMessageComponentException.ThrowIfInvalidTextInputLabel(label); - InvalidMessageComponentException.ThrowIfInvalidTextInputValue(value); - InvalidMessageComponentException.ThrowIfInvalidTextInputLength(minLength, maxLength); + MessageComponentType.StringSelect => new StringSelectComponent(), + MessageComponentType.UserSelect => new UserSelectComponent(), + MessageComponentType.RoleSelect => new RoleSelectComponent(), + MessageComponentType.MentionableSelect => new MentionableSelectComponent(), + MessageComponentType.ChannelSelect => new ChannelSelectComponent(), + _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) + }; - UpdateActionRow(false); - InputTextComponent menu = new InputTextComponent - { - CustomId = customId, - Label = label, - Style = style, - Value = value, - Required = required, - Placeholder = placeholder, - MinLength = minLength, - MaxLength = maxLength, - }; - _current.Components.Add(menu); - return this; - } + select.CustomId = customId; + select.Placeholder = placeholder; + select.MinValues = minValues; + select.MaxValues = maxValues; + select.Disabled = disabled; + + _current.Components.Add(select); + return new SelectMenuComponentBuilder(select, this); + } - private void UpdateActionRow(bool forceRow) where T : BaseComponent - { - if (_current.Components.Count == 0) - { - return; - } + /// + /// Adds a select menu to a new action row + /// + /// Unique ID for the select menu + /// Label for the input text + /// Style of the Input Text + /// Default value for the Input Text + /// Is the Input Text Required to be filled out + /// Text to display if no value is selected yet + /// The min number of options you must select + /// The max number of options you can select + /// + public MessageComponentBuilder AddInputText(string customId, string label, InputTextStyles style, string value = null, bool? required = null, string placeholder = null, int? minLength = null, int? maxLength = null) + { + InvalidMessageComponentException.ThrowIfInvalidCustomId(customId); + InvalidMessageComponentException.ThrowIfInvalidTextInputLabel(label); + InvalidMessageComponentException.ThrowIfInvalidTextInputValue(value); + InvalidMessageComponentException.ThrowIfInvalidTextInputLength(minLength, maxLength); - //5 buttons allowed per row - if (!forceRow && typeof(T) == typeof(ButtonComponent) && _current.Components.Count < 5) - { - return; - } + UpdateActionRow(false); + InputTextComponent menu = new() + { + CustomId = customId, + Label = label, + Style = style, + Value = value, + Required = required, + Placeholder = placeholder, + MinLength = minLength, + MaxLength = maxLength, + }; + _current.Components.Add(menu); + return this; + } - //All other components are only 1 per action row so add a new row. - _current = new ActionRowComponent(); - _components.Add(_current); - InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(_components.Count); + private void UpdateActionRow(bool forceRow) where T : BaseComponent + { + if (_current.Components.Count == 0) + { + return; } - /// - /// Returns the built action rows - /// - /// - public List Build() + //5 buttons allowed per row + if (!forceRow && typeof(T) == typeof(ButtonComponent) && _current.Components.Count < 5) { - return _components; + return; } + + //All other components are only 1 per action row, so add a new row. + _current = new ActionRowComponent(); + _components.Add(_current); + InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(_components.Count); + } + + /// + /// Returns the built action rows + /// + /// + public List Build() + { + return _components; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/MessageComponents/SelectMenuComponentBuilder.cs b/Oxide.Ext.Discord/Builders/MessageComponents/SelectMenuComponentBuilder.cs index a6672722a..fa8d61130 100644 --- a/Oxide.Ext.Discord/Builders/MessageComponents/SelectMenuComponentBuilder.cs +++ b/Oxide.Ext.Discord/Builders/MessageComponents/SelectMenuComponentBuilder.cs @@ -1,105 +1,100 @@ using System; -using System.Collections.Generic; using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Builder for Select Menus +/// +public class SelectMenuComponentBuilder { + private readonly BaseSelectMenuComponent _menu; + private readonly MessageComponentBuilder _builder; + + internal SelectMenuComponentBuilder(BaseSelectMenuComponent menu, MessageComponentBuilder builder) + { + _menu = menu; + _builder = builder; + } + /// - /// Builder for Select Menus + /// Adds an option to a select menu; /// - public class SelectMenuComponentBuilder + /// Display text for the select option + /// Selected value for the select option + /// Description of the select option + /// Default selected option + /// Emoji to display with the option + /// Throw is more than 25 options are added + public SelectMenuComponentBuilder AddOption(string label, string value, string description, bool @default = false, DiscordEmoji emoji = null) { - private readonly BaseSelectMenuComponent _menu; - private readonly MessageComponentBuilder _builder; - - internal SelectMenuComponentBuilder(BaseSelectMenuComponent menu, MessageComponentBuilder builder) - { - _menu = menu; - _builder = builder; - } + InvalidSelectMenuComponentException.ThrowIfTypeCantAddOptions(_menu.Type); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionLabel(label); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionValue(value); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionDescription(description); - /// - /// Adds an option to a select menu; - /// - /// Display text for the select option - /// Selected value for the select option - /// Description of the select option - /// Default selected option - /// Emoji to display with the option - /// Throw is more than 25 options are added - public SelectMenuComponentBuilder AddOption(string label, string value, string description, bool @default = false, DiscordEmoji emoji = null) - { - InvalidSelectMenuComponentException.ThrowIfTypeCantAddOptions(_menu.Type); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionLabel(label); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionValue(value); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionDescription(description); - - StringSelectComponent text = (StringSelectComponent)_menu; + StringSelectComponent text = (StringSelectComponent)_menu; - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionCount(text.Options.Count); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionCount(text.Options.Count); - text.Options.Add(new SelectMenuOption - { - Label = label, - Value = value, - Description = description, - Default = @default, - Emoji = emoji - }); - return this; - } - - /// - /// Adds an allow channel type for - /// - /// Channel Type to add - /// This - public SelectMenuComponentBuilder AddChannelType(ChannelType type) + text.Options.Add(new SelectMenuOption { - InvalidSelectMenuComponentException.ThrowIfTypeCantAddChannelTypes(_menu.Type); + Label = label, + Value = value, + Description = description, + Default = @default, + Emoji = emoji + }); + return this; + } + + /// + /// Adds an allow channel type for + /// + /// Channel Type to add + /// This + public SelectMenuComponentBuilder AddChannelType(ChannelType type) + { + InvalidSelectMenuComponentException.ThrowIfTypeCantAddChannelTypes(_menu.Type); - ChannelSelectComponent text = (ChannelSelectComponent)_menu; - text.ChannelTypes.Add(type); - return this; - } + ChannelSelectComponent text = (ChannelSelectComponent)_menu; + text.ChannelTypes.Add(type); + return this; + } - /// - /// Adds an allow channel type for - /// - /// ID of the default value to add - /// This - public SelectMenuComponentBuilder AddDefaultValue(Snowflake id) - { - InvalidSelectMenuComponentException.ThrowIfCantAddDefaultValue(_menu.Type); - if (_menu.DefaultValues == null) - { - _menu.DefaultValues = new List(); - } - - switch (_menu.Type) - { - case MessageComponentType.UserSelect: - _menu.DefaultValues.Add(new SelectMenuDefaultValue(id, SelectMenuDefaultValueType.User)); - break; - case MessageComponentType.RoleSelect: - _menu.DefaultValues.Add(new SelectMenuDefaultValue(id, SelectMenuDefaultValueType.Role)); - break; - case MessageComponentType.ChannelSelect: - _menu.DefaultValues.Add(new SelectMenuDefaultValue(id, SelectMenuDefaultValueType.Channel)); - break; - } + /// + /// Adds an allow channel type for + /// + /// ID of the default value to add + /// This + public SelectMenuComponentBuilder AddDefaultValue(Snowflake id) + { + InvalidSelectMenuComponentException.ThrowIfCantAddDefaultValue(_menu.Type); + _menu.DefaultValues ??= []; - return this; - } - - /// - /// Returns the root builder - /// - /// - public MessageComponentBuilder Build() + switch (_menu.Type) { - return _builder; + case MessageComponentType.UserSelect: + _menu.DefaultValues.Add(new SelectMenuDefaultValue(id, SelectMenuDefaultValueType.User)); + break; + case MessageComponentType.RoleSelect: + _menu.DefaultValues.Add(new SelectMenuDefaultValue(id, SelectMenuDefaultValueType.Role)); + break; + case MessageComponentType.ChannelSelect: + _menu.DefaultValues.Add(new SelectMenuDefaultValue(id, SelectMenuDefaultValueType.Channel)); + break; } + + return this; + } + + /// + /// Returns the root builder + /// + /// + public MessageComponentBuilder Build() + { + return _builder; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseChannelMessageBuilder.cs b/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseChannelMessageBuilder.cs index 3931c9a2e..aed8a50a5 100644 --- a/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseChannelMessageBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseChannelMessageBuilder.cs @@ -4,139 +4,130 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Represents a builder for +/// +/// Type of the message +/// Type of the builder +public abstract class BaseChannelMessageBuilder : BaseMessageBuilder + where TMessage : MessageCreate + where TBuilder : BaseChannelMessageBuilder { /// - /// Represents a builder for + /// Constructor /// - /// Type of the message - /// Type of the builder - public abstract class BaseChannelMessageBuilder : BaseMessageBuilder - where TMessage : MessageCreate - where TBuilder : BaseChannelMessageBuilder - { - /// - /// Constructor - /// - /// Message being created - protected BaseChannelMessageBuilder(TMessage message) : base(message) { } + /// Message being created + protected BaseChannelMessageBuilder(TMessage message) : base(message) { } - /// - /// Adds a sticker to the message - /// - /// Sticker ID to be added - /// This - public TBuilder AddSticker(Snowflake stickerId) - { - InvalidSnowflakeException.ThrowIfInvalid(stickerId, nameof(stickerId)); - if (Message.StickerIds == null) - { - Message.StickerIds = new List(); - } - - InvalidMessageException.ThrowIfMaxStickers(Message.StickerIds.Count + 1); - Message.StickerIds.Add(stickerId); - return Builder; - } + /// + /// Adds a sticker to the message + /// + /// Sticker ID to be added + /// This + public TBuilder AddSticker(Snowflake stickerId) + { + InvalidSnowflakeException.ThrowIfInvalid(stickerId); + Message.StickerIds ??= new List(); + InvalidMessageException.ThrowIfMaxStickers(Message.StickerIds.Count + 1); + Message.StickerIds.Add(stickerId); + return Builder; + } - /// - /// Adds stickers to the message - /// - /// Sticker ID's to be added - /// This - public TBuilder AddStickers(ICollection stickerIds) - { - if (stickerIds == null) throw new ArgumentNullException(nameof(stickerIds)); - InvalidSnowflakeException.ThrowIfInvalid(stickerIds, nameof(stickerIds)); - if (Message.StickerIds == null) - { - Message.StickerIds = new List(); - } - - InvalidMessageException.ThrowIfMaxStickers(Message.StickerIds.Count + stickerIds.Count); - Message.StickerIds.AddRange(stickerIds); - return Builder; - } + /// + /// Adds a sticker to the message + /// + /// Sticker to be added + /// This + public TBuilder AddSticker(DiscordSticker sticker) + { + if (sticker == null) throw new ArgumentNullException(nameof(sticker)); + return AddSticker(sticker.Id); + } + + /// + /// Adds stickers to the message + /// + /// Sticker ID's to be added + /// This + public TBuilder AddStickers(ICollection stickerIds) + { + if (stickerIds == null) throw new ArgumentNullException(nameof(stickerIds)); + InvalidSnowflakeException.ThrowIfInvalid(stickerIds); + Message.StickerIds ??= new List(); + InvalidMessageException.ThrowIfMaxStickers(Message.StickerIds.Count + stickerIds.Count); + Message.StickerIds.AddRange(stickerIds); + return Builder; + } - /// - /// Adds a sticker to the message - /// - /// Sticker to be added - /// This - public TBuilder AddSticker(DiscordSticker sticker) + /// + /// Adds stickers to the message + /// + /// Sticker ID's to be added + /// This + public TBuilder AddStickers(ICollection stickerIds) + { + if (stickerIds == null) throw new ArgumentNullException(nameof(stickerIds)); + List ids = DiscordPool.Internal.GetList(); + foreach (DiscordSticker sticker in stickerIds) { - if (sticker == null) throw new ArgumentNullException(nameof(sticker)); - return AddSticker(sticker.Id); + ids.Add(sticker.Id); } - - /// - /// Adds stickers to the message - /// - /// Sticker ID's to be added - /// This - public TBuilder AddStickers(ICollection stickerIds) - { - if (stickerIds == null) throw new ArgumentNullException(nameof(stickerIds)); - List ids = DiscordPool.Internal.GetList(); - foreach (DiscordSticker sticker in stickerIds) - { - ids.Add(sticker.Id); - } - AddStickers(ids); - DiscordPool.Internal.FreeList(ids); + AddStickers(ids); + DiscordPool.Internal.FreeList(ids); - return Builder; - } + return Builder; + } - /// - /// Adds a to the message - /// - /// Message Reference to be added - /// This - public TBuilder AddMessageReference(MessageReference reference) - { - Message.MessageReference = reference ?? throw new ArgumentNullException(nameof(reference)); - return Builder; - } + /// + /// Adds a to the message + /// + /// Message Reference to be added + /// This + public TBuilder AddMessageReference(MessageReference reference) + { + Message.MessageReference = reference ?? throw new ArgumentNullException(nameof(reference)); + return Builder; + } - /// - /// Adds a to the message - /// - /// Message to reply to - /// Should the API call error if the message does not exist (Default true) - /// This - public TBuilder AddReply(DiscordMessage message, bool failIfNotExists = true) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - return AddReply(message.Id, message.GuildId, failIfNotExists); - } + /// + /// Adds a to the message + /// + /// Message to reply to + /// Should the API call error if the message does not exist (Default true) + /// This + public TBuilder AddReply(DiscordMessage message, bool failIfNotExists = true) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + return AddReply(message.Id, message.GuildId, failIfNotExists); + } - /// - /// Adds a to the message - /// - /// ID of the message to reply to - /// Guild ID of the message if one exists - /// Should the API call error if the message does not exist (Default true) - /// This - public TBuilder AddReply(Snowflake messageId, Snowflake? guildId = null, bool failIfNotExists = true) - { - MessageReference reference = Message.MessageReference ?? new MessageReference(); - reference.MessageId = messageId; - reference.GuildId = guildId; - reference.FailIfNotExists = failIfNotExists; - Message.MessageReference = reference; - return Builder; - } + /// + /// Adds a to the message + /// + /// ID of the message to reply to + /// Guild ID of the message if one exists + /// Should the API call error if the message does not exist (Default true) + /// This + public TBuilder AddReply(Snowflake messageId, Snowflake? guildId = null, bool failIfNotExists = true) + { + MessageReference reference = Message.MessageReference ?? new MessageReference(); + reference.MessageId = messageId; + reference.GuildId = guildId; + reference.FailIfNotExists = failIfNotExists; + Message.MessageReference = reference; + return Builder; + } - /// - /// Adds a sticker to the message - /// - /// Sticker to be added - /// This - public TBuilder SuppressNotifications(DiscordSticker sticker) - { - Message.Flags |= MessageFlags.SuppressNotifications; - return Builder; - } + /// + /// Adds a sticker to the message + /// + /// Sticker to be added + /// This + public TBuilder SuppressNotifications(DiscordSticker sticker) + { + Message.Flags |= MessageFlags.SuppressNotifications; + return Builder; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseMessageBuilder.cs b/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseMessageBuilder.cs index 7a27869b2..342cdbb7f 100644 --- a/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseMessageBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseMessageBuilder.cs @@ -3,196 +3,184 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Represents a builder for +/// +/// +/// +public abstract class BaseMessageBuilder + where TMessage : BaseMessageCreate + where TBuilder : BaseMessageBuilder { /// - /// Represents a builder for + /// Message the builder is for /// - /// - /// - public abstract class BaseMessageBuilder - where TMessage : BaseMessageCreate - where TBuilder : BaseMessageBuilder - { - /// - /// Message the builder is for - /// - protected readonly TMessage Message; - - /// - /// This builder - /// - protected readonly TBuilder Builder; - - /// - /// Constructor - /// - /// Message being created - protected BaseMessageBuilder(TMessage message) - { - Builder = (TBuilder)this; - Message = message; - } - - /// - /// Adds message text - /// - /// Text to be added - /// This - public virtual TBuilder AddContent(string content) - { - InvalidMessageException.ThrowIfInvalidContent(content); - Message.Content = content; - return Builder; - } + protected readonly TMessage Message; - /// - /// Marks the message As Text-To-Speech - /// - /// Should TTS be enabled (Default true) - /// this - public virtual TBuilder AsTts(bool enabled = true) - { - Message.Tts = enabled; - return Builder; - } + /// + /// This builder + /// + protected readonly TBuilder Builder; + + /// + /// Constructor + /// + /// Message being created + protected BaseMessageBuilder(TMessage message) + { + Builder = (TBuilder)this; + Message = message; + } + + /// + /// Adds message text + /// + /// Text to be added + /// This + public virtual TBuilder AddContent(string content) + { + InvalidMessageException.ThrowIfInvalidContent(content); + Message.Content = content; + return Builder; + } - /// - /// Adds a - /// - /// Embed to be added - /// This - public virtual TBuilder AddEmbed(DiscordEmbed embed) - { - if (embed == null) throw new ArgumentNullException(nameof(embed)); - if (Message.Embeds == null) - { - Message.Embeds = new List(); - } - - InvalidEmbedException.ThrowIfEmbedLimit(Message.Embeds.Count + 1); - Message.Embeds.Add(embed); - return Builder; - } - - /// - /// Adds created from a - /// - /// Build to add embeds from - /// This - public virtual TBuilder AddEmbed(DiscordEmbedBuilder builder) - { - if (builder == null) throw new ArgumentNullException(nameof(builder)); - return AddEmbed(builder.Build()); - } - - /// - /// Adds a collection of to the response - /// - /// Embeds to be added - /// This - public virtual TBuilder AddEmbeds(ICollection embeds) - { - if (embeds == null) throw new ArgumentNullException(nameof(embeds)); - if (Message.Embeds == null) - { - Message.Embeds = new List(); - } - - InvalidEmbedException.ThrowIfEmbedLimit(Message.Embeds.Count + embeds.Count); - Message.Embeds.AddRange(embeds); - return Builder; - } - - /// - /// Adds to the response - /// - /// Mentions to be added - /// This - public virtual TBuilder AddAllowedMentions(AllowedMentions mentions) - { - if (mentions == null) throw new ArgumentNullException(nameof(mentions)); - Message.AllowedMentions = mentions; - return Builder; - } - - /// - /// Suppresses embeds on this response - /// - /// This - public virtual TBuilder SuppressEmbeds() - { - Message.Flags |= MessageFlags.SuppressEmbeds; - return Builder; - } - - /// - /// Adds a single - /// - /// Component to be added - /// This - public virtual TBuilder AddActionRow(ActionRowComponent component) - { - if (component == null) throw new ArgumentNullException(nameof(component)); - if (Message.Components == null) - { - Message.Components = new List(); - } - - InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(Message.Components.Count + 1); - Message.Components.Add(component); - return Builder; - } - - /// - /// Adds a collection MessageComponents/> - /// - /// Components to be added - /// This - public virtual TBuilder AddComponents(ICollection components) - { - if (components == null) throw new ArgumentNullException(nameof(components)); - if (Message.Components == null) - { - Message.Components = new List(); - } - - InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(Message.Components.Count + components.Count); - Message.Components.AddRange(components); - return Builder; - } - - /// - /// Adds MessageComponents from - /// - /// Build to add components from - /// This - public virtual TBuilder AddComponents(MessageComponentBuilder builder) - { - if (builder == null) throw new ArgumentNullException(nameof(builder)); - return AddComponents(builder.Build()); - } + /// + /// Marks the message As Text-To-Speech + /// + /// Should TTS be enabled (Default true) + /// this + public virtual TBuilder AsTts(bool enabled = true) + { + Message.Tts = enabled; + return Builder; + } - /// - /// Adds an attachment to the message - /// - /// Name of the file - /// byte[] of the attachment - /// Attachment content type - /// Description for the attachment - public virtual TBuilder AddAttachment(string filename, byte[] data, string contentType, string description = null) - { - Message.AddAttachment(filename, data, contentType, description); - return Builder; - } - - /// - /// Returns the built message - /// - /// - public TMessage Build() - { - return Message; - } + /// + /// Adds a + /// + /// Embed to be added + /// This + public virtual TBuilder AddEmbed(DiscordEmbed embed) + { + if (embed == null) throw new ArgumentNullException(nameof(embed)); + Message.Embeds ??= []; + + InvalidEmbedException.ThrowIfEmbedLimit(Message.Embeds.Count + 1); + Message.Embeds.Add(embed); + return Builder; + } + + /// + /// Adds created from a + /// + /// Build to add embeds from + /// This + public virtual TBuilder AddEmbed(DiscordEmbedBuilder builder) + { + if (builder == null) throw new ArgumentNullException(nameof(builder)); + return AddEmbed(builder.Build()); + } + + /// + /// Adds a collection of to the response + /// + /// Embeds to be added + /// This + public virtual TBuilder AddEmbeds(ICollection embeds) + { + if (embeds == null) throw new ArgumentNullException(nameof(embeds)); + Message.Embeds ??= []; + + InvalidEmbedException.ThrowIfEmbedLimit(Message.Embeds.Count + embeds.Count); + Message.Embeds.AddRange(embeds); + return Builder; + } + + /// + /// Adds to the response + /// + /// Mentions to be added + /// This + public virtual TBuilder AddAllowedMentions(AllowedMentions mentions) + { + if (mentions == null) throw new ArgumentNullException(nameof(mentions)); + Message.AllowedMentions = mentions; + return Builder; + } + + /// + /// Suppresses embeds on this response + /// + /// This + public virtual TBuilder SuppressEmbeds() + { + Message.Flags |= MessageFlags.SuppressEmbeds; + return Builder; + } + + /// + /// Adds a single + /// + /// Component to be added + /// This + public virtual TBuilder AddActionRow(ActionRowComponent component) + { + if (component == null) throw new ArgumentNullException(nameof(component)); + Message.Components ??= []; + + InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(Message.Components.Count + 1); + Message.Components.Add(component); + return Builder; + } + + /// + /// Adds a collection MessageComponents/> + /// + /// Components to be added + /// This + public virtual TBuilder AddComponents(ICollection components) + { + if (components == null) throw new ArgumentNullException(nameof(components)); + Message.Components ??= []; + + InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(Message.Components.Count + components.Count); + Message.Components.AddRange(components); + return Builder; + } + + /// + /// Adds MessageComponents from + /// + /// Build to add components from + /// This + public virtual TBuilder AddComponents(MessageComponentBuilder builder) + { + if (builder == null) throw new ArgumentNullException(nameof(builder)); + return AddComponents(builder.Build()); + } + + /// + /// Adds an attachment to the message + /// + /// Name of the file + /// byte[] of the attachment + /// Attachment content type + /// Description for the attachment + /// Title of the attachment + public virtual TBuilder AddAttachment(string filename, byte[] data, string contentType, string description = null, string title = null) + { + Message.AddAttachment(filename, data, contentType, description, title); + return Builder; + } + + /// + /// Returns the built message + /// + /// + public TMessage Build() + { + return Message; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseWebhookMessageBuilder.cs b/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseWebhookMessageBuilder.cs index ab94c808e..5c2c412dc 100644 --- a/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseWebhookMessageBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Messages/BaseBuilders/BaseWebhookMessageBuilder.cs @@ -1,44 +1,43 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Represents a builder for +/// +/// Type of the message +/// Type of the builder +public abstract class BaseWebhookMessageBuilder : BaseChannelMessageBuilder + where TMessage : WebhookCreateMessage + where TBuilder : BaseChannelMessageBuilder { /// - /// Represents a builder for + /// Constructor /// - /// Type of the message - /// Type of the builder - public abstract class BaseWebhookMessageBuilder : BaseChannelMessageBuilder - where TMessage : WebhookCreateMessage - where TBuilder : BaseChannelMessageBuilder - { - /// - /// Constructor - /// - /// Message being created - protected BaseWebhookMessageBuilder(TMessage message) : base(message) { } + /// Message being created + protected BaseWebhookMessageBuilder(TMessage message) : base(message) { } - /// - /// Adds a custom username for the sender - /// - /// Username to be displayed as the sender - /// This - public TBuilder AddUserName(string userName) - { - InvalidUserException.ThrowIfInvalidUserName(userName); - Message.Username = userName; - return Builder; - } + /// + /// Adds a custom username for the sender + /// + /// Username to be displayed as the sender + /// This + public TBuilder AddUserName(string userName) + { + InvalidUserException.ThrowIfInvalidUserName(userName); + Message.Username = userName; + return Builder; + } - /// - /// Adds a custom avatar url for the sender - /// - /// Avatar URL to be displayed for the sender - /// This - public TBuilder AddAvatarUrl(string avatarUrl) - { - Message.AvatarUrl = avatarUrl; - return Builder; - } + /// + /// Adds a custom avatar url for the sender + /// + /// Avatar URL to be displayed for the sender + /// This + public TBuilder AddAvatarUrl(string avatarUrl) + { + Message.AvatarUrl = avatarUrl; + return Builder; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Messages/DiscordMessageBuilder.cs b/Oxide.Ext.Discord/Builders/Messages/DiscordMessageBuilder.cs index 2d6ce5307..d0082df0f 100644 --- a/Oxide.Ext.Discord/Builders/Messages/DiscordMessageBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Messages/DiscordMessageBuilder.cs @@ -1,21 +1,20 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Represents a builder for +/// +public class DiscordMessageBuilder : BaseChannelMessageBuilder { /// - /// Represents a builder for + /// Constructor creating a new message /// - public class DiscordMessageBuilder : BaseChannelMessageBuilder - { - /// - /// Constructor creating a new message - /// - public DiscordMessageBuilder() : this(new MessageCreate()) { } + public DiscordMessageBuilder() : this(new MessageCreate()) { } - /// - /// Constructor to use existing message - /// - /// Message to use - public DiscordMessageBuilder(MessageCreate message) : base(message) { } - } + /// + /// Constructor to use an existing message + /// + /// Message to use + public DiscordMessageBuilder(MessageCreate message) : base(message) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/Messages/WebhookMessageBuilder.cs b/Oxide.Ext.Discord/Builders/Messages/WebhookMessageBuilder.cs index 0eaa3066e..21c9b94b2 100644 --- a/Oxide.Ext.Discord/Builders/Messages/WebhookMessageBuilder.cs +++ b/Oxide.Ext.Discord/Builders/Messages/WebhookMessageBuilder.cs @@ -1,21 +1,20 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Represents a builder for +/// +public class WebhookMessageBuilder : BaseWebhookMessageBuilder { /// - /// Represents a builder for + /// Constructor for creating a new WebhookCreateMessage /// - public class WebhookMessageBuilder : BaseWebhookMessageBuilder - { - /// - /// Constructor for creating a new WebhookCreateMessage - /// - public WebhookMessageBuilder() : this(new WebhookCreateMessage()) { } + public WebhookMessageBuilder() : this(new WebhookCreateMessage()) { } - /// - /// Constructor for using an existing WebhookCreateMessage - /// - /// Message to use - public WebhookMessageBuilder(WebhookCreateMessage message) : base(message) { } - } + /// + /// Constructor for using an existing WebhookCreateMessage + /// + /// Message to use + public WebhookMessageBuilder(WebhookCreateMessage message) : base(message) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Builders/QueryStringBuilder.cs b/Oxide.Ext.Discord/Builders/QueryStringBuilder.cs index ed2ca5583..10093caa6 100644 --- a/Oxide.Ext.Discord/Builders/QueryStringBuilder.cs +++ b/Oxide.Ext.Discord/Builders/QueryStringBuilder.cs @@ -1,96 +1,70 @@ using System.Collections.Generic; -using System.Text; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Builders +namespace Oxide.Ext.Discord.Builders; + +/// +/// Builder used to build query strings for urls +/// +public ref struct QueryStringBuilder { + private ValueStringBuilder _builder; + + public QueryStringBuilder() + { + _builder = new ValueStringBuilder(); + _builder.Append('?'); + } + /// - /// Builder used to build query strings for urls + /// Add a key value pair to the query string /// - public class QueryStringBuilder : BasePoolable + /// Key name + /// Key value + public void Add(string key, string value) { - private StringBuilder _builder; - - /// - /// Creates a pooled - /// - /// - public static QueryStringBuilder Create(DiscordPluginPool pool) => pool.Get(); - - /// - /// Add a key value pair to the query string - /// - /// Key name - /// Key value - public void Add(string key, string value) - { - AddKey(key); - _builder.Append(value); - } - - /// - /// Add a list of values with the specified separator - /// - /// Key name - /// List to be added - /// Separator for the list - /// - public void AddList(string key, List list, string separator) - { - AddKey(key); - for (int index = 0; index < list.Count; index++) - { - T entry = list[index]; - _builder.Append(entry.ToString()); - if (index + 1 != list.Count) - { - _builder.Append(separator); - } - } - } + AddKey(key); + _builder.Append(value); + } - private void AddKey(string key) + /// + /// Add a list of values with the specified separator + /// + /// Key name + /// List to be added + /// Separator for the list + /// + public void AddList(string key, List list, string separator) + { + AddKey(key); + for (int index = 0; index < list.Count; index++) { - if (_builder.Length > 1) + T entry = list[index]; + _builder.Append(entry.ToString()); + if (index + 1 != list.Count) { - _builder.Append('&'); + _builder.Append(separator); } - - _builder.Append(key); - _builder.Append('='); - } - - /// - /// Returns the query string as a string. - /// - /// - public override string ToString() - { - return _builder.Length <= 1 ? string.Empty : _builder.ToString(); - } - - /// - /// Returns the query string and returns the builder back to the pool - /// - /// - public string ToStringAndFree() - { - string query = ToString(); - Dispose(); - return query; } + } - /// - protected override void EnterPool() + private void AddKey(string key) + { + if (_builder.Length > 1) { - PluginPool.FreeStringBuilder(_builder); + _builder.Append('&'); } + + _builder.Append(key); + _builder.Append('='); + } - /// - protected override void LeavePool() - { - _builder = PluginPool.GetStringBuilder(); - _builder.Append("?"); - } + /// + /// Returns the query string as a string. + /// + /// + public override string ToString() + { + return _builder.Length <= 1 ? string.Empty : _builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Cache/DiscordPluginCache.cs b/Oxide.Ext.Discord/Cache/DiscordPluginCache.cs index 524880817..a71c2a151 100644 --- a/Oxide.Ext.Discord/Cache/DiscordPluginCache.cs +++ b/Oxide.Ext.Discord/Cache/DiscordPluginCache.cs @@ -5,72 +5,90 @@ using Oxide.Core.Plugins; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Cache +namespace Oxide.Ext.Discord.Cache; + +/// +/// Represents a cache for Loaded and Loadable plugins +/// +public sealed class DiscordPluginCache : Singleton { + private readonly List _loadablePlugins = []; + private readonly List _loadedPlugins = []; + private readonly List _allPlugins = []; + private DateTime _nextLoadedUpdate = DateTime.MinValue; + private DateTime _nextAllUpdate = DateTime.MinValue; + + private DiscordPluginCache() {} + /// - /// Represents a cache for Loaded and Loadable plugins + /// Returns a list of plugins loaded by oxide /// - public sealed class DiscordPluginCache : Singleton + /// + public IReadOnlyList GetLoadedPlugins() { - private readonly List _loadablePlugins = new List(); - private readonly List _loadedPlugins = new List(); - private DateTime _nextUpdate = DateTime.MinValue; - - private DiscordPluginCache() {} - - /// - /// Returns a list of plugins loaded by oxide - /// - /// - public IReadOnlyList GetLoadedPlugins() + if (_loadedPlugins.Count != 0) { - if (_loadedPlugins.Count != 0) - { - return _loadedPlugins; - } - - _loadablePlugins.Clear(); - _loadedPlugins.AddRange(Interface.Oxide.RootPluginManager.GetPlugins() - .Where(p => !p.IsCorePlugin) - .Select(p => p.Name) - .OrderBy(p => p)); return _loadedPlugins; } + + _loadablePlugins.Clear(); + _loadedPlugins.AddRange(Interface.Oxide.RootPluginManager.GetPlugins() + .Where(p => !p.IsCorePlugin) + .Select(p => p.Name) + .OrderBy(p => p)); + return _loadedPlugins; + } - /// - /// Returns a list of plugins that can be loaded by oxide - /// Already loaded plugins are excluded from the list - /// - /// - public IReadOnlyList GetLoadablePlugins() + /// + /// Returns a list of plugins that can be loaded by oxide + /// Already loaded plugins are excluded from the list + /// + /// + public IReadOnlyList GetLoadablePlugins() + { + if (_nextLoadedUpdate > DateTime.UtcNow) { - if (_nextUpdate > DateTime.UtcNow) - { - return _loadablePlugins; - } - - _loadablePlugins.Clear(); - _loadablePlugins.AddRange(OxideLibrary.Instance.PluginLoader.ScanDirectory(Interface.Oxide.PluginDirectory).Except(GetLoadedPlugins()).OrderBy(p => p)); - _nextUpdate = DateTime.UtcNow + TimeSpan.FromSeconds(5); return _loadablePlugins; } + + _loadablePlugins.Clear(); + _loadablePlugins.AddRange(OxideLibrary.Instance.PluginLoader.ScanDirectory(Interface.Oxide.PluginDirectory).Except(GetLoadedPlugins()).OrderBy(p => p)); + _nextLoadedUpdate = DateTime.UtcNow + TimeSpan.FromSeconds(15); + return _loadablePlugins; + } + + /// + /// Returns a list of all plugins in the plugin folder + /// + /// + public IReadOnlyList GetAllPlugins() + { + if (_nextAllUpdate > DateTime.UtcNow) + { + return _allPlugins; + } + + _allPlugins.Clear(); + _allPlugins.AddRange(OxideLibrary.Instance.PluginLoader.ScanDirectory(Interface.Oxide.PluginDirectory).OrderBy(p => p)); + _nextAllUpdate = DateTime.UtcNow + TimeSpan.FromSeconds(15); + return _loadablePlugins; + } - internal void OnPluginLoaded(Plugin plugin) + internal void OnPluginLoaded(Plugin plugin) + { + if (!plugin.IsCorePlugin) { - if (!plugin.IsCorePlugin) - { - _nextUpdate = DateTime.UtcNow; - _loadedPlugins.Clear(); - } + _nextLoadedUpdate = DateTime.UtcNow; + _loadedPlugins.Clear(); } + } - internal void OnPluginUnloaded(Plugin plugin) + internal void OnPluginUnloaded(Plugin plugin) + { + if (!plugin.IsCorePlugin) { - if (!plugin.IsCorePlugin) - { - _nextUpdate = DateTime.UtcNow; - _loadedPlugins.Clear(); - } + _nextLoadedUpdate = DateTime.UtcNow; + _loadedPlugins.Clear(); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Cache/Emoji/EmojiCache.cs b/Oxide.Ext.Discord/Cache/Emoji/EmojiCache.cs index 9fc34ad76..a1dfdfab7 100644 --- a/Oxide.Ext.Discord/Cache/Emoji/EmojiCache.cs +++ b/Oxide.Ext.Discord/Cache/Emoji/EmojiCache.cs @@ -2,48 +2,86 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Cache +namespace Oxide.Ext.Discord.Cache; + +/// +/// Cached Emoji Data +/// +public sealed partial class EmojiCache : Singleton { + private readonly Hash _emojiToText = new(); + private readonly Hash _textToEmoji = new(); + public readonly Regex EmojiRegex = new(@"(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])", RegexOptions.Compiled); + public readonly Regex TextRegex = new(@":[\d\w_]*:", RegexOptions.Compiled); + + public readonly MatchEvaluator EmojiToTextOrDefault; + public readonly MatchEvaluator TextToEmojiOrDefault; + + private EmojiCache() + { + EmojiToTextOrDefault = match => _emojiToText[match.Value] ?? match.Value; + TextToEmojiOrDefault = match => _textToEmoji[match.Value] ?? match.Value; + } + /// - /// Cached Emoji Data + /// Convert an emoji character to the emoji string text /// - public sealed partial class EmojiCache : Singleton - { - private readonly Hash _emojiToText = new Hash(); - private readonly Hash _textToEmoji = new Hash(); - private readonly Regex _emojiRegex = new Regex(@"(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])", RegexOptions.Compiled); - private readonly Regex _textRegex = new Regex(@":[\d\w_]*", RegexOptions.Compiled); + /// Emoji to convert + /// + public string EmojiToText(string emoji) => _emojiToText[emoji]; - private EmojiCache() { } - - /// - /// Convert an emoji character to emoji string text - /// - /// Emoji to convert - /// - public string EmojiToText(string emoji) => _emojiToText[emoji]; - - /// - /// Convert emoji string text to an emoji character - /// - /// - /// - public string TextToEmoji(string text) => _textToEmoji[text]; - - /// - /// Replaces emoji character with emoji string characters - /// - /// - /// - /// - public string ReplaceEmojiWithText(string text, string nonMatchReplacement = "") => _emojiRegex.Replace(text, match => _emojiToText[match.Value] ?? nonMatchReplacement); - - /// - /// Replaces emoji string text with emoji characters - /// - /// - /// - /// - public string ReplaceTextWithEmoji(string text, string nonMatchReplacement = "") => _textRegex.Replace(text, match => _textToEmoji[match.Value] ?? nonMatchReplacement); - } + /// + /// Convert emoji string text to an emoji character + /// + /// + /// + public string TextToEmoji(string text) => _textToEmoji[text]; + + /// + /// Replaces emoji character with emoji string characters + /// + /// Text to replace + /// Replacement Text to use if non-matching + /// + public string ReplaceEmojiWithText(string text, string nonMatchReplacement) => EmojiRegex.Replace(text, match => _emojiToText[match.Value] ?? nonMatchReplacement); + + /// + /// Replaces emoji string text with emoji characters + /// + /// Text to replace + /// Replacement Text to use if non-matching + /// + public string ReplaceTextWithEmoji(string text, string nonMatchReplacement) => TextRegex.Replace(text, match => _textToEmoji[match.Value] ?? nonMatchReplacement); + + /// + /// Replaces emoji character with emoji string characters + /// + /// Text to replace + /// Replacement Evaluator function + /// + public string ReplaceEmojiWithText(string text, MatchEvaluator evaluator) => EmojiRegex.Replace(text, evaluator); + + /// + /// Replaces emoji string text with emoji characters + /// + /// Text to replace + /// Replacement Evaluator function + /// + public string ReplaceTextWithEmoji(string text, MatchEvaluator evaluator) => TextRegex.Replace(text, evaluator); + + /// + /// Replaces emoji character with emoji string characters + /// If no match is found then the original text is used + /// + /// Text to replace + /// + public string ReplaceEmojiWithText(string text) => ReplaceEmojiWithText(text, EmojiToTextOrDefault); + + /// + /// Replaces emoji string text with emoji characters + /// If no match is found then the original text is used + /// + /// Text to replace + /// + public string ReplaceTextWithEmoji(string text) => ReplaceTextWithEmoji(text, TextToEmojiOrDefault); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Cache/Emoji/EmojiCache.data.cs b/Oxide.Ext.Discord/Cache/Emoji/EmojiCache.data.cs index 2a8418bf6..928c2f3cc 100644 --- a/Oxide.Ext.Discord/Cache/Emoji/EmojiCache.data.cs +++ b/Oxide.Ext.Discord/Cache/Emoji/EmojiCache.data.cs @@ -1,4611 +1,4610 @@ -namespace Oxide.Ext.Discord.Cache +namespace Oxide.Ext.Discord.Cache; + +public partial class EmojiCache { - public partial class EmojiCache + internal void Build() { - internal void Build() - { - _textToEmoji[":100:"] = "💯"; - _emojiToText["💯"] = ":100:"; - _textToEmoji[":1234:"] = "🔢"; - _emojiToText["🔢"] = ":1234:"; - _textToEmoji[":soccer:"] = "⚽"; - _emojiToText["⚽"] = ":soccer:"; - _textToEmoji[":soccer_ball:"] = "⚽"; - _emojiToText["⚽"] = ":soccer_ball:"; - _textToEmoji[":basketball:"] = "🏀"; - _emojiToText["🏀"] = ":basketball:"; - _textToEmoji[":football:"] = "🏈"; - _emojiToText["🏈"] = ":football:"; - _textToEmoji[":baseball:"] = "⚾"; - _emojiToText["⚾"] = ":baseball:"; - _textToEmoji[":softball:"] = "🥎"; - _emojiToText["🥎"] = ":softball:"; - _textToEmoji[":tennis:"] = "🎾"; - _emojiToText["🎾"] = ":tennis:"; - _textToEmoji[":volleyball:"] = "🏐"; - _emojiToText["🏐"] = ":volleyball:"; - _textToEmoji[":rugby_football:"] = "🏉"; - _emojiToText["🏉"] = ":rugby_football:"; - _textToEmoji[":flying_disc:"] = "🥏"; - _emojiToText["🥏"] = ":flying_disc:"; - _textToEmoji[":8ball:"] = "🎱"; - _emojiToText["🎱"] = ":8ball:"; - _textToEmoji[":yo_yo:"] = "🪀"; - _emojiToText["🪀"] = ":yo_yo:"; - _textToEmoji[":ping_pong:"] = "🏓"; - _emojiToText["🏓"] = ":ping_pong:"; - _textToEmoji[":table_tennis:"] = "🏓"; - _emojiToText["🏓"] = ":table_tennis:"; - _textToEmoji[":badminton:"] = "🏸"; - _emojiToText["🏸"] = ":badminton:"; - _textToEmoji[":hockey:"] = "🏒"; - _emojiToText["🏒"] = ":hockey:"; - _textToEmoji[":ice_hockey:"] = "🏒"; - _emojiToText["🏒"] = ":ice_hockey:"; - _textToEmoji[":field_hockey:"] = "🏑"; - _emojiToText["🏑"] = ":field_hockey:"; - _textToEmoji[":lacrosse:"] = "🥍"; - _emojiToText["🥍"] = ":lacrosse:"; - _textToEmoji[":cricket_game:"] = "🏏"; - _emojiToText["🏏"] = ":cricket_game:"; - _textToEmoji[":cricket_bat_ball:"] = "🏏"; - _emojiToText["🏏"] = ":cricket_bat_ball:"; - _textToEmoji[":boomerang:"] = "🪃"; - _emojiToText["🪃"] = ":boomerang:"; - _textToEmoji[":goal:"] = "🥅"; - _emojiToText["🥅"] = ":goal:"; - _textToEmoji[":goal_net:"] = "🥅"; - _emojiToText["🥅"] = ":goal_net:"; - _textToEmoji[":golf:"] = "⛳"; - _emojiToText["⛳"] = ":golf:"; - _textToEmoji[":flag_in_hole:"] = "⛳"; - _emojiToText["⛳"] = ":flag_in_hole:"; - _textToEmoji[":kite:"] = "🪁"; - _emojiToText["🪁"] = ":kite:"; - _textToEmoji[":playground_slide:"] = "🛝"; - _emojiToText["🛝"] = ":playground_slide:"; - _textToEmoji[":bow_and_arrow:"] = "🏹"; - _emojiToText["🏹"] = ":bow_and_arrow:"; - _textToEmoji[":archery:"] = "🏹"; - _emojiToText["🏹"] = ":archery:"; - _textToEmoji[":fishing_pole_and_fish:"] = "🎣"; - _emojiToText["🎣"] = ":fishing_pole_and_fish:"; - _textToEmoji[":fishing_pole:"] = "🎣"; - _emojiToText["🎣"] = ":fishing_pole:"; - _textToEmoji[":diving_mask:"] = "🤿"; - _emojiToText["🤿"] = ":diving_mask:"; - _textToEmoji[":boxing_glove:"] = "🥊"; - _emojiToText["🥊"] = ":boxing_glove:"; - _textToEmoji[":boxing_gloves:"] = "🥊"; - _emojiToText["🥊"] = ":boxing_gloves:"; - _textToEmoji[":martial_arts_uniform:"] = "🥋"; - _emojiToText["🥋"] = ":martial_arts_uniform:"; - _textToEmoji[":karate_uniform:"] = "🥋"; - _emojiToText["🥋"] = ":karate_uniform:"; - _textToEmoji[":running_shirt_with_sash:"] = "🎽"; - _emojiToText["🎽"] = ":running_shirt_with_sash:"; - _textToEmoji[":running_shirt:"] = "🎽"; - _emojiToText["🎽"] = ":running_shirt:"; - _textToEmoji[":skateboard:"] = "🛹"; - _emojiToText["🛹"] = ":skateboard:"; - _textToEmoji[":roller_skate:"] = "🛼"; - _emojiToText["🛼"] = ":roller_skate:"; - _textToEmoji[":sled:"] = "🛷"; - _emojiToText["🛷"] = ":sled:"; - _textToEmoji[":ice_skate:"] = "⛸️"; - _emojiToText["⛸️"] = ":ice_skate:"; - _textToEmoji[":curling_stone:"] = "🥌"; - _emojiToText["🥌"] = ":curling_stone:"; - _textToEmoji[":ski:"] = "🎿"; - _emojiToText["🎿"] = ":ski:"; - _textToEmoji[":skis:"] = "🎿"; - _emojiToText["🎿"] = ":skis:"; - _textToEmoji[":skier:"] = "⛷️"; - _emojiToText["⛷️"] = ":skier:"; - _textToEmoji[":snowboarder:"] = "🏂"; - _emojiToText["🏂"] = ":snowboarder:"; - _textToEmoji[":parachute:"] = "🪂"; - _emojiToText["🪂"] = ":parachute:"; - _textToEmoji[":person_lifting_weights:"] = "🏋️"; - _emojiToText["🏋️"] = ":person_lifting_weights:"; - _textToEmoji[":lifter:"] = "🏋️"; - _emojiToText["🏋️"] = ":lifter:"; - _textToEmoji[":weight_lifter:"] = "🏋️"; - _emojiToText["🏋️"] = ":weight_lifter:"; - _textToEmoji[":woman_lifting_weights:"] = "🏋️‍♀️"; - _emojiToText["🏋️‍♀️"] = ":woman_lifting_weights:"; - _textToEmoji[":man_lifting_weights:"] = "🏋️‍♂️"; - _emojiToText["🏋️‍♂️"] = ":man_lifting_weights:"; - _textToEmoji[":people_wrestling:"] = "🤼"; - _emojiToText["🤼"] = ":people_wrestling:"; - _textToEmoji[":wrestlers:"] = "🤼"; - _emojiToText["🤼"] = ":wrestlers:"; - _textToEmoji[":wrestling:"] = "🤼"; - _emojiToText["🤼"] = ":wrestling:"; - _textToEmoji[":women_wrestling:"] = "🤼‍♀️"; - _emojiToText["🤼‍♀️"] = ":women_wrestling:"; - _textToEmoji[":men_wrestling:"] = "🤼‍♂️"; - _emojiToText["🤼‍♂️"] = ":men_wrestling:"; - _textToEmoji[":person_doing_cartwheel:"] = "🤸"; - _emojiToText["🤸"] = ":person_doing_cartwheel:"; - _textToEmoji[":cartwheel:"] = "🤸"; - _emojiToText["🤸"] = ":cartwheel:"; - _textToEmoji[":woman_cartwheeling:"] = "🤸‍♀️"; - _emojiToText["🤸‍♀️"] = ":woman_cartwheeling:"; - _textToEmoji[":man_cartwheeling:"] = "🤸‍♂️"; - _emojiToText["🤸‍♂️"] = ":man_cartwheeling:"; - _textToEmoji[":person_bouncing_ball:"] = "⛹️"; - _emojiToText["⛹️"] = ":person_bouncing_ball:"; - _textToEmoji[":basketball_player:"] = "⛹️"; - _emojiToText["⛹️"] = ":basketball_player:"; - _textToEmoji[":person_with_ball:"] = "⛹️"; - _emojiToText["⛹️"] = ":person_with_ball:"; - _textToEmoji[":woman_bouncing_ball:"] = "⛹️‍♀️"; - _emojiToText["⛹️‍♀️"] = ":woman_bouncing_ball:"; - _textToEmoji[":man_bouncing_ball:"] = "⛹️‍♂️"; - _emojiToText["⛹️‍♂️"] = ":man_bouncing_ball:"; - _textToEmoji[":person_fencing:"] = "🤺"; - _emojiToText["🤺"] = ":person_fencing:"; - _textToEmoji[":fencer:"] = "🤺"; - _emojiToText["🤺"] = ":fencer:"; - _textToEmoji[":fencing:"] = "🤺"; - _emojiToText["🤺"] = ":fencing:"; - _textToEmoji[":person_playing_handball:"] = "🤾"; - _emojiToText["🤾"] = ":person_playing_handball:"; - _textToEmoji[":handball:"] = "🤾"; - _emojiToText["🤾"] = ":handball:"; - _textToEmoji[":woman_playing_handball:"] = "🤾‍♀️"; - _emojiToText["🤾‍♀️"] = ":woman_playing_handball:"; - _textToEmoji[":man_playing_handball:"] = "🤾‍♂️"; - _emojiToText["🤾‍♂️"] = ":man_playing_handball:"; - _textToEmoji[":person_golfing:"] = "🏌️"; - _emojiToText["🏌️"] = ":person_golfing:"; - _textToEmoji[":golfer:"] = "🏌️"; - _emojiToText["🏌️"] = ":golfer:"; - _textToEmoji[":woman_golfing:"] = "🏌️‍♀️"; - _emojiToText["🏌️‍♀️"] = ":woman_golfing:"; - _textToEmoji[":man_golfing:"] = "🏌️‍♂️"; - _emojiToText["🏌️‍♂️"] = ":man_golfing:"; - _textToEmoji[":horse_racing:"] = "🏇"; - _emojiToText["🏇"] = ":horse_racing:"; - _textToEmoji[":person_in_lotus_position:"] = "🧘"; - _emojiToText["🧘"] = ":person_in_lotus_position:"; - _textToEmoji[":woman_in_lotus_position:"] = "🧘‍♀️"; - _emojiToText["🧘‍♀️"] = ":woman_in_lotus_position:"; - _textToEmoji[":man_in_lotus_position:"] = "🧘‍♂️"; - _emojiToText["🧘‍♂️"] = ":man_in_lotus_position:"; - _textToEmoji[":person_surfing:"] = "🏄"; - _emojiToText["🏄"] = ":person_surfing:"; - _textToEmoji[":surfer:"] = "🏄"; - _emojiToText["🏄"] = ":surfer:"; - _textToEmoji[":woman_surfing:"] = "🏄‍♀️"; - _emojiToText["🏄‍♀️"] = ":woman_surfing:"; - _textToEmoji[":man_surfing:"] = "🏄‍♂️"; - _emojiToText["🏄‍♂️"] = ":man_surfing:"; - _textToEmoji[":person_swimming:"] = "🏊"; - _emojiToText["🏊"] = ":person_swimming:"; - _textToEmoji[":swimmer:"] = "🏊"; - _emojiToText["🏊"] = ":swimmer:"; - _textToEmoji[":woman_swimming:"] = "🏊‍♀️"; - _emojiToText["🏊‍♀️"] = ":woman_swimming:"; - _textToEmoji[":man_swimming:"] = "🏊‍♂️"; - _emojiToText["🏊‍♂️"] = ":man_swimming:"; - _textToEmoji[":person_playing_water_polo:"] = "🤽"; - _emojiToText["🤽"] = ":person_playing_water_polo:"; - _textToEmoji[":water_polo:"] = "🤽"; - _emojiToText["🤽"] = ":water_polo:"; - _textToEmoji[":woman_playing_water_polo:"] = "🤽‍♀️"; - _emojiToText["🤽‍♀️"] = ":woman_playing_water_polo:"; - _textToEmoji[":man_playing_water_polo:"] = "🤽‍♂️"; - _emojiToText["🤽‍♂️"] = ":man_playing_water_polo:"; - _textToEmoji[":person_rowing_boat:"] = "🚣"; - _emojiToText["🚣"] = ":person_rowing_boat:"; - _textToEmoji[":rowboat:"] = "🚣"; - _emojiToText["🚣"] = ":rowboat:"; - _textToEmoji[":woman_rowing_boat:"] = "🚣‍♀️"; - _emojiToText["🚣‍♀️"] = ":woman_rowing_boat:"; - _textToEmoji[":man_rowing_boat:"] = "🚣‍♂️"; - _emojiToText["🚣‍♂️"] = ":man_rowing_boat:"; - _textToEmoji[":person_climbing:"] = "🧗"; - _emojiToText["🧗"] = ":person_climbing:"; - _textToEmoji[":woman_climbing:"] = "🧗‍♀️"; - _emojiToText["🧗‍♀️"] = ":woman_climbing:"; - _textToEmoji[":man_climbing:"] = "🧗‍♂️"; - _emojiToText["🧗‍♂️"] = ":man_climbing:"; - _textToEmoji[":person_mountain_biking:"] = "🚵"; - _emojiToText["🚵"] = ":person_mountain_biking:"; - _textToEmoji[":mountain_bicyclist:"] = "🚵"; - _emojiToText["🚵"] = ":mountain_bicyclist:"; - _textToEmoji[":woman_mountain_biking:"] = "🚵‍♀️"; - _emojiToText["🚵‍♀️"] = ":woman_mountain_biking:"; - _textToEmoji[":man_mountain_biking:"] = "🚵‍♂️"; - _emojiToText["🚵‍♂️"] = ":man_mountain_biking:"; - _textToEmoji[":person_biking:"] = "🚴"; - _emojiToText["🚴"] = ":person_biking:"; - _textToEmoji[":bicyclist:"] = "🚴"; - _emojiToText["🚴"] = ":bicyclist:"; - _textToEmoji[":woman_biking:"] = "🚴‍♀️"; - _emojiToText["🚴‍♀️"] = ":woman_biking:"; - _textToEmoji[":man_biking:"] = "🚴‍♂️"; - _emojiToText["🚴‍♂️"] = ":man_biking:"; - _textToEmoji[":trophy:"] = "🏆"; - _emojiToText["🏆"] = ":trophy:"; - _textToEmoji[":first_place:"] = "🥇"; - _emojiToText["🥇"] = ":first_place:"; - _textToEmoji[":first_place_medal:"] = "🥇"; - _emojiToText["🥇"] = ":first_place_medal:"; - _textToEmoji[":second_place:"] = "🥈"; - _emojiToText["🥈"] = ":second_place:"; - _textToEmoji[":second_place_medal:"] = "🥈"; - _emojiToText["🥈"] = ":second_place_medal:"; - _textToEmoji[":third_place:"] = "🥉"; - _emojiToText["🥉"] = ":third_place:"; - _textToEmoji[":third_place_medal:"] = "🥉"; - _emojiToText["🥉"] = ":third_place_medal:"; - _textToEmoji[":medal:"] = "🏅"; - _emojiToText["🏅"] = ":medal:"; - _textToEmoji[":sports_medal:"] = "🏅"; - _emojiToText["🏅"] = ":sports_medal:"; - _textToEmoji[":military_medal:"] = "🎖️"; - _emojiToText["🎖️"] = ":military_medal:"; - _textToEmoji[":rosette:"] = "🏵️"; - _emojiToText["🏵️"] = ":rosette:"; - _textToEmoji[":reminder_ribbon:"] = "🎗️"; - _emojiToText["🎗️"] = ":reminder_ribbon:"; - _textToEmoji[":ticket:"] = "🎫"; - _emojiToText["🎫"] = ":ticket:"; - _textToEmoji[":tickets:"] = "🎟️"; - _emojiToText["🎟️"] = ":tickets:"; - _textToEmoji[":admission_tickets:"] = "🎟️"; - _emojiToText["🎟️"] = ":admission_tickets:"; - _textToEmoji[":circus_tent:"] = "🎪"; - _emojiToText["🎪"] = ":circus_tent:"; - _textToEmoji[":person_juggling:"] = "🤹"; - _emojiToText["🤹"] = ":person_juggling:"; - _textToEmoji[":juggling:"] = "🤹"; - _emojiToText["🤹"] = ":juggling:"; - _textToEmoji[":juggler:"] = "🤹"; - _emojiToText["🤹"] = ":juggler:"; - _textToEmoji[":woman_juggling:"] = "🤹‍♀️"; - _emojiToText["🤹‍♀️"] = ":woman_juggling:"; - _textToEmoji[":man_juggling:"] = "🤹‍♂️"; - _emojiToText["🤹‍♂️"] = ":man_juggling:"; - _textToEmoji[":performing_arts:"] = "🎭"; - _emojiToText["🎭"] = ":performing_arts:"; - _textToEmoji[":ballet_shoes:"] = "🩰"; - _emojiToText["🩰"] = ":ballet_shoes:"; - _textToEmoji[":art:"] = "🎨"; - _emojiToText["🎨"] = ":art:"; - _textToEmoji[":clapper:"] = "🎬"; - _emojiToText["🎬"] = ":clapper:"; - _textToEmoji[":clapper_board:"] = "🎬"; - _emojiToText["🎬"] = ":clapper_board:"; - _textToEmoji[":microphone:"] = "🎤"; - _emojiToText["🎤"] = ":microphone:"; - _textToEmoji[":headphones:"] = "🎧"; - _emojiToText["🎧"] = ":headphones:"; - _textToEmoji[":headphone:"] = "🎧"; - _emojiToText["🎧"] = ":headphone:"; - _textToEmoji[":musical_score:"] = "🎼"; - _emojiToText["🎼"] = ":musical_score:"; - _textToEmoji[":musical_keyboard:"] = "🎹"; - _emojiToText["🎹"] = ":musical_keyboard:"; - _textToEmoji[":maracas:"] = "🪇"; - _emojiToText["🪇"] = ":maracas:"; - _textToEmoji[":drum:"] = "🥁"; - _emojiToText["🥁"] = ":drum:"; - _textToEmoji[":drum_with_drumsticks:"] = "🥁"; - _emojiToText["🥁"] = ":drum_with_drumsticks:"; - _textToEmoji[":long_drum:"] = "🪘"; - _emojiToText["🪘"] = ":long_drum:"; - _textToEmoji[":saxophone:"] = "🎷"; - _emojiToText["🎷"] = ":saxophone:"; - _textToEmoji[":trumpet:"] = "🎺"; - _emojiToText["🎺"] = ":trumpet:"; - _textToEmoji[":accordion:"] = "🪗"; - _emojiToText["🪗"] = ":accordion:"; - _textToEmoji[":guitar:"] = "🎸"; - _emojiToText["🎸"] = ":guitar:"; - _textToEmoji[":banjo:"] = "🪕"; - _emojiToText["🪕"] = ":banjo:"; - _textToEmoji[":violin:"] = "🎻"; - _emojiToText["🎻"] = ":violin:"; - _textToEmoji[":flute:"] = "🪈"; - _emojiToText["🪈"] = ":flute:"; - _textToEmoji[":game_die:"] = "🎲"; - _emojiToText["🎲"] = ":game_die:"; - _textToEmoji[":chess_pawn:"] = "♟️"; - _emojiToText["♟️"] = ":chess_pawn:"; - _textToEmoji[":dart:"] = "🎯"; - _emojiToText["🎯"] = ":dart:"; - _textToEmoji[":direct_hit:"] = "🎯"; - _emojiToText["🎯"] = ":direct_hit:"; - _textToEmoji[":bowling:"] = "🎳"; - _emojiToText["🎳"] = ":bowling:"; - _textToEmoji[":video_game:"] = "🎮"; - _emojiToText["🎮"] = ":video_game:"; - _textToEmoji[":slot_machine:"] = "🎰"; - _emojiToText["🎰"] = ":slot_machine:"; - _textToEmoji[":jigsaw:"] = "🧩"; - _emojiToText["🧩"] = ":jigsaw:"; - _textToEmoji[":puzzle_piece:"] = "🧩"; - _emojiToText["🧩"] = ":puzzle_piece:"; - _textToEmoji[":flag_white:"] = "🏳️"; - _emojiToText["🏳️"] = ":flag_white:"; - _textToEmoji[":flag_black:"] = "🏴"; - _emojiToText["🏴"] = ":flag_black:"; - _textToEmoji[":pirate_flag:"] = "🏴‍☠️"; - _emojiToText["🏴‍☠️"] = ":pirate_flag:"; - _textToEmoji[":checkered_flag:"] = "🏁"; - _emojiToText["🏁"] = ":checkered_flag:"; - _textToEmoji[":triangular_flag_on_post:"] = "🚩"; - _emojiToText["🚩"] = ":triangular_flag_on_post:"; - _textToEmoji[":rainbow_flag:"] = "🏳️‍🌈"; - _emojiToText["🏳️‍🌈"] = ":rainbow_flag:"; - _textToEmoji[":gay_pride_flag:"] = "🏳️‍🌈"; - _emojiToText["🏳️‍🌈"] = ":gay_pride_flag:"; - _textToEmoji[":transgender_flag:"] = "🏳️‍⚧️"; - _emojiToText["🏳️‍⚧️"] = ":transgender_flag:"; - _textToEmoji[":united_nations:"] = "🇺🇳"; - _emojiToText["🇺🇳"] = ":united_nations:"; - _textToEmoji[":flag_af:"] = "🇦🇫"; - _emojiToText["🇦🇫"] = ":flag_af:"; - _textToEmoji[":flag_ax:"] = "🇦🇽"; - _emojiToText["🇦🇽"] = ":flag_ax:"; - _textToEmoji[":flag_al:"] = "🇦🇱"; - _emojiToText["🇦🇱"] = ":flag_al:"; - _textToEmoji[":flag_dz:"] = "🇩🇿"; - _emojiToText["🇩🇿"] = ":flag_dz:"; - _textToEmoji[":flag_as:"] = "🇦🇸"; - _emojiToText["🇦🇸"] = ":flag_as:"; - _textToEmoji[":flag_ad:"] = "🇦🇩"; - _emojiToText["🇦🇩"] = ":flag_ad:"; - _textToEmoji[":flag_ao:"] = "🇦🇴"; - _emojiToText["🇦🇴"] = ":flag_ao:"; - _textToEmoji[":flag_ai:"] = "🇦🇮"; - _emojiToText["🇦🇮"] = ":flag_ai:"; - _textToEmoji[":flag_aq:"] = "🇦🇶"; - _emojiToText["🇦🇶"] = ":flag_aq:"; - _textToEmoji[":flag_ag:"] = "🇦🇬"; - _emojiToText["🇦🇬"] = ":flag_ag:"; - _textToEmoji[":flag_ar:"] = "🇦🇷"; - _emojiToText["🇦🇷"] = ":flag_ar:"; - _textToEmoji[":flag_am:"] = "🇦🇲"; - _emojiToText["🇦🇲"] = ":flag_am:"; - _textToEmoji[":flag_aw:"] = "🇦🇼"; - _emojiToText["🇦🇼"] = ":flag_aw:"; - _textToEmoji[":flag_au:"] = "🇦🇺"; - _emojiToText["🇦🇺"] = ":flag_au:"; - _textToEmoji[":flag_at:"] = "🇦🇹"; - _emojiToText["🇦🇹"] = ":flag_at:"; - _textToEmoji[":flag_az:"] = "🇦🇿"; - _emojiToText["🇦🇿"] = ":flag_az:"; - _textToEmoji[":flag_bs:"] = "🇧🇸"; - _emojiToText["🇧🇸"] = ":flag_bs:"; - _textToEmoji[":flag_bh:"] = "🇧🇭"; - _emojiToText["🇧🇭"] = ":flag_bh:"; - _textToEmoji[":flag_bd:"] = "🇧🇩"; - _emojiToText["🇧🇩"] = ":flag_bd:"; - _textToEmoji[":flag_bb:"] = "🇧🇧"; - _emojiToText["🇧🇧"] = ":flag_bb:"; - _textToEmoji[":flag_by:"] = "🇧🇾"; - _emojiToText["🇧🇾"] = ":flag_by:"; - _textToEmoji[":flag_be:"] = "🇧🇪"; - _emojiToText["🇧🇪"] = ":flag_be:"; - _textToEmoji[":flag_bz:"] = "🇧🇿"; - _emojiToText["🇧🇿"] = ":flag_bz:"; - _textToEmoji[":flag_bj:"] = "🇧🇯"; - _emojiToText["🇧🇯"] = ":flag_bj:"; - _textToEmoji[":flag_bm:"] = "🇧🇲"; - _emojiToText["🇧🇲"] = ":flag_bm:"; - _textToEmoji[":flag_bt:"] = "🇧🇹"; - _emojiToText["🇧🇹"] = ":flag_bt:"; - _textToEmoji[":flag_bo:"] = "🇧🇴"; - _emojiToText["🇧🇴"] = ":flag_bo:"; - _textToEmoji[":flag_ba:"] = "🇧🇦"; - _emojiToText["🇧🇦"] = ":flag_ba:"; - _textToEmoji[":flag_bw:"] = "🇧🇼"; - _emojiToText["🇧🇼"] = ":flag_bw:"; - _textToEmoji[":flag_br:"] = "🇧🇷"; - _emojiToText["🇧🇷"] = ":flag_br:"; - _textToEmoji[":flag_io:"] = "🇮🇴"; - _emojiToText["🇮🇴"] = ":flag_io:"; - _textToEmoji[":flag_vg:"] = "🇻🇬"; - _emojiToText["🇻🇬"] = ":flag_vg:"; - _textToEmoji[":flag_bn:"] = "🇧🇳"; - _emojiToText["🇧🇳"] = ":flag_bn:"; - _textToEmoji[":flag_bg:"] = "🇧🇬"; - _emojiToText["🇧🇬"] = ":flag_bg:"; - _textToEmoji[":flag_bf:"] = "🇧🇫"; - _emojiToText["🇧🇫"] = ":flag_bf:"; - _textToEmoji[":flag_bi:"] = "🇧🇮"; - _emojiToText["🇧🇮"] = ":flag_bi:"; - _textToEmoji[":flag_kh:"] = "🇰🇭"; - _emojiToText["🇰🇭"] = ":flag_kh:"; - _textToEmoji[":flag_cm:"] = "🇨🇲"; - _emojiToText["🇨🇲"] = ":flag_cm:"; - _textToEmoji[":flag_ca:"] = "🇨🇦"; - _emojiToText["🇨🇦"] = ":flag_ca:"; - _textToEmoji[":flag_ic:"] = "🇮🇨"; - _emojiToText["🇮🇨"] = ":flag_ic:"; - _textToEmoji[":flag_cv:"] = "🇨🇻"; - _emojiToText["🇨🇻"] = ":flag_cv:"; - _textToEmoji[":flag_bq:"] = "🇧🇶"; - _emojiToText["🇧🇶"] = ":flag_bq:"; - _textToEmoji[":flag_ky:"] = "🇰🇾"; - _emojiToText["🇰🇾"] = ":flag_ky:"; - _textToEmoji[":flag_cf:"] = "🇨🇫"; - _emojiToText["🇨🇫"] = ":flag_cf:"; - _textToEmoji[":flag_td:"] = "🇹🇩"; - _emojiToText["🇹🇩"] = ":flag_td:"; - _textToEmoji[":flag_cl:"] = "🇨🇱"; - _emojiToText["🇨🇱"] = ":flag_cl:"; - _textToEmoji[":flag_cn:"] = "🇨🇳"; - _emojiToText["🇨🇳"] = ":flag_cn:"; - _textToEmoji[":flag_cx:"] = "🇨🇽"; - _emojiToText["🇨🇽"] = ":flag_cx:"; - _textToEmoji[":flag_cc:"] = "🇨🇨"; - _emojiToText["🇨🇨"] = ":flag_cc:"; - _textToEmoji[":flag_co:"] = "🇨🇴"; - _emojiToText["🇨🇴"] = ":flag_co:"; - _textToEmoji[":flag_km:"] = "🇰🇲"; - _emojiToText["🇰🇲"] = ":flag_km:"; - _textToEmoji[":flag_cg:"] = "🇨🇬"; - _emojiToText["🇨🇬"] = ":flag_cg:"; - _textToEmoji[":flag_cd:"] = "🇨🇩"; - _emojiToText["🇨🇩"] = ":flag_cd:"; - _textToEmoji[":flag_ck:"] = "🇨🇰"; - _emojiToText["🇨🇰"] = ":flag_ck:"; - _textToEmoji[":flag_cr:"] = "🇨🇷"; - _emojiToText["🇨🇷"] = ":flag_cr:"; - _textToEmoji[":flag_ci:"] = "🇨🇮"; - _emojiToText["🇨🇮"] = ":flag_ci:"; - _textToEmoji[":flag_hr:"] = "🇭🇷"; - _emojiToText["🇭🇷"] = ":flag_hr:"; - _textToEmoji[":flag_cu:"] = "🇨🇺"; - _emojiToText["🇨🇺"] = ":flag_cu:"; - _textToEmoji[":flag_cw:"] = "🇨🇼"; - _emojiToText["🇨🇼"] = ":flag_cw:"; - _textToEmoji[":flag_cy:"] = "🇨🇾"; - _emojiToText["🇨🇾"] = ":flag_cy:"; - _textToEmoji[":flag_cz:"] = "🇨🇿"; - _emojiToText["🇨🇿"] = ":flag_cz:"; - _textToEmoji[":flag_dk:"] = "🇩🇰"; - _emojiToText["🇩🇰"] = ":flag_dk:"; - _textToEmoji[":flag_dj:"] = "🇩🇯"; - _emojiToText["🇩🇯"] = ":flag_dj:"; - _textToEmoji[":flag_dm:"] = "🇩🇲"; - _emojiToText["🇩🇲"] = ":flag_dm:"; - _textToEmoji[":flag_do:"] = "🇩🇴"; - _emojiToText["🇩🇴"] = ":flag_do:"; - _textToEmoji[":flag_ec:"] = "🇪🇨"; - _emojiToText["🇪🇨"] = ":flag_ec:"; - _textToEmoji[":flag_eg:"] = "🇪🇬"; - _emojiToText["🇪🇬"] = ":flag_eg:"; - _textToEmoji[":flag_sv:"] = "🇸🇻"; - _emojiToText["🇸🇻"] = ":flag_sv:"; - _textToEmoji[":flag_gq:"] = "🇬🇶"; - _emojiToText["🇬🇶"] = ":flag_gq:"; - _textToEmoji[":flag_er:"] = "🇪🇷"; - _emojiToText["🇪🇷"] = ":flag_er:"; - _textToEmoji[":flag_ee:"] = "🇪🇪"; - _emojiToText["🇪🇪"] = ":flag_ee:"; - _textToEmoji[":flag_et:"] = "🇪🇹"; - _emojiToText["🇪🇹"] = ":flag_et:"; - _textToEmoji[":flag_eu:"] = "🇪🇺"; - _emojiToText["🇪🇺"] = ":flag_eu:"; - _textToEmoji[":flag_fk:"] = "🇫🇰"; - _emojiToText["🇫🇰"] = ":flag_fk:"; - _textToEmoji[":flag_fo:"] = "🇫🇴"; - _emojiToText["🇫🇴"] = ":flag_fo:"; - _textToEmoji[":flag_fj:"] = "🇫🇯"; - _emojiToText["🇫🇯"] = ":flag_fj:"; - _textToEmoji[":flag_fi:"] = "🇫🇮"; - _emojiToText["🇫🇮"] = ":flag_fi:"; - _textToEmoji[":flag_fr:"] = "🇫🇷"; - _emojiToText["🇫🇷"] = ":flag_fr:"; - _textToEmoji[":flag_gf:"] = "🇬🇫"; - _emojiToText["🇬🇫"] = ":flag_gf:"; - _textToEmoji[":flag_pf:"] = "🇵🇫"; - _emojiToText["🇵🇫"] = ":flag_pf:"; - _textToEmoji[":flag_tf:"] = "🇹🇫"; - _emojiToText["🇹🇫"] = ":flag_tf:"; - _textToEmoji[":flag_ga:"] = "🇬🇦"; - _emojiToText["🇬🇦"] = ":flag_ga:"; - _textToEmoji[":flag_gm:"] = "🇬🇲"; - _emojiToText["🇬🇲"] = ":flag_gm:"; - _textToEmoji[":flag_ge:"] = "🇬🇪"; - _emojiToText["🇬🇪"] = ":flag_ge:"; - _textToEmoji[":flag_de:"] = "🇩🇪"; - _emojiToText["🇩🇪"] = ":flag_de:"; - _textToEmoji[":flag_gh:"] = "🇬🇭"; - _emojiToText["🇬🇭"] = ":flag_gh:"; - _textToEmoji[":flag_gi:"] = "🇬🇮"; - _emojiToText["🇬🇮"] = ":flag_gi:"; - _textToEmoji[":flag_gr:"] = "🇬🇷"; - _emojiToText["🇬🇷"] = ":flag_gr:"; - _textToEmoji[":flag_gl:"] = "🇬🇱"; - _emojiToText["🇬🇱"] = ":flag_gl:"; - _textToEmoji[":flag_gd:"] = "🇬🇩"; - _emojiToText["🇬🇩"] = ":flag_gd:"; - _textToEmoji[":flag_gp:"] = "🇬🇵"; - _emojiToText["🇬🇵"] = ":flag_gp:"; - _textToEmoji[":flag_gu:"] = "🇬🇺"; - _emojiToText["🇬🇺"] = ":flag_gu:"; - _textToEmoji[":flag_gt:"] = "🇬🇹"; - _emojiToText["🇬🇹"] = ":flag_gt:"; - _textToEmoji[":flag_gg:"] = "🇬🇬"; - _emojiToText["🇬🇬"] = ":flag_gg:"; - _textToEmoji[":flag_gn:"] = "🇬🇳"; - _emojiToText["🇬🇳"] = ":flag_gn:"; - _textToEmoji[":flag_gw:"] = "🇬🇼"; - _emojiToText["🇬🇼"] = ":flag_gw:"; - _textToEmoji[":flag_gy:"] = "🇬🇾"; - _emojiToText["🇬🇾"] = ":flag_gy:"; - _textToEmoji[":flag_ht:"] = "🇭🇹"; - _emojiToText["🇭🇹"] = ":flag_ht:"; - _textToEmoji[":flag_hn:"] = "🇭🇳"; - _emojiToText["🇭🇳"] = ":flag_hn:"; - _textToEmoji[":flag_hk:"] = "🇭🇰"; - _emojiToText["🇭🇰"] = ":flag_hk:"; - _textToEmoji[":flag_hu:"] = "🇭🇺"; - _emojiToText["🇭🇺"] = ":flag_hu:"; - _textToEmoji[":flag_is:"] = "🇮🇸"; - _emojiToText["🇮🇸"] = ":flag_is:"; - _textToEmoji[":flag_in:"] = "🇮🇳"; - _emojiToText["🇮🇳"] = ":flag_in:"; - _textToEmoji[":flag_id:"] = "🇮🇩"; - _emojiToText["🇮🇩"] = ":flag_id:"; - _textToEmoji[":flag_ir:"] = "🇮🇷"; - _emojiToText["🇮🇷"] = ":flag_ir:"; - _textToEmoji[":flag_iq:"] = "🇮🇶"; - _emojiToText["🇮🇶"] = ":flag_iq:"; - _textToEmoji[":flag_ie:"] = "🇮🇪"; - _emojiToText["🇮🇪"] = ":flag_ie:"; - _textToEmoji[":flag_im:"] = "🇮🇲"; - _emojiToText["🇮🇲"] = ":flag_im:"; - _textToEmoji[":flag_il:"] = "🇮🇱"; - _emojiToText["🇮🇱"] = ":flag_il:"; - _textToEmoji[":flag_it:"] = "🇮🇹"; - _emojiToText["🇮🇹"] = ":flag_it:"; - _textToEmoji[":flag_jm:"] = "🇯🇲"; - _emojiToText["🇯🇲"] = ":flag_jm:"; - _textToEmoji[":flag_jp:"] = "🇯🇵"; - _emojiToText["🇯🇵"] = ":flag_jp:"; - _textToEmoji[":crossed_flags:"] = "🎌"; - _emojiToText["🎌"] = ":crossed_flags:"; - _textToEmoji[":flag_je:"] = "🇯🇪"; - _emojiToText["🇯🇪"] = ":flag_je:"; - _textToEmoji[":flag_jo:"] = "🇯🇴"; - _emojiToText["🇯🇴"] = ":flag_jo:"; - _textToEmoji[":flag_kz:"] = "🇰🇿"; - _emojiToText["🇰🇿"] = ":flag_kz:"; - _textToEmoji[":flag_ke:"] = "🇰🇪"; - _emojiToText["🇰🇪"] = ":flag_ke:"; - _textToEmoji[":flag_ki:"] = "🇰🇮"; - _emojiToText["🇰🇮"] = ":flag_ki:"; - _textToEmoji[":flag_xk:"] = "🇽🇰"; - _emojiToText["🇽🇰"] = ":flag_xk:"; - _textToEmoji[":flag_kw:"] = "🇰🇼"; - _emojiToText["🇰🇼"] = ":flag_kw:"; - _textToEmoji[":flag_kg:"] = "🇰🇬"; - _emojiToText["🇰🇬"] = ":flag_kg:"; - _textToEmoji[":flag_la:"] = "🇱🇦"; - _emojiToText["🇱🇦"] = ":flag_la:"; - _textToEmoji[":flag_lv:"] = "🇱🇻"; - _emojiToText["🇱🇻"] = ":flag_lv:"; - _textToEmoji[":flag_lb:"] = "🇱🇧"; - _emojiToText["🇱🇧"] = ":flag_lb:"; - _textToEmoji[":flag_ls:"] = "🇱🇸"; - _emojiToText["🇱🇸"] = ":flag_ls:"; - _textToEmoji[":flag_lr:"] = "🇱🇷"; - _emojiToText["🇱🇷"] = ":flag_lr:"; - _textToEmoji[":flag_ly:"] = "🇱🇾"; - _emojiToText["🇱🇾"] = ":flag_ly:"; - _textToEmoji[":flag_li:"] = "🇱🇮"; - _emojiToText["🇱🇮"] = ":flag_li:"; - _textToEmoji[":flag_lt:"] = "🇱🇹"; - _emojiToText["🇱🇹"] = ":flag_lt:"; - _textToEmoji[":flag_lu:"] = "🇱🇺"; - _emojiToText["🇱🇺"] = ":flag_lu:"; - _textToEmoji[":flag_mo:"] = "🇲🇴"; - _emojiToText["🇲🇴"] = ":flag_mo:"; - _textToEmoji[":flag_mk:"] = "🇲🇰"; - _emojiToText["🇲🇰"] = ":flag_mk:"; - _textToEmoji[":flag_mg:"] = "🇲🇬"; - _emojiToText["🇲🇬"] = ":flag_mg:"; - _textToEmoji[":flag_mw:"] = "🇲🇼"; - _emojiToText["🇲🇼"] = ":flag_mw:"; - _textToEmoji[":flag_my:"] = "🇲🇾"; - _emojiToText["🇲🇾"] = ":flag_my:"; - _textToEmoji[":flag_mv:"] = "🇲🇻"; - _emojiToText["🇲🇻"] = ":flag_mv:"; - _textToEmoji[":flag_ml:"] = "🇲🇱"; - _emojiToText["🇲🇱"] = ":flag_ml:"; - _textToEmoji[":flag_mt:"] = "🇲🇹"; - _emojiToText["🇲🇹"] = ":flag_mt:"; - _textToEmoji[":flag_mh:"] = "🇲🇭"; - _emojiToText["🇲🇭"] = ":flag_mh:"; - _textToEmoji[":flag_mq:"] = "🇲🇶"; - _emojiToText["🇲🇶"] = ":flag_mq:"; - _textToEmoji[":flag_mr:"] = "🇲🇷"; - _emojiToText["🇲🇷"] = ":flag_mr:"; - _textToEmoji[":flag_mu:"] = "🇲🇺"; - _emojiToText["🇲🇺"] = ":flag_mu:"; - _textToEmoji[":flag_yt:"] = "🇾🇹"; - _emojiToText["🇾🇹"] = ":flag_yt:"; - _textToEmoji[":flag_mx:"] = "🇲🇽"; - _emojiToText["🇲🇽"] = ":flag_mx:"; - _textToEmoji[":flag_fm:"] = "🇫🇲"; - _emojiToText["🇫🇲"] = ":flag_fm:"; - _textToEmoji[":flag_md:"] = "🇲🇩"; - _emojiToText["🇲🇩"] = ":flag_md:"; - _textToEmoji[":flag_mc:"] = "🇲🇨"; - _emojiToText["🇲🇨"] = ":flag_mc:"; - _textToEmoji[":flag_mn:"] = "🇲🇳"; - _emojiToText["🇲🇳"] = ":flag_mn:"; - _textToEmoji[":flag_me:"] = "🇲🇪"; - _emojiToText["🇲🇪"] = ":flag_me:"; - _textToEmoji[":flag_ms:"] = "🇲🇸"; - _emojiToText["🇲🇸"] = ":flag_ms:"; - _textToEmoji[":flag_ma:"] = "🇲🇦"; - _emojiToText["🇲🇦"] = ":flag_ma:"; - _textToEmoji[":flag_mz:"] = "🇲🇿"; - _emojiToText["🇲🇿"] = ":flag_mz:"; - _textToEmoji[":flag_mm:"] = "🇲🇲"; - _emojiToText["🇲🇲"] = ":flag_mm:"; - _textToEmoji[":flag_na:"] = "🇳🇦"; - _emojiToText["🇳🇦"] = ":flag_na:"; - _textToEmoji[":flag_nr:"] = "🇳🇷"; - _emojiToText["🇳🇷"] = ":flag_nr:"; - _textToEmoji[":flag_np:"] = "🇳🇵"; - _emojiToText["🇳🇵"] = ":flag_np:"; - _textToEmoji[":flag_nl:"] = "🇳🇱"; - _emojiToText["🇳🇱"] = ":flag_nl:"; - _textToEmoji[":flag_nc:"] = "🇳🇨"; - _emojiToText["🇳🇨"] = ":flag_nc:"; - _textToEmoji[":flag_nz:"] = "🇳🇿"; - _emojiToText["🇳🇿"] = ":flag_nz:"; - _textToEmoji[":flag_ni:"] = "🇳🇮"; - _emojiToText["🇳🇮"] = ":flag_ni:"; - _textToEmoji[":flag_ne:"] = "🇳🇪"; - _emojiToText["🇳🇪"] = ":flag_ne:"; - _textToEmoji[":flag_ng:"] = "🇳🇬"; - _emojiToText["🇳🇬"] = ":flag_ng:"; - _textToEmoji[":flag_nu:"] = "🇳🇺"; - _emojiToText["🇳🇺"] = ":flag_nu:"; - _textToEmoji[":flag_nf:"] = "🇳🇫"; - _emojiToText["🇳🇫"] = ":flag_nf:"; - _textToEmoji[":flag_kp:"] = "🇰🇵"; - _emojiToText["🇰🇵"] = ":flag_kp:"; - _textToEmoji[":flag_mp:"] = "🇲🇵"; - _emojiToText["🇲🇵"] = ":flag_mp:"; - _textToEmoji[":flag_no:"] = "🇳🇴"; - _emojiToText["🇳🇴"] = ":flag_no:"; - _textToEmoji[":flag_om:"] = "🇴🇲"; - _emojiToText["🇴🇲"] = ":flag_om:"; - _textToEmoji[":flag_pk:"] = "🇵🇰"; - _emojiToText["🇵🇰"] = ":flag_pk:"; - _textToEmoji[":flag_pw:"] = "🇵🇼"; - _emojiToText["🇵🇼"] = ":flag_pw:"; - _textToEmoji[":flag_ps:"] = "🇵🇸"; - _emojiToText["🇵🇸"] = ":flag_ps:"; - _textToEmoji[":flag_pa:"] = "🇵🇦"; - _emojiToText["🇵🇦"] = ":flag_pa:"; - _textToEmoji[":flag_pg:"] = "🇵🇬"; - _emojiToText["🇵🇬"] = ":flag_pg:"; - _textToEmoji[":flag_py:"] = "🇵🇾"; - _emojiToText["🇵🇾"] = ":flag_py:"; - _textToEmoji[":flag_pe:"] = "🇵🇪"; - _emojiToText["🇵🇪"] = ":flag_pe:"; - _textToEmoji[":flag_ph:"] = "🇵🇭"; - _emojiToText["🇵🇭"] = ":flag_ph:"; - _textToEmoji[":flag_pn:"] = "🇵🇳"; - _emojiToText["🇵🇳"] = ":flag_pn:"; - _textToEmoji[":flag_pl:"] = "🇵🇱"; - _emojiToText["🇵🇱"] = ":flag_pl:"; - _textToEmoji[":flag_pt:"] = "🇵🇹"; - _emojiToText["🇵🇹"] = ":flag_pt:"; - _textToEmoji[":flag_pr:"] = "🇵🇷"; - _emojiToText["🇵🇷"] = ":flag_pr:"; - _textToEmoji[":flag_qa:"] = "🇶🇦"; - _emojiToText["🇶🇦"] = ":flag_qa:"; - _textToEmoji[":flag_re:"] = "🇷🇪"; - _emojiToText["🇷🇪"] = ":flag_re:"; - _textToEmoji[":flag_ro:"] = "🇷🇴"; - _emojiToText["🇷🇴"] = ":flag_ro:"; - _textToEmoji[":flag_ru:"] = "🇷🇺"; - _emojiToText["🇷🇺"] = ":flag_ru:"; - _textToEmoji[":flag_rw:"] = "🇷🇼"; - _emojiToText["🇷🇼"] = ":flag_rw:"; - _textToEmoji[":flag_ws:"] = "🇼🇸"; - _emojiToText["🇼🇸"] = ":flag_ws:"; - _textToEmoji[":flag_sm:"] = "🇸🇲"; - _emojiToText["🇸🇲"] = ":flag_sm:"; - _textToEmoji[":flag_st:"] = "🇸🇹"; - _emojiToText["🇸🇹"] = ":flag_st:"; - _textToEmoji[":flag_sa:"] = "🇸🇦"; - _emojiToText["🇸🇦"] = ":flag_sa:"; - _textToEmoji[":flag_sn:"] = "🇸🇳"; - _emojiToText["🇸🇳"] = ":flag_sn:"; - _textToEmoji[":flag_rs:"] = "🇷🇸"; - _emojiToText["🇷🇸"] = ":flag_rs:"; - _textToEmoji[":flag_sc:"] = "🇸🇨"; - _emojiToText["🇸🇨"] = ":flag_sc:"; - _textToEmoji[":flag_sl:"] = "🇸🇱"; - _emojiToText["🇸🇱"] = ":flag_sl:"; - _textToEmoji[":flag_sg:"] = "🇸🇬"; - _emojiToText["🇸🇬"] = ":flag_sg:"; - _textToEmoji[":flag_sx:"] = "🇸🇽"; - _emojiToText["🇸🇽"] = ":flag_sx:"; - _textToEmoji[":flag_sk:"] = "🇸🇰"; - _emojiToText["🇸🇰"] = ":flag_sk:"; - _textToEmoji[":flag_si:"] = "🇸🇮"; - _emojiToText["🇸🇮"] = ":flag_si:"; - _textToEmoji[":flag_gs:"] = "🇬🇸"; - _emojiToText["🇬🇸"] = ":flag_gs:"; - _textToEmoji[":flag_sb:"] = "🇸🇧"; - _emojiToText["🇸🇧"] = ":flag_sb:"; - _textToEmoji[":flag_so:"] = "🇸🇴"; - _emojiToText["🇸🇴"] = ":flag_so:"; - _textToEmoji[":flag_za:"] = "🇿🇦"; - _emojiToText["🇿🇦"] = ":flag_za:"; - _textToEmoji[":flag_kr:"] = "🇰🇷"; - _emojiToText["🇰🇷"] = ":flag_kr:"; - _textToEmoji[":flag_ss:"] = "🇸🇸"; - _emojiToText["🇸🇸"] = ":flag_ss:"; - _textToEmoji[":flag_es:"] = "🇪🇸"; - _emojiToText["🇪🇸"] = ":flag_es:"; - _textToEmoji[":flag_lk:"] = "🇱🇰"; - _emojiToText["🇱🇰"] = ":flag_lk:"; - _textToEmoji[":flag_bl:"] = "🇧🇱"; - _emojiToText["🇧🇱"] = ":flag_bl:"; - _textToEmoji[":flag_sh:"] = "🇸🇭"; - _emojiToText["🇸🇭"] = ":flag_sh:"; - _textToEmoji[":flag_kn:"] = "🇰🇳"; - _emojiToText["🇰🇳"] = ":flag_kn:"; - _textToEmoji[":flag_lc:"] = "🇱🇨"; - _emojiToText["🇱🇨"] = ":flag_lc:"; - _textToEmoji[":flag_pm:"] = "🇵🇲"; - _emojiToText["🇵🇲"] = ":flag_pm:"; - _textToEmoji[":flag_vc:"] = "🇻🇨"; - _emojiToText["🇻🇨"] = ":flag_vc:"; - _textToEmoji[":flag_sd:"] = "🇸🇩"; - _emojiToText["🇸🇩"] = ":flag_sd:"; - _textToEmoji[":flag_sr:"] = "🇸🇷"; - _emojiToText["🇸🇷"] = ":flag_sr:"; - _textToEmoji[":flag_sz:"] = "🇸🇿"; - _emojiToText["🇸🇿"] = ":flag_sz:"; - _textToEmoji[":flag_se:"] = "🇸🇪"; - _emojiToText["🇸🇪"] = ":flag_se:"; - _textToEmoji[":flag_ch:"] = "🇨🇭"; - _emojiToText["🇨🇭"] = ":flag_ch:"; - _textToEmoji[":flag_sy:"] = "🇸🇾"; - _emojiToText["🇸🇾"] = ":flag_sy:"; - _textToEmoji[":flag_tw:"] = "🇹🇼"; - _emojiToText["🇹🇼"] = ":flag_tw:"; - _textToEmoji[":flag_tj:"] = "🇹🇯"; - _emojiToText["🇹🇯"] = ":flag_tj:"; - _textToEmoji[":flag_tz:"] = "🇹🇿"; - _emojiToText["🇹🇿"] = ":flag_tz:"; - _textToEmoji[":flag_th:"] = "🇹🇭"; - _emojiToText["🇹🇭"] = ":flag_th:"; - _textToEmoji[":flag_tl:"] = "🇹🇱"; - _emojiToText["🇹🇱"] = ":flag_tl:"; - _textToEmoji[":flag_tg:"] = "🇹🇬"; - _emojiToText["🇹🇬"] = ":flag_tg:"; - _textToEmoji[":flag_tk:"] = "🇹🇰"; - _emojiToText["🇹🇰"] = ":flag_tk:"; - _textToEmoji[":flag_to:"] = "🇹🇴"; - _emojiToText["🇹🇴"] = ":flag_to:"; - _textToEmoji[":flag_tt:"] = "🇹🇹"; - _emojiToText["🇹🇹"] = ":flag_tt:"; - _textToEmoji[":flag_tn:"] = "🇹🇳"; - _emojiToText["🇹🇳"] = ":flag_tn:"; - _textToEmoji[":flag_tr:"] = "🇹🇷"; - _emojiToText["🇹🇷"] = ":flag_tr:"; - _textToEmoji[":flag_tm:"] = "🇹🇲"; - _emojiToText["🇹🇲"] = ":flag_tm:"; - _textToEmoji[":flag_tc:"] = "🇹🇨"; - _emojiToText["🇹🇨"] = ":flag_tc:"; - _textToEmoji[":flag_vi:"] = "🇻🇮"; - _emojiToText["🇻🇮"] = ":flag_vi:"; - _textToEmoji[":flag_tv:"] = "🇹🇻"; - _emojiToText["🇹🇻"] = ":flag_tv:"; - _textToEmoji[":flag_ug:"] = "🇺🇬"; - _emojiToText["🇺🇬"] = ":flag_ug:"; - _textToEmoji[":flag_ua:"] = "🇺🇦"; - _emojiToText["🇺🇦"] = ":flag_ua:"; - _textToEmoji[":flag_ae:"] = "🇦🇪"; - _emojiToText["🇦🇪"] = ":flag_ae:"; - _textToEmoji[":flag_gb:"] = "🇬🇧"; - _emojiToText["🇬🇧"] = ":flag_gb:"; - _textToEmoji[":england:"] = "🏴󠁧󠁢󠁥󠁮󠁧󠁿"; - _emojiToText["🏴󠁧󠁢󠁥󠁮󠁧󠁿"] = ":england:"; - _textToEmoji[":scotland:"] = "🏴󠁧󠁢󠁳󠁣󠁴󠁿"; - _emojiToText["🏴󠁧󠁢󠁳󠁣󠁴󠁿"] = ":scotland:"; - _textToEmoji[":wales:"] = "🏴󠁧󠁢󠁷󠁬󠁳󠁿"; - _emojiToText["🏴󠁧󠁢󠁷󠁬󠁳󠁿"] = ":wales:"; - _textToEmoji[":flag_us:"] = "🇺🇸"; - _emojiToText["🇺🇸"] = ":flag_us:"; - _textToEmoji[":flag_uy:"] = "🇺🇾"; - _emojiToText["🇺🇾"] = ":flag_uy:"; - _textToEmoji[":flag_uz:"] = "🇺🇿"; - _emojiToText["🇺🇿"] = ":flag_uz:"; - _textToEmoji[":flag_vu:"] = "🇻🇺"; - _emojiToText["🇻🇺"] = ":flag_vu:"; - _textToEmoji[":flag_va:"] = "🇻🇦"; - _emojiToText["🇻🇦"] = ":flag_va:"; - _textToEmoji[":flag_ve:"] = "🇻🇪"; - _emojiToText["🇻🇪"] = ":flag_ve:"; - _textToEmoji[":flag_vn:"] = "🇻🇳"; - _emojiToText["🇻🇳"] = ":flag_vn:"; - _textToEmoji[":flag_wf:"] = "🇼🇫"; - _emojiToText["🇼🇫"] = ":flag_wf:"; - _textToEmoji[":flag_eh:"] = "🇪🇭"; - _emojiToText["🇪🇭"] = ":flag_eh:"; - _textToEmoji[":flag_ye:"] = "🇾🇪"; - _emojiToText["🇾🇪"] = ":flag_ye:"; - _textToEmoji[":flag_zm:"] = "🇿🇲"; - _emojiToText["🇿🇲"] = ":flag_zm:"; - _textToEmoji[":flag_zw:"] = "🇿🇼"; - _emojiToText["🇿🇼"] = ":flag_zw:"; - _textToEmoji[":flag_ac:"] = "🇦🇨"; - _emojiToText["🇦🇨"] = ":flag_ac:"; - _textToEmoji[":flag_bv:"] = "🇧🇻"; - _emojiToText["🇧🇻"] = ":flag_bv:"; - _textToEmoji[":flag_cp:"] = "🇨🇵"; - _emojiToText["🇨🇵"] = ":flag_cp:"; - _textToEmoji[":flag_ea:"] = "🇪🇦"; - _emojiToText["🇪🇦"] = ":flag_ea:"; - _textToEmoji[":flag_dg:"] = "🇩🇬"; - _emojiToText["🇩🇬"] = ":flag_dg:"; - _textToEmoji[":flag_hm:"] = "🇭🇲"; - _emojiToText["🇭🇲"] = ":flag_hm:"; - _textToEmoji[":flag_mf:"] = "🇲🇫"; - _emojiToText["🇲🇫"] = ":flag_mf:"; - _textToEmoji[":flag_sj:"] = "🇸🇯"; - _emojiToText["🇸🇯"] = ":flag_sj:"; - _textToEmoji[":flag_ta:"] = "🇹🇦"; - _emojiToText["🇹🇦"] = ":flag_ta:"; - _textToEmoji[":flag_um:"] = "🇺🇲"; - _emojiToText["🇺🇲"] = ":flag_um:"; - _textToEmoji[":green_apple:"] = "🍏"; - _emojiToText["🍏"] = ":green_apple:"; - _textToEmoji[":apple:"] = "🍎"; - _emojiToText["🍎"] = ":apple:"; - _textToEmoji[":red_apple:"] = "🍎"; - _emojiToText["🍎"] = ":red_apple:"; - _textToEmoji[":pear:"] = "🍐"; - _emojiToText["🍐"] = ":pear:"; - _textToEmoji[":tangerine:"] = "🍊"; - _emojiToText["🍊"] = ":tangerine:"; - _textToEmoji[":lemon:"] = "🍋"; - _emojiToText["🍋"] = ":lemon:"; - _textToEmoji[":banana:"] = "🍌"; - _emojiToText["🍌"] = ":banana:"; - _textToEmoji[":watermelon:"] = "🍉"; - _emojiToText["🍉"] = ":watermelon:"; - _textToEmoji[":grapes:"] = "🍇"; - _emojiToText["🍇"] = ":grapes:"; - _textToEmoji[":strawberry:"] = "🍓"; - _emojiToText["🍓"] = ":strawberry:"; - _textToEmoji[":blueberries:"] = "🫐"; - _emojiToText["🫐"] = ":blueberries:"; - _textToEmoji[":melon:"] = "🍈"; - _emojiToText["🍈"] = ":melon:"; - _textToEmoji[":cherries:"] = "🍒"; - _emojiToText["🍒"] = ":cherries:"; - _textToEmoji[":peach:"] = "🍑"; - _emojiToText["🍑"] = ":peach:"; - _textToEmoji[":mango:"] = "🥭"; - _emojiToText["🥭"] = ":mango:"; - _textToEmoji[":pineapple:"] = "🍍"; - _emojiToText["🍍"] = ":pineapple:"; - _textToEmoji[":coconut:"] = "🥥"; - _emojiToText["🥥"] = ":coconut:"; - _textToEmoji[":kiwi:"] = "🥝"; - _emojiToText["🥝"] = ":kiwi:"; - _textToEmoji[":kiwifruit:"] = "🥝"; - _emojiToText["🥝"] = ":kiwifruit:"; - _textToEmoji[":kiwi_fruit:"] = "🥝"; - _emojiToText["🥝"] = ":kiwi_fruit:"; - _textToEmoji[":tomato:"] = "🍅"; - _emojiToText["🍅"] = ":tomato:"; - _textToEmoji[":eggplant:"] = "🍆"; - _emojiToText["🍆"] = ":eggplant:"; - _textToEmoji[":avocado:"] = "🥑"; - _emojiToText["🥑"] = ":avocado:"; - _textToEmoji[":pea_pod:"] = "🫛"; - _emojiToText["🫛"] = ":pea_pod:"; - _textToEmoji[":broccoli:"] = "🥦"; - _emojiToText["🥦"] = ":broccoli:"; - _textToEmoji[":leafy_green:"] = "🥬"; - _emojiToText["🥬"] = ":leafy_green:"; - _textToEmoji[":cucumber:"] = "🥒"; - _emojiToText["🥒"] = ":cucumber:"; - _textToEmoji[":hot_pepper:"] = "🌶️"; - _emojiToText["🌶️"] = ":hot_pepper:"; - _textToEmoji[":bell_pepper:"] = "🫑"; - _emojiToText["🫑"] = ":bell_pepper:"; - _textToEmoji[":corn:"] = "🌽"; - _emojiToText["🌽"] = ":corn:"; - _textToEmoji[":ear_of_corn:"] = "🌽"; - _emojiToText["🌽"] = ":ear_of_corn:"; - _textToEmoji[":carrot:"] = "🥕"; - _emojiToText["🥕"] = ":carrot:"; - _textToEmoji[":olive:"] = "🫒"; - _emojiToText["🫒"] = ":olive:"; - _textToEmoji[":garlic:"] = "🧄"; - _emojiToText["🧄"] = ":garlic:"; - _textToEmoji[":onion:"] = "🧅"; - _emojiToText["🧅"] = ":onion:"; - _textToEmoji[":potato:"] = "🥔"; - _emojiToText["🥔"] = ":potato:"; - _textToEmoji[":sweet_potato:"] = "🍠"; - _emojiToText["🍠"] = ":sweet_potato:"; - _textToEmoji[":ginger_root:"] = "🫚"; - _emojiToText["🫚"] = ":ginger_root:"; - _textToEmoji[":croissant:"] = "🥐"; - _emojiToText["🥐"] = ":croissant:"; - _textToEmoji[":bagel:"] = "🥯"; - _emojiToText["🥯"] = ":bagel:"; - _textToEmoji[":bread:"] = "🍞"; - _emojiToText["🍞"] = ":bread:"; - _textToEmoji[":french_bread:"] = "🥖"; - _emojiToText["🥖"] = ":french_bread:"; - _textToEmoji[":baguette_bread:"] = "🥖"; - _emojiToText["🥖"] = ":baguette_bread:"; - _textToEmoji[":pretzel:"] = "🥨"; - _emojiToText["🥨"] = ":pretzel:"; - _textToEmoji[":cheese:"] = "🧀"; - _emojiToText["🧀"] = ":cheese:"; - _textToEmoji[":cheese_wedge:"] = "🧀"; - _emojiToText["🧀"] = ":cheese_wedge:"; - _textToEmoji[":egg:"] = "🥚"; - _emojiToText["🥚"] = ":egg:"; - _textToEmoji[":cooking:"] = "🍳"; - _emojiToText["🍳"] = ":cooking:"; - _textToEmoji[":butter:"] = "🧈"; - _emojiToText["🧈"] = ":butter:"; - _textToEmoji[":pancakes:"] = "🥞"; - _emojiToText["🥞"] = ":pancakes:"; - _textToEmoji[":waffle:"] = "🧇"; - _emojiToText["🧇"] = ":waffle:"; - _textToEmoji[":bacon:"] = "🥓"; - _emojiToText["🥓"] = ":bacon:"; - _textToEmoji[":cut_of_meat:"] = "🥩"; - _emojiToText["🥩"] = ":cut_of_meat:"; - _textToEmoji[":poultry_leg:"] = "🍗"; - _emojiToText["🍗"] = ":poultry_leg:"; - _textToEmoji[":meat_on_bone:"] = "🍖"; - _emojiToText["🍖"] = ":meat_on_bone:"; - _textToEmoji[":bone:"] = "🦴"; - _emojiToText["🦴"] = ":bone:"; - _textToEmoji[":hotdog:"] = "🌭"; - _emojiToText["🌭"] = ":hotdog:"; - _textToEmoji[":hot_dog:"] = "🌭"; - _emojiToText["🌭"] = ":hot_dog:"; - _textToEmoji[":hamburger:"] = "🍔"; - _emojiToText["🍔"] = ":hamburger:"; - _textToEmoji[":fries:"] = "🍟"; - _emojiToText["🍟"] = ":fries:"; - _textToEmoji[":french_fries:"] = "🍟"; - _emojiToText["🍟"] = ":french_fries:"; - _textToEmoji[":pizza:"] = "🍕"; - _emojiToText["🍕"] = ":pizza:"; - _textToEmoji[":flatbread:"] = "🫓"; - _emojiToText["🫓"] = ":flatbread:"; - _textToEmoji[":sandwich:"] = "🥪"; - _emojiToText["🥪"] = ":sandwich:"; - _textToEmoji[":stuffed_flatbread:"] = "🥙"; - _emojiToText["🥙"] = ":stuffed_flatbread:"; - _textToEmoji[":stuffed_pita:"] = "🥙"; - _emojiToText["🥙"] = ":stuffed_pita:"; - _textToEmoji[":falafel:"] = "🧆"; - _emojiToText["🧆"] = ":falafel:"; - _textToEmoji[":taco:"] = "🌮"; - _emojiToText["🌮"] = ":taco:"; - _textToEmoji[":burrito:"] = "🌯"; - _emojiToText["🌯"] = ":burrito:"; - _textToEmoji[":tamale:"] = "🫔"; - _emojiToText["🫔"] = ":tamale:"; - _textToEmoji[":salad:"] = "🥗"; - _emojiToText["🥗"] = ":salad:"; - _textToEmoji[":green_salad:"] = "🥗"; - _emojiToText["🥗"] = ":green_salad:"; - _textToEmoji[":shallow_pan_of_food:"] = "🥘"; - _emojiToText["🥘"] = ":shallow_pan_of_food:"; - _textToEmoji[":paella:"] = "🥘"; - _emojiToText["🥘"] = ":paella:"; - _textToEmoji[":fondue:"] = "🫕"; - _emojiToText["🫕"] = ":fondue:"; - _textToEmoji[":canned_food:"] = "🥫"; - _emojiToText["🥫"] = ":canned_food:"; - _textToEmoji[":jar:"] = "🫙"; - _emojiToText["🫙"] = ":jar:"; - _textToEmoji[":spaghetti:"] = "🍝"; - _emojiToText["🍝"] = ":spaghetti:"; - _textToEmoji[":ramen:"] = "🍜"; - _emojiToText["🍜"] = ":ramen:"; - _textToEmoji[":steaming_bowl:"] = "🍜"; - _emojiToText["🍜"] = ":steaming_bowl:"; - _textToEmoji[":stew:"] = "🍲"; - _emojiToText["🍲"] = ":stew:"; - _textToEmoji[":pot_of_food:"] = "🍲"; - _emojiToText["🍲"] = ":pot_of_food:"; - _textToEmoji[":curry:"] = "🍛"; - _emojiToText["🍛"] = ":curry:"; - _textToEmoji[":curry_rice:"] = "🍛"; - _emojiToText["🍛"] = ":curry_rice:"; - _textToEmoji[":sushi:"] = "🍣"; - _emojiToText["🍣"] = ":sushi:"; - _textToEmoji[":bento:"] = "🍱"; - _emojiToText["🍱"] = ":bento:"; - _textToEmoji[":bento_box:"] = "🍱"; - _emojiToText["🍱"] = ":bento_box:"; - _textToEmoji[":dumpling:"] = "🥟"; - _emojiToText["🥟"] = ":dumpling:"; - _textToEmoji[":oyster:"] = "🦪"; - _emojiToText["🦪"] = ":oyster:"; - _textToEmoji[":fried_shrimp:"] = "🍤"; - _emojiToText["🍤"] = ":fried_shrimp:"; - _textToEmoji[":rice_ball:"] = "🍙"; - _emojiToText["🍙"] = ":rice_ball:"; - _textToEmoji[":rice:"] = "🍚"; - _emojiToText["🍚"] = ":rice:"; - _textToEmoji[":cooked_rice:"] = "🍚"; - _emojiToText["🍚"] = ":cooked_rice:"; - _textToEmoji[":rice_cracker:"] = "🍘"; - _emojiToText["🍘"] = ":rice_cracker:"; - _textToEmoji[":fish_cake:"] = "🍥"; - _emojiToText["🍥"] = ":fish_cake:"; - _textToEmoji[":fortune_cookie:"] = "🥠"; - _emojiToText["🥠"] = ":fortune_cookie:"; - _textToEmoji[":moon_cake:"] = "🥮"; - _emojiToText["🥮"] = ":moon_cake:"; - _textToEmoji[":oden:"] = "🍢"; - _emojiToText["🍢"] = ":oden:"; - _textToEmoji[":dango:"] = "🍡"; - _emojiToText["🍡"] = ":dango:"; - _textToEmoji[":shaved_ice:"] = "🍧"; - _emojiToText["🍧"] = ":shaved_ice:"; - _textToEmoji[":ice_cream:"] = "🍨"; - _emojiToText["🍨"] = ":ice_cream:"; - _textToEmoji[":icecream:"] = "🍦"; - _emojiToText["🍦"] = ":icecream:"; - _textToEmoji[":pie:"] = "🥧"; - _emojiToText["🥧"] = ":pie:"; - _textToEmoji[":cupcake:"] = "🧁"; - _emojiToText["🧁"] = ":cupcake:"; - _textToEmoji[":cake:"] = "🍰"; - _emojiToText["🍰"] = ":cake:"; - _textToEmoji[":shortcake:"] = "🍰"; - _emojiToText["🍰"] = ":shortcake:"; - _textToEmoji[":birthday:"] = "🎂"; - _emojiToText["🎂"] = ":birthday:"; - _textToEmoji[":birthday_cake:"] = "🎂"; - _emojiToText["🎂"] = ":birthday_cake:"; - _textToEmoji[":custard:"] = "🍮"; - _emojiToText["🍮"] = ":custard:"; - _textToEmoji[":pudding:"] = "🍮"; - _emojiToText["🍮"] = ":pudding:"; - _textToEmoji[":flan:"] = "🍮"; - _emojiToText["🍮"] = ":flan:"; - _textToEmoji[":lollipop:"] = "🍭"; - _emojiToText["🍭"] = ":lollipop:"; - _textToEmoji[":candy:"] = "🍬"; - _emojiToText["🍬"] = ":candy:"; - _textToEmoji[":chocolate_bar:"] = "🍫"; - _emojiToText["🍫"] = ":chocolate_bar:"; - _textToEmoji[":popcorn:"] = "🍿"; - _emojiToText["🍿"] = ":popcorn:"; - _textToEmoji[":doughnut:"] = "🍩"; - _emojiToText["🍩"] = ":doughnut:"; - _textToEmoji[":cookie:"] = "🍪"; - _emojiToText["🍪"] = ":cookie:"; - _textToEmoji[":chestnut:"] = "🌰"; - _emojiToText["🌰"] = ":chestnut:"; - _textToEmoji[":peanuts:"] = "🥜"; - _emojiToText["🥜"] = ":peanuts:"; - _textToEmoji[":shelled_peanut:"] = "🥜"; - _emojiToText["🥜"] = ":shelled_peanut:"; - _textToEmoji[":beans:"] = "🫘"; - _emojiToText["🫘"] = ":beans:"; - _textToEmoji[":honey_pot:"] = "🍯"; - _emojiToText["🍯"] = ":honey_pot:"; - _textToEmoji[":milk:"] = "🥛"; - _emojiToText["🥛"] = ":milk:"; - _textToEmoji[":glass_of_milk:"] = "🥛"; - _emojiToText["🥛"] = ":glass_of_milk:"; - _textToEmoji[":pouring_liquid:"] = "🫗"; - _emojiToText["🫗"] = ":pouring_liquid:"; - _textToEmoji[":baby_bottle:"] = "🍼"; - _emojiToText["🍼"] = ":baby_bottle:"; - _textToEmoji[":teapot:"] = "🫖"; - _emojiToText["🫖"] = ":teapot:"; - _textToEmoji[":coffee:"] = "☕"; - _emojiToText["☕"] = ":coffee:"; - _textToEmoji[":hot_beverage:"] = "☕"; - _emojiToText["☕"] = ":hot_beverage:"; - _textToEmoji[":tea:"] = "🍵"; - _emojiToText["🍵"] = ":tea:"; - _textToEmoji[":mate:"] = "🧉"; - _emojiToText["🧉"] = ":mate:"; - _textToEmoji[":beverage_box:"] = "🧃"; - _emojiToText["🧃"] = ":beverage_box:"; - _textToEmoji[":cup_with_straw:"] = "🥤"; - _emojiToText["🥤"] = ":cup_with_straw:"; - _textToEmoji[":bubble_tea:"] = "🧋"; - _emojiToText["🧋"] = ":bubble_tea:"; - _textToEmoji[":sake:"] = "🍶"; - _emojiToText["🍶"] = ":sake:"; - _textToEmoji[":beer:"] = "🍺"; - _emojiToText["🍺"] = ":beer:"; - _textToEmoji[":beer_mug:"] = "🍺"; - _emojiToText["🍺"] = ":beer_mug:"; - _textToEmoji[":beers:"] = "🍻"; - _emojiToText["🍻"] = ":beers:"; - _textToEmoji[":champagne_glass:"] = "🥂"; - _emojiToText["🥂"] = ":champagne_glass:"; - _textToEmoji[":clinking_glass:"] = "🥂"; - _emojiToText["🥂"] = ":clinking_glass:"; - _textToEmoji[":wine_glass:"] = "🍷"; - _emojiToText["🍷"] = ":wine_glass:"; - _textToEmoji[":tumbler_glass:"] = "🥃"; - _emojiToText["🥃"] = ":tumbler_glass:"; - _textToEmoji[":whisky:"] = "🥃"; - _emojiToText["🥃"] = ":whisky:"; - _textToEmoji[":cocktail:"] = "🍸"; - _emojiToText["🍸"] = ":cocktail:"; - _textToEmoji[":tropical_drink:"] = "🍹"; - _emojiToText["🍹"] = ":tropical_drink:"; - _textToEmoji[":champagne:"] = "🍾"; - _emojiToText["🍾"] = ":champagne:"; - _textToEmoji[":bottle_with_popping_cork:"] = "🍾"; - _emojiToText["🍾"] = ":bottle_with_popping_cork:"; - _textToEmoji[":ice_cube:"] = "🧊"; - _emojiToText["🧊"] = ":ice_cube:"; - _textToEmoji[":spoon:"] = "🥄"; - _emojiToText["🥄"] = ":spoon:"; - _textToEmoji[":fork_and_knife:"] = "🍴"; - _emojiToText["🍴"] = ":fork_and_knife:"; - _textToEmoji[":fork_knife_plate:"] = "🍽️"; - _emojiToText["🍽️"] = ":fork_knife_plate:"; - _textToEmoji[":fork_and_knife_with_plate:"] = "🍽️"; - _emojiToText["🍽️"] = ":fork_and_knife_with_plate:"; - _textToEmoji[":bowl_with_spoon:"] = "🥣"; - _emojiToText["🥣"] = ":bowl_with_spoon:"; - _textToEmoji[":takeout_box:"] = "🥡"; - _emojiToText["🥡"] = ":takeout_box:"; - _textToEmoji[":chopsticks:"] = "🥢"; - _emojiToText["🥢"] = ":chopsticks:"; - _textToEmoji[":salt:"] = "🧂"; - _emojiToText["🧂"] = ":salt:"; - _textToEmoji[":dog:"] = "🐶"; - _emojiToText["🐶"] = ":dog:"; - _textToEmoji[":dog_face:"] = "🐶"; - _emojiToText["🐶"] = ":dog_face:"; - _textToEmoji[":cat:"] = "🐱"; - _emojiToText["🐱"] = ":cat:"; - _textToEmoji[":cat_face:"] = "🐱"; - _emojiToText["🐱"] = ":cat_face:"; - _textToEmoji[":mouse:"] = "🐭"; - _emojiToText["🐭"] = ":mouse:"; - _textToEmoji[":mouse_face:"] = "🐭"; - _emojiToText["🐭"] = ":mouse_face:"; - _textToEmoji[":hamster:"] = "🐹"; - _emojiToText["🐹"] = ":hamster:"; - _textToEmoji[":rabbit:"] = "🐰"; - _emojiToText["🐰"] = ":rabbit:"; - _textToEmoji[":rabbit_face:"] = "🐰"; - _emojiToText["🐰"] = ":rabbit_face:"; - _textToEmoji[":fox:"] = "🦊"; - _emojiToText["🦊"] = ":fox:"; - _textToEmoji[":fox_face:"] = "🦊"; - _emojiToText["🦊"] = ":fox_face:"; - _textToEmoji[":bear:"] = "🐻"; - _emojiToText["🐻"] = ":bear:"; - _textToEmoji[":panda_face:"] = "🐼"; - _emojiToText["🐼"] = ":panda_face:"; - _textToEmoji[":panda:"] = "🐼"; - _emojiToText["🐼"] = ":panda:"; - _textToEmoji[":polar_bear:"] = "🐻‍❄️"; - _emojiToText["🐻‍❄️"] = ":polar_bear:"; - _textToEmoji[":koala:"] = "🐨"; - _emojiToText["🐨"] = ":koala:"; - _textToEmoji[":tiger:"] = "🐯"; - _emojiToText["🐯"] = ":tiger:"; - _textToEmoji[":tiger_face:"] = "🐯"; - _emojiToText["🐯"] = ":tiger_face:"; - _textToEmoji[":lion_face:"] = "🦁"; - _emojiToText["🦁"] = ":lion_face:"; - _textToEmoji[":lion:"] = "🦁"; - _emojiToText["🦁"] = ":lion:"; - _textToEmoji[":cow:"] = "🐮"; - _emojiToText["🐮"] = ":cow:"; - _textToEmoji[":cow_face:"] = "🐮"; - _emojiToText["🐮"] = ":cow_face:"; - _textToEmoji[":pig:"] = "🐷"; - _emojiToText["🐷"] = ":pig:"; - _textToEmoji[":pig_face:"] = "🐷"; - _emojiToText["🐷"] = ":pig_face:"; - _textToEmoji[":pig_nose:"] = "🐽"; - _emojiToText["🐽"] = ":pig_nose:"; - _textToEmoji[":frog:"] = "🐸"; - _emojiToText["🐸"] = ":frog:"; - _textToEmoji[":monkey_face:"] = "🐵"; - _emojiToText["🐵"] = ":monkey_face:"; - _textToEmoji[":see_no_evil:"] = "🙈"; - _emojiToText["🙈"] = ":see_no_evil:"; - _textToEmoji[":hear_no_evil:"] = "🙉"; - _emojiToText["🙉"] = ":hear_no_evil:"; - _textToEmoji[":speak_no_evil:"] = "🙊"; - _emojiToText["🙊"] = ":speak_no_evil:"; - _textToEmoji[":monkey:"] = "🐒"; - _emojiToText["🐒"] = ":monkey:"; - _textToEmoji[":chicken:"] = "🐔"; - _emojiToText["🐔"] = ":chicken:"; - _textToEmoji[":penguin:"] = "🐧"; - _emojiToText["🐧"] = ":penguin:"; - _textToEmoji[":bird:"] = "🐦"; - _emojiToText["🐦"] = ":bird:"; - _textToEmoji[":baby_chick:"] = "🐤"; - _emojiToText["🐤"] = ":baby_chick:"; - _textToEmoji[":hatching_chick:"] = "🐣"; - _emojiToText["🐣"] = ":hatching_chick:"; - _textToEmoji[":hatched_chick:"] = "🐥"; - _emojiToText["🐥"] = ":hatched_chick:"; - _textToEmoji[":goose:"] = "🪿"; - _emojiToText["🪿"] = ":goose:"; - _textToEmoji[":duck:"] = "🦆"; - _emojiToText["🦆"] = ":duck:"; - _textToEmoji[":black_bird:"] = "🐦‍⬛"; - _emojiToText["🐦‍⬛"] = ":black_bird:"; - _textToEmoji[":eagle:"] = "🦅"; - _emojiToText["🦅"] = ":eagle:"; - _textToEmoji[":owl:"] = "🦉"; - _emojiToText["🦉"] = ":owl:"; - _textToEmoji[":bat:"] = "🦇"; - _emojiToText["🦇"] = ":bat:"; - _textToEmoji[":wolf:"] = "🐺"; - _emojiToText["🐺"] = ":wolf:"; - _textToEmoji[":boar:"] = "🐗"; - _emojiToText["🐗"] = ":boar:"; - _textToEmoji[":horse:"] = "🐴"; - _emojiToText["🐴"] = ":horse:"; - _textToEmoji[":horse_face:"] = "🐴"; - _emojiToText["🐴"] = ":horse_face:"; - _textToEmoji[":unicorn:"] = "🦄"; - _emojiToText["🦄"] = ":unicorn:"; - _textToEmoji[":unicorn_face:"] = "🦄"; - _emojiToText["🦄"] = ":unicorn_face:"; - _textToEmoji[":moose:"] = "🫎"; - _emojiToText["🫎"] = ":moose:"; - _textToEmoji[":bee:"] = "🐝"; - _emojiToText["🐝"] = ":bee:"; - _textToEmoji[":honeybee:"] = "🐝"; - _emojiToText["🐝"] = ":honeybee:"; - _textToEmoji[":worm:"] = "🪱"; - _emojiToText["🪱"] = ":worm:"; - _textToEmoji[":bug:"] = "🐛"; - _emojiToText["🐛"] = ":bug:"; - _textToEmoji[":butterfly:"] = "🦋"; - _emojiToText["🦋"] = ":butterfly:"; - _textToEmoji[":snail:"] = "🐌"; - _emojiToText["🐌"] = ":snail:"; - _textToEmoji[":lady_beetle:"] = "🐞"; - _emojiToText["🐞"] = ":lady_beetle:"; - _textToEmoji[":ant:"] = "🐜"; - _emojiToText["🐜"] = ":ant:"; - _textToEmoji[":fly:"] = "🪰"; - _emojiToText["🪰"] = ":fly:"; - _textToEmoji[":beetle:"] = "🪲"; - _emojiToText["🪲"] = ":beetle:"; - _textToEmoji[":cockroach:"] = "🪳"; - _emojiToText["🪳"] = ":cockroach:"; - _textToEmoji[":mosquito:"] = "🦟"; - _emojiToText["🦟"] = ":mosquito:"; - _textToEmoji[":cricket:"] = "🦗"; - _emojiToText["🦗"] = ":cricket:"; - _textToEmoji[":spider:"] = "🕷️"; - _emojiToText["🕷️"] = ":spider:"; - _textToEmoji[":spider_web:"] = "🕸️"; - _emojiToText["🕸️"] = ":spider_web:"; - _textToEmoji[":scorpion:"] = "🦂"; - _emojiToText["🦂"] = ":scorpion:"; - _textToEmoji[":turtle:"] = "🐢"; - _emojiToText["🐢"] = ":turtle:"; - _textToEmoji[":snake:"] = "🐍"; - _emojiToText["🐍"] = ":snake:"; - _textToEmoji[":lizard:"] = "🦎"; - _emojiToText["🦎"] = ":lizard:"; - _textToEmoji[":t_rex:"] = "🦖"; - _emojiToText["🦖"] = ":t_rex:"; - _textToEmoji[":sauropod:"] = "🦕"; - _emojiToText["🦕"] = ":sauropod:"; - _textToEmoji[":octopus:"] = "🐙"; - _emojiToText["🐙"] = ":octopus:"; - _textToEmoji[":squid:"] = "🦑"; - _emojiToText["🦑"] = ":squid:"; - _textToEmoji[":jellyfish:"] = "🪼"; - _emojiToText["🪼"] = ":jellyfish:"; - _textToEmoji[":shrimp:"] = "🦐"; - _emojiToText["🦐"] = ":shrimp:"; - _textToEmoji[":lobster:"] = "🦞"; - _emojiToText["🦞"] = ":lobster:"; - _textToEmoji[":crab:"] = "🦀"; - _emojiToText["🦀"] = ":crab:"; - _textToEmoji[":blowfish:"] = "🐡"; - _emojiToText["🐡"] = ":blowfish:"; - _textToEmoji[":tropical_fish:"] = "🐠"; - _emojiToText["🐠"] = ":tropical_fish:"; - _textToEmoji[":fish:"] = "🐟"; - _emojiToText["🐟"] = ":fish:"; - _textToEmoji[":dolphin:"] = "🐬"; - _emojiToText["🐬"] = ":dolphin:"; - _textToEmoji[":whale:"] = "🐳"; - _emojiToText["🐳"] = ":whale:"; - _textToEmoji[":whale2:"] = "🐋"; - _emojiToText["🐋"] = ":whale2:"; - _textToEmoji[":shark:"] = "🦈"; - _emojiToText["🦈"] = ":shark:"; - _textToEmoji[":seal:"] = "🦭"; - _emojiToText["🦭"] = ":seal:"; - _textToEmoji[":crocodile:"] = "🐊"; - _emojiToText["🐊"] = ":crocodile:"; - _textToEmoji[":tiger2:"] = "🐅"; - _emojiToText["🐅"] = ":tiger2:"; - _textToEmoji[":leopard:"] = "🐆"; - _emojiToText["🐆"] = ":leopard:"; - _textToEmoji[":zebra:"] = "🦓"; - _emojiToText["🦓"] = ":zebra:"; - _textToEmoji[":gorilla:"] = "🦍"; - _emojiToText["🦍"] = ":gorilla:"; - _textToEmoji[":orangutan:"] = "🦧"; - _emojiToText["🦧"] = ":orangutan:"; - _textToEmoji[":mammoth:"] = "🦣"; - _emojiToText["🦣"] = ":mammoth:"; - _textToEmoji[":elephant:"] = "🐘"; - _emojiToText["🐘"] = ":elephant:"; - _textToEmoji[":hippopotamus:"] = "🦛"; - _emojiToText["🦛"] = ":hippopotamus:"; - _textToEmoji[":rhino:"] = "🦏"; - _emojiToText["🦏"] = ":rhino:"; - _textToEmoji[":rhinoceros:"] = "🦏"; - _emojiToText["🦏"] = ":rhinoceros:"; - _textToEmoji[":dromedary_camel:"] = "🐪"; - _emojiToText["🐪"] = ":dromedary_camel:"; - _textToEmoji[":camel:"] = "🐫"; - _emojiToText["🐫"] = ":camel:"; - _textToEmoji[":giraffe:"] = "🦒"; - _emojiToText["🦒"] = ":giraffe:"; - _textToEmoji[":kangaroo:"] = "🦘"; - _emojiToText["🦘"] = ":kangaroo:"; - _textToEmoji[":bison:"] = "🦬"; - _emojiToText["🦬"] = ":bison:"; - _textToEmoji[":water_buffalo:"] = "🐃"; - _emojiToText["🐃"] = ":water_buffalo:"; - _textToEmoji[":ox:"] = "🐂"; - _emojiToText["🐂"] = ":ox:"; - _textToEmoji[":cow2:"] = "🐄"; - _emojiToText["🐄"] = ":cow2:"; - _textToEmoji[":donkey:"] = "🫏"; - _emojiToText["🫏"] = ":donkey:"; - _textToEmoji[":racehorse:"] = "🐎"; - _emojiToText["🐎"] = ":racehorse:"; - _textToEmoji[":pig2:"] = "🐖"; - _emojiToText["🐖"] = ":pig2:"; - _textToEmoji[":ram:"] = "🐏"; - _emojiToText["🐏"] = ":ram:"; - _textToEmoji[":sheep:"] = "🐑"; - _emojiToText["🐑"] = ":sheep:"; - _textToEmoji[":ewe:"] = "🐑"; - _emojiToText["🐑"] = ":ewe:"; - _textToEmoji[":llama:"] = "🦙"; - _emojiToText["🦙"] = ":llama:"; - _textToEmoji[":goat:"] = "🐐"; - _emojiToText["🐐"] = ":goat:"; - _textToEmoji[":deer:"] = "🦌"; - _emojiToText["🦌"] = ":deer:"; - _textToEmoji[":dog2:"] = "🐕"; - _emojiToText["🐕"] = ":dog2:"; - _textToEmoji[":poodle:"] = "🐩"; - _emojiToText["🐩"] = ":poodle:"; - _textToEmoji[":guide_dog:"] = "🦮"; - _emojiToText["🦮"] = ":guide_dog:"; - _textToEmoji[":service_dog:"] = "🐕‍🦺"; - _emojiToText["🐕‍🦺"] = ":service_dog:"; - _textToEmoji[":cat2:"] = "🐈"; - _emojiToText["🐈"] = ":cat2:"; - _textToEmoji[":black_cat:"] = "🐈‍⬛"; - _emojiToText["🐈‍⬛"] = ":black_cat:"; - _textToEmoji[":feather:"] = "🪶"; - _emojiToText["🪶"] = ":feather:"; - _textToEmoji[":wing:"] = "🪽"; - _emojiToText["🪽"] = ":wing:"; - _textToEmoji[":rooster:"] = "🐓"; - _emojiToText["🐓"] = ":rooster:"; - _textToEmoji[":turkey:"] = "🦃"; - _emojiToText["🦃"] = ":turkey:"; - _textToEmoji[":dodo:"] = "🦤"; - _emojiToText["🦤"] = ":dodo:"; - _textToEmoji[":peacock:"] = "🦚"; - _emojiToText["🦚"] = ":peacock:"; - _textToEmoji[":parrot:"] = "🦜"; - _emojiToText["🦜"] = ":parrot:"; - _textToEmoji[":swan:"] = "🦢"; - _emojiToText["🦢"] = ":swan:"; - _textToEmoji[":flamingo:"] = "🦩"; - _emojiToText["🦩"] = ":flamingo:"; - _textToEmoji[":dove:"] = "🕊️"; - _emojiToText["🕊️"] = ":dove:"; - _textToEmoji[":dove_of_peace:"] = "🕊️"; - _emojiToText["🕊️"] = ":dove_of_peace:"; - _textToEmoji[":rabbit2:"] = "🐇"; - _emojiToText["🐇"] = ":rabbit2:"; - _textToEmoji[":raccoon:"] = "🦝"; - _emojiToText["🦝"] = ":raccoon:"; - _textToEmoji[":skunk:"] = "🦨"; - _emojiToText["🦨"] = ":skunk:"; - _textToEmoji[":badger:"] = "🦡"; - _emojiToText["🦡"] = ":badger:"; - _textToEmoji[":beaver:"] = "🦫"; - _emojiToText["🦫"] = ":beaver:"; - _textToEmoji[":otter:"] = "🦦"; - _emojiToText["🦦"] = ":otter:"; - _textToEmoji[":sloth:"] = "🦥"; - _emojiToText["🦥"] = ":sloth:"; - _textToEmoji[":mouse2:"] = "🐁"; - _emojiToText["🐁"] = ":mouse2:"; - _textToEmoji[":rat:"] = "🐀"; - _emojiToText["🐀"] = ":rat:"; - _textToEmoji[":chipmunk:"] = "🐿️"; - _emojiToText["🐿️"] = ":chipmunk:"; - _textToEmoji[":hedgehog:"] = "🦔"; - _emojiToText["🦔"] = ":hedgehog:"; - _textToEmoji[":feet:"] = "🐾"; - _emojiToText["🐾"] = ":feet:"; - _textToEmoji[":paw_prints:"] = "🐾"; - _emojiToText["🐾"] = ":paw_prints:"; - _textToEmoji[":dragon:"] = "🐉"; - _emojiToText["🐉"] = ":dragon:"; - _textToEmoji[":dragon_face:"] = "🐲"; - _emojiToText["🐲"] = ":dragon_face:"; - _textToEmoji[":cactus:"] = "🌵"; - _emojiToText["🌵"] = ":cactus:"; - _textToEmoji[":christmas_tree:"] = "🎄"; - _emojiToText["🎄"] = ":christmas_tree:"; - _textToEmoji[":evergreen_tree:"] = "🌲"; - _emojiToText["🌲"] = ":evergreen_tree:"; - _textToEmoji[":deciduous_tree:"] = "🌳"; - _emojiToText["🌳"] = ":deciduous_tree:"; - _textToEmoji[":palm_tree:"] = "🌴"; - _emojiToText["🌴"] = ":palm_tree:"; - _textToEmoji[":wood:"] = "🪵"; - _emojiToText["🪵"] = ":wood:"; - _textToEmoji[":seedling:"] = "🌱"; - _emojiToText["🌱"] = ":seedling:"; - _textToEmoji[":herb:"] = "🌿"; - _emojiToText["🌿"] = ":herb:"; - _textToEmoji[":shamrock:"] = "☘️"; - _emojiToText["☘️"] = ":shamrock:"; - _textToEmoji[":four_leaf_clover:"] = "🍀"; - _emojiToText["🍀"] = ":four_leaf_clover:"; - _textToEmoji[":bamboo:"] = "🎍"; - _emojiToText["🎍"] = ":bamboo:"; - _textToEmoji[":potted_plant:"] = "🪴"; - _emojiToText["🪴"] = ":potted_plant:"; - _textToEmoji[":tanabata_tree:"] = "🎋"; - _emojiToText["🎋"] = ":tanabata_tree:"; - _textToEmoji[":leaves:"] = "🍃"; - _emojiToText["🍃"] = ":leaves:"; - _textToEmoji[":fallen_leaf:"] = "🍂"; - _emojiToText["🍂"] = ":fallen_leaf:"; - _textToEmoji[":maple_leaf:"] = "🍁"; - _emojiToText["🍁"] = ":maple_leaf:"; - _textToEmoji[":nest_with_eggs:"] = "🪺"; - _emojiToText["🪺"] = ":nest_with_eggs:"; - _textToEmoji[":empty_nest:"] = "🪹"; - _emojiToText["🪹"] = ":empty_nest:"; - _textToEmoji[":mushroom:"] = "🍄"; - _emojiToText["🍄"] = ":mushroom:"; - _textToEmoji[":shell:"] = "🐚"; - _emojiToText["🐚"] = ":shell:"; - _textToEmoji[":spiral_shell:"] = "🐚"; - _emojiToText["🐚"] = ":spiral_shell:"; - _textToEmoji[":coral:"] = "🪸"; - _emojiToText["🪸"] = ":coral:"; - _textToEmoji[":rock:"] = "🪨"; - _emojiToText["🪨"] = ":rock:"; - _textToEmoji[":ear_of_rice:"] = "🌾"; - _emojiToText["🌾"] = ":ear_of_rice:"; - _textToEmoji[":sheaf_of_rice:"] = "🌾"; - _emojiToText["🌾"] = ":sheaf_of_rice:"; - _textToEmoji[":bouquet:"] = "💐"; - _emojiToText["💐"] = ":bouquet:"; - _textToEmoji[":tulip:"] = "🌷"; - _emojiToText["🌷"] = ":tulip:"; - _textToEmoji[":rose:"] = "🌹"; - _emojiToText["🌹"] = ":rose:"; - _textToEmoji[":wilted_rose:"] = "🥀"; - _emojiToText["🥀"] = ":wilted_rose:"; - _textToEmoji[":wilted_flower:"] = "🥀"; - _emojiToText["🥀"] = ":wilted_flower:"; - _textToEmoji[":hyacinth:"] = "🪻"; - _emojiToText["🪻"] = ":hyacinth:"; - _textToEmoji[":lotus:"] = "🪷"; - _emojiToText["🪷"] = ":lotus:"; - _textToEmoji[":hibiscus:"] = "🌺"; - _emojiToText["🌺"] = ":hibiscus:"; - _textToEmoji[":cherry_blossom:"] = "🌸"; - _emojiToText["🌸"] = ":cherry_blossom:"; - _textToEmoji[":blossom:"] = "🌼"; - _emojiToText["🌼"] = ":blossom:"; - _textToEmoji[":sunflower:"] = "🌻"; - _emojiToText["🌻"] = ":sunflower:"; - _textToEmoji[":sun_with_face:"] = "🌞"; - _emojiToText["🌞"] = ":sun_with_face:"; - _textToEmoji[":full_moon_with_face:"] = "🌝"; - _emojiToText["🌝"] = ":full_moon_with_face:"; - _textToEmoji[":first_quarter_moon_with_face:"] = "🌛"; - _emojiToText["🌛"] = ":first_quarter_moon_with_face:"; - _textToEmoji[":last_quarter_moon_with_face:"] = "🌜"; - _emojiToText["🌜"] = ":last_quarter_moon_with_face:"; - _textToEmoji[":new_moon_with_face:"] = "🌚"; - _emojiToText["🌚"] = ":new_moon_with_face:"; - _textToEmoji[":new_moon_face:"] = "🌚"; - _emojiToText["🌚"] = ":new_moon_face:"; - _textToEmoji[":full_moon:"] = "🌕"; - _emojiToText["🌕"] = ":full_moon:"; - _textToEmoji[":waning_gibbous_moon:"] = "🌖"; - _emojiToText["🌖"] = ":waning_gibbous_moon:"; - _textToEmoji[":last_quarter_moon:"] = "🌗"; - _emojiToText["🌗"] = ":last_quarter_moon:"; - _textToEmoji[":waning_crescent_moon:"] = "🌘"; - _emojiToText["🌘"] = ":waning_crescent_moon:"; - _textToEmoji[":new_moon:"] = "🌑"; - _emojiToText["🌑"] = ":new_moon:"; - _textToEmoji[":waxing_crescent_moon:"] = "🌒"; - _emojiToText["🌒"] = ":waxing_crescent_moon:"; - _textToEmoji[":first_quarter_moon:"] = "🌓"; - _emojiToText["🌓"] = ":first_quarter_moon:"; - _textToEmoji[":waxing_gibbous_moon:"] = "🌔"; - _emojiToText["🌔"] = ":waxing_gibbous_moon:"; - _textToEmoji[":crescent_moon:"] = "🌙"; - _emojiToText["🌙"] = ":crescent_moon:"; - _textToEmoji[":earth_americas:"] = "🌎"; - _emojiToText["🌎"] = ":earth_americas:"; - _textToEmoji[":earth_africa:"] = "🌍"; - _emojiToText["🌍"] = ":earth_africa:"; - _textToEmoji[":earth_asia:"] = "🌏"; - _emojiToText["🌏"] = ":earth_asia:"; - _textToEmoji[":ringed_planet:"] = "🪐"; - _emojiToText["🪐"] = ":ringed_planet:"; - _textToEmoji[":dizzy:"] = "💫"; - _emojiToText["💫"] = ":dizzy:"; - _textToEmoji[":star:"] = "⭐"; - _emojiToText["⭐"] = ":star:"; - _textToEmoji[":star2:"] = "🌟"; - _emojiToText["🌟"] = ":star2:"; - _textToEmoji[":glowing_star:"] = "🌟"; - _emojiToText["🌟"] = ":glowing_star:"; - _textToEmoji[":sparkles:"] = "✨"; - _emojiToText["✨"] = ":sparkles:"; - _textToEmoji[":zap:"] = "⚡"; - _emojiToText["⚡"] = ":zap:"; - _textToEmoji[":high_voltage:"] = "⚡"; - _emojiToText["⚡"] = ":high_voltage:"; - _textToEmoji[":comet:"] = "☄️"; - _emojiToText["☄️"] = ":comet:"; - _textToEmoji[":boom:"] = "💥"; - _emojiToText["💥"] = ":boom:"; - _textToEmoji[":collision:"] = "💥"; - _emojiToText["💥"] = ":collision:"; - _textToEmoji[":fire:"] = "🔥"; - _emojiToText["🔥"] = ":fire:"; - _textToEmoji[":flame:"] = "🔥"; - _emojiToText["🔥"] = ":flame:"; - _textToEmoji[":cloud_tornado:"] = "🌪️"; - _emojiToText["🌪️"] = ":cloud_tornado:"; - _textToEmoji[":cloud_with_tornado:"] = "🌪️"; - _emojiToText["🌪️"] = ":cloud_with_tornado:"; - _textToEmoji[":tornado:"] = "🌪️"; - _emojiToText["🌪️"] = ":tornado:"; - _textToEmoji[":rainbow:"] = "🌈"; - _emojiToText["🌈"] = ":rainbow:"; - _textToEmoji[":sunny:"] = "☀️"; - _emojiToText["☀️"] = ":sunny:"; - _textToEmoji[":sun:"] = "☀️"; - _emojiToText["☀️"] = ":sun:"; - _textToEmoji[":white_sun_small_cloud:"] = "🌤️"; - _emojiToText["🌤️"] = ":white_sun_small_cloud:"; - _textToEmoji[":white_sun_with_small_cloud:"] = "🌤️"; - _emojiToText["🌤️"] = ":white_sun_with_small_cloud:"; - _textToEmoji[":partly_sunny:"] = "⛅"; - _emojiToText["⛅"] = ":partly_sunny:"; - _textToEmoji[":white_sun_cloud:"] = "🌥️"; - _emojiToText["🌥️"] = ":white_sun_cloud:"; - _textToEmoji[":white_sun_behind_cloud:"] = "🌥️"; - _emojiToText["🌥️"] = ":white_sun_behind_cloud:"; - _textToEmoji[":cloud:"] = "☁️"; - _emojiToText["☁️"] = ":cloud:"; - _textToEmoji[":white_sun_rain_cloud:"] = "🌦️"; - _emojiToText["🌦️"] = ":white_sun_rain_cloud:"; - _textToEmoji[":white_sun_behind_cloud_with_rain:"] = "🌦️"; - _emojiToText["🌦️"] = ":white_sun_behind_cloud_with_rain:"; - _textToEmoji[":cloud_rain:"] = "🌧️"; - _emojiToText["🌧️"] = ":cloud_rain:"; - _textToEmoji[":cloud_with_rain:"] = "🌧️"; - _emojiToText["🌧️"] = ":cloud_with_rain:"; - _textToEmoji[":thunder_cloud_rain:"] = "⛈️"; - _emojiToText["⛈️"] = ":thunder_cloud_rain:"; - _textToEmoji[":thunder_cloud_and_rain:"] = "⛈️"; - _emojiToText["⛈️"] = ":thunder_cloud_and_rain:"; - _textToEmoji[":cloud_lightning:"] = "🌩️"; - _emojiToText["🌩️"] = ":cloud_lightning:"; - _textToEmoji[":cloud_with_lightning:"] = "🌩️"; - _emojiToText["🌩️"] = ":cloud_with_lightning:"; - _textToEmoji[":cloud_snow:"] = "🌨️"; - _emojiToText["🌨️"] = ":cloud_snow:"; - _textToEmoji[":cloud_with_snow:"] = "🌨️"; - _emojiToText["🌨️"] = ":cloud_with_snow:"; - _textToEmoji[":snowflake:"] = "❄️"; - _emojiToText["❄️"] = ":snowflake:"; - _textToEmoji[":snowman2:"] = "☃️"; - _emojiToText["☃️"] = ":snowman2:"; - _textToEmoji[":snowman:"] = "⛄"; - _emojiToText["⛄"] = ":snowman:"; - _textToEmoji[":wind_blowing_face:"] = "🌬️"; - _emojiToText["🌬️"] = ":wind_blowing_face:"; - _textToEmoji[":wind_face:"] = "🌬️"; - _emojiToText["🌬️"] = ":wind_face:"; - _textToEmoji[":dash:"] = "💨"; - _emojiToText["💨"] = ":dash:"; - _textToEmoji[":dashing_away:"] = "💨"; - _emojiToText["💨"] = ":dashing_away:"; - _textToEmoji[":droplet:"] = "💧"; - _emojiToText["💧"] = ":droplet:"; - _textToEmoji[":sweat_drops:"] = "💦"; - _emojiToText["💦"] = ":sweat_drops:"; - _textToEmoji[":bubbles:"] = "🫧"; - _emojiToText["🫧"] = ":bubbles:"; - _textToEmoji[":umbrella:"] = "☔"; - _emojiToText["☔"] = ":umbrella:"; - _textToEmoji[":umbrella2:"] = "☂️"; - _emojiToText["☂️"] = ":umbrella2:"; - _textToEmoji[":ocean:"] = "🌊"; - _emojiToText["🌊"] = ":ocean:"; - _textToEmoji[":water_wave:"] = "🌊"; - _emojiToText["🌊"] = ":water_wave:"; - _textToEmoji[":fog:"] = "🌫️"; - _emojiToText["🌫️"] = ":fog:"; - _textToEmoji[":watch:"] = "⌚"; - _emojiToText["⌚"] = ":watch:"; - _textToEmoji[":mobile_phone:"] = "📱"; - _emojiToText["📱"] = ":mobile_phone:"; - _textToEmoji[":iphone:"] = "📱"; - _emojiToText["📱"] = ":iphone:"; - _textToEmoji[":calling:"] = "📲"; - _emojiToText["📲"] = ":calling:"; - _textToEmoji[":computer:"] = "💻"; - _emojiToText["💻"] = ":computer:"; - _textToEmoji[":keyboard:"] = "⌨️"; - _emojiToText["⌨️"] = ":keyboard:"; - _textToEmoji[":desktop:"] = "🖥️"; - _emojiToText["🖥️"] = ":desktop:"; - _textToEmoji[":desktop_computer:"] = "🖥️"; - _emojiToText["🖥️"] = ":desktop_computer:"; - _textToEmoji[":printer:"] = "🖨️"; - _emojiToText["🖨️"] = ":printer:"; - _textToEmoji[":mouse_three_button:"] = "🖱️"; - _emojiToText["🖱️"] = ":mouse_three_button:"; - _textToEmoji[":three_button_mouse:"] = "🖱️"; - _emojiToText["🖱️"] = ":three_button_mouse:"; - _textToEmoji[":trackball:"] = "🖲️"; - _emojiToText["🖲️"] = ":trackball:"; - _textToEmoji[":joystick:"] = "🕹️"; - _emojiToText["🕹️"] = ":joystick:"; - _textToEmoji[":compression:"] = "🗜️"; - _emojiToText["🗜️"] = ":compression:"; - _textToEmoji[":clamp:"] = "🗜️"; - _emojiToText["🗜️"] = ":clamp:"; - _textToEmoji[":minidisc:"] = "💽"; - _emojiToText["💽"] = ":minidisc:"; - _textToEmoji[":computer_disk:"] = "💽"; - _emojiToText["💽"] = ":computer_disk:"; - _textToEmoji[":floppy_disk:"] = "💾"; - _emojiToText["💾"] = ":floppy_disk:"; - _textToEmoji[":cd:"] = "💿"; - _emojiToText["💿"] = ":cd:"; - _textToEmoji[":optical_disk:"] = "💿"; - _emojiToText["💿"] = ":optical_disk:"; - _textToEmoji[":dvd:"] = "📀"; - _emojiToText["📀"] = ":dvd:"; - _textToEmoji[":vhs:"] = "📼"; - _emojiToText["📼"] = ":vhs:"; - _textToEmoji[":videocassette:"] = "📼"; - _emojiToText["📼"] = ":videocassette:"; - _textToEmoji[":camera:"] = "📷"; - _emojiToText["📷"] = ":camera:"; - _textToEmoji[":camera_with_flash:"] = "📸"; - _emojiToText["📸"] = ":camera_with_flash:"; - _textToEmoji[":video_camera:"] = "📹"; - _emojiToText["📹"] = ":video_camera:"; - _textToEmoji[":movie_camera:"] = "🎥"; - _emojiToText["🎥"] = ":movie_camera:"; - _textToEmoji[":projector:"] = "📽️"; - _emojiToText["📽️"] = ":projector:"; - _textToEmoji[":film_projector:"] = "📽️"; - _emojiToText["📽️"] = ":film_projector:"; - _textToEmoji[":film_frames:"] = "🎞️"; - _emojiToText["🎞️"] = ":film_frames:"; - _textToEmoji[":telephone_receiver:"] = "📞"; - _emojiToText["📞"] = ":telephone_receiver:"; - _textToEmoji[":telephone:"] = "☎️"; - _emojiToText["☎️"] = ":telephone:"; - _textToEmoji[":pager:"] = "📟"; - _emojiToText["📟"] = ":pager:"; - _textToEmoji[":fax:"] = "📠"; - _emojiToText["📠"] = ":fax:"; - _textToEmoji[":fax_machine:"] = "📠"; - _emojiToText["📠"] = ":fax_machine:"; - _textToEmoji[":tv:"] = "📺"; - _emojiToText["📺"] = ":tv:"; - _textToEmoji[":television:"] = "📺"; - _emojiToText["📺"] = ":television:"; - _textToEmoji[":radio:"] = "📻"; - _emojiToText["📻"] = ":radio:"; - _textToEmoji[":microphone2:"] = "🎙️"; - _emojiToText["🎙️"] = ":microphone2:"; - _textToEmoji[":studio_microphone:"] = "🎙️"; - _emojiToText["🎙️"] = ":studio_microphone:"; - _textToEmoji[":level_slider:"] = "🎚️"; - _emojiToText["🎚️"] = ":level_slider:"; - _textToEmoji[":control_knobs:"] = "🎛️"; - _emojiToText["🎛️"] = ":control_knobs:"; - _textToEmoji[":compass:"] = "🧭"; - _emojiToText["🧭"] = ":compass:"; - _textToEmoji[":stopwatch:"] = "⏱️"; - _emojiToText["⏱️"] = ":stopwatch:"; - _textToEmoji[":timer:"] = "⏲️"; - _emojiToText["⏲️"] = ":timer:"; - _textToEmoji[":timer_clock:"] = "⏲️"; - _emojiToText["⏲️"] = ":timer_clock:"; - _textToEmoji[":alarm_clock:"] = "⏰"; - _emojiToText["⏰"] = ":alarm_clock:"; - _textToEmoji[":clock:"] = "🕰️"; - _emojiToText["🕰️"] = ":clock:"; - _textToEmoji[":mantlepiece_clock:"] = "🕰️"; - _emojiToText["🕰️"] = ":mantlepiece_clock:"; - _textToEmoji[":hourglass:"] = "⌛"; - _emojiToText["⌛"] = ":hourglass:"; - _textToEmoji[":hourglass_flowing_sand:"] = "⏳"; - _emojiToText["⏳"] = ":hourglass_flowing_sand:"; - _textToEmoji[":satellite:"] = "📡"; - _emojiToText["📡"] = ":satellite:"; - _textToEmoji[":battery:"] = "🔋"; - _emojiToText["🔋"] = ":battery:"; - _textToEmoji[":low_battery:"] = "🪫"; - _emojiToText["🪫"] = ":low_battery:"; - _textToEmoji[":electric_plug:"] = "🔌"; - _emojiToText["🔌"] = ":electric_plug:"; - _textToEmoji[":bulb:"] = "💡"; - _emojiToText["💡"] = ":bulb:"; - _textToEmoji[":light_bulb:"] = "💡"; - _emojiToText["💡"] = ":light_bulb:"; - _textToEmoji[":flashlight:"] = "🔦"; - _emojiToText["🔦"] = ":flashlight:"; - _textToEmoji[":candle:"] = "🕯️"; - _emojiToText["🕯️"] = ":candle:"; - _textToEmoji[":diya_lamp:"] = "🪔"; - _emojiToText["🪔"] = ":diya_lamp:"; - _textToEmoji[":fire_extinguisher:"] = "🧯"; - _emojiToText["🧯"] = ":fire_extinguisher:"; - _textToEmoji[":oil:"] = "🛢️"; - _emojiToText["🛢️"] = ":oil:"; - _textToEmoji[":oil_drum:"] = "🛢️"; - _emojiToText["🛢️"] = ":oil_drum:"; - _textToEmoji[":money_with_wings:"] = "💸"; - _emojiToText["💸"] = ":money_with_wings:"; - _textToEmoji[":dollar:"] = "💵"; - _emojiToText["💵"] = ":dollar:"; - _textToEmoji[":yen:"] = "💴"; - _emojiToText["💴"] = ":yen:"; - _textToEmoji[":yen_banknote:"] = "💴"; - _emojiToText["💴"] = ":yen_banknote:"; - _textToEmoji[":euro:"] = "💶"; - _emojiToText["💶"] = ":euro:"; - _textToEmoji[":euro_banknote:"] = "💶"; - _emojiToText["💶"] = ":euro_banknote:"; - _textToEmoji[":pound:"] = "💷"; - _emojiToText["💷"] = ":pound:"; - _textToEmoji[":coin:"] = "🪙"; - _emojiToText["🪙"] = ":coin:"; - _textToEmoji[":moneybag:"] = "💰"; - _emojiToText["💰"] = ":moneybag:"; - _textToEmoji[":money_bag:"] = "💰"; - _emojiToText["💰"] = ":money_bag:"; - _textToEmoji[":credit_card:"] = "💳"; - _emojiToText["💳"] = ":credit_card:"; - _textToEmoji[":identification_card:"] = "🪪"; - _emojiToText["🪪"] = ":identification_card:"; - _textToEmoji[":gem:"] = "💎"; - _emojiToText["💎"] = ":gem:"; - _textToEmoji[":gem_stone:"] = "💎"; - _emojiToText["💎"] = ":gem_stone:"; - _textToEmoji[":scales:"] = "⚖️"; - _emojiToText["⚖️"] = ":scales:"; - _textToEmoji[":balance_scale:"] = "⚖️"; - _emojiToText["⚖️"] = ":balance_scale:"; - _textToEmoji[":ladder:"] = "🪜"; - _emojiToText["🪜"] = ":ladder:"; - _textToEmoji[":toolbox:"] = "🧰"; - _emojiToText["🧰"] = ":toolbox:"; - _textToEmoji[":screwdriver:"] = "🪛"; - _emojiToText["🪛"] = ":screwdriver:"; - _textToEmoji[":wrench:"] = "🔧"; - _emojiToText["🔧"] = ":wrench:"; - _textToEmoji[":hammer:"] = "🔨"; - _emojiToText["🔨"] = ":hammer:"; - _textToEmoji[":hammer_pick:"] = "⚒️"; - _emojiToText["⚒️"] = ":hammer_pick:"; - _textToEmoji[":hammer_and_pick:"] = "⚒️"; - _emojiToText["⚒️"] = ":hammer_and_pick:"; - _textToEmoji[":tools:"] = "🛠️"; - _emojiToText["🛠️"] = ":tools:"; - _textToEmoji[":hammer_and_wrench:"] = "🛠️"; - _emojiToText["🛠️"] = ":hammer_and_wrench:"; - _textToEmoji[":pick:"] = "⛏️"; - _emojiToText["⛏️"] = ":pick:"; - _textToEmoji[":carpentry_saw:"] = "🪚"; - _emojiToText["🪚"] = ":carpentry_saw:"; - _textToEmoji[":nut_and_bolt:"] = "🔩"; - _emojiToText["🔩"] = ":nut_and_bolt:"; - _textToEmoji[":gear:"] = "⚙️"; - _emojiToText["⚙️"] = ":gear:"; - _textToEmoji[":mouse_trap:"] = "🪤"; - _emojiToText["🪤"] = ":mouse_trap:"; - _textToEmoji[":bricks:"] = "🧱"; - _emojiToText["🧱"] = ":bricks:"; - _textToEmoji[":brick:"] = "🧱"; - _emojiToText["🧱"] = ":brick:"; - _textToEmoji[":chains:"] = "⛓️"; - _emojiToText["⛓️"] = ":chains:"; - _textToEmoji[":magnet:"] = "🧲"; - _emojiToText["🧲"] = ":magnet:"; - _textToEmoji[":gun:"] = "🔫"; - _emojiToText["🔫"] = ":gun:"; - _textToEmoji[":pistol:"] = "🔫"; - _emojiToText["🔫"] = ":pistol:"; - _textToEmoji[":bomb:"] = "💣"; - _emojiToText["💣"] = ":bomb:"; - _textToEmoji[":firecracker:"] = "🧨"; - _emojiToText["🧨"] = ":firecracker:"; - _textToEmoji[":axe:"] = "🪓"; - _emojiToText["🪓"] = ":axe:"; - _textToEmoji[":knife:"] = "🔪"; - _emojiToText["🔪"] = ":knife:"; - _textToEmoji[":kitchen_knife:"] = "🔪"; - _emojiToText["🔪"] = ":kitchen_knife:"; - _textToEmoji[":dagger:"] = "🗡️"; - _emojiToText["🗡️"] = ":dagger:"; - _textToEmoji[":dagger_knife:"] = "🗡️"; - _emojiToText["🗡️"] = ":dagger_knife:"; - _textToEmoji[":crossed_swords:"] = "⚔️"; - _emojiToText["⚔️"] = ":crossed_swords:"; - _textToEmoji[":shield:"] = "🛡️"; - _emojiToText["🛡️"] = ":shield:"; - _textToEmoji[":smoking:"] = "🚬"; - _emojiToText["🚬"] = ":smoking:"; - _textToEmoji[":cigarette:"] = "🚬"; - _emojiToText["🚬"] = ":cigarette:"; - _textToEmoji[":coffin:"] = "⚰️"; - _emojiToText["⚰️"] = ":coffin:"; - _textToEmoji[":headstone:"] = "🪦"; - _emojiToText["🪦"] = ":headstone:"; - _textToEmoji[":urn:"] = "⚱️"; - _emojiToText["⚱️"] = ":urn:"; - _textToEmoji[":funeral_urn:"] = "⚱️"; - _emojiToText["⚱️"] = ":funeral_urn:"; - _textToEmoji[":amphora:"] = "🏺"; - _emojiToText["🏺"] = ":amphora:"; - _textToEmoji[":crystal_ball:"] = "🔮"; - _emojiToText["🔮"] = ":crystal_ball:"; - _textToEmoji[":prayer_beads:"] = "📿"; - _emojiToText["📿"] = ":prayer_beads:"; - _textToEmoji[":nazar_amulet:"] = "🧿"; - _emojiToText["🧿"] = ":nazar_amulet:"; - _textToEmoji[":hamsa:"] = "🪬"; - _emojiToText["🪬"] = ":hamsa:"; - _textToEmoji[":barber:"] = "💈"; - _emojiToText["💈"] = ":barber:"; - _textToEmoji[":barber_pole:"] = "💈"; - _emojiToText["💈"] = ":barber_pole:"; - _textToEmoji[":alembic:"] = "⚗️"; - _emojiToText["⚗️"] = ":alembic:"; - _textToEmoji[":telescope:"] = "🔭"; - _emojiToText["🔭"] = ":telescope:"; - _textToEmoji[":microscope:"] = "🔬"; - _emojiToText["🔬"] = ":microscope:"; - _textToEmoji[":hole:"] = "🕳️"; - _emojiToText["🕳️"] = ":hole:"; - _textToEmoji[":x_ray:"] = "🩻"; - _emojiToText["🩻"] = ":x_ray:"; - _textToEmoji[":adhesive_bandage:"] = "🩹"; - _emojiToText["🩹"] = ":adhesive_bandage:"; - _textToEmoji[":stethoscope:"] = "🩺"; - _emojiToText["🩺"] = ":stethoscope:"; - _textToEmoji[":pill:"] = "💊"; - _emojiToText["💊"] = ":pill:"; - _textToEmoji[":syringe:"] = "💉"; - _emojiToText["💉"] = ":syringe:"; - _textToEmoji[":drop_of_blood:"] = "🩸"; - _emojiToText["🩸"] = ":drop_of_blood:"; - _textToEmoji[":dna:"] = "🧬"; - _emojiToText["🧬"] = ":dna:"; - _textToEmoji[":microbe:"] = "🦠"; - _emojiToText["🦠"] = ":microbe:"; - _textToEmoji[":petri_dish:"] = "🧫"; - _emojiToText["🧫"] = ":petri_dish:"; - _textToEmoji[":test_tube:"] = "🧪"; - _emojiToText["🧪"] = ":test_tube:"; - _textToEmoji[":thermometer:"] = "🌡️"; - _emojiToText["🌡️"] = ":thermometer:"; - _textToEmoji[":broom:"] = "🧹"; - _emojiToText["🧹"] = ":broom:"; - _textToEmoji[":plunger:"] = "🪠"; - _emojiToText["🪠"] = ":plunger:"; - _textToEmoji[":basket:"] = "🧺"; - _emojiToText["🧺"] = ":basket:"; - _textToEmoji[":roll_of_paper:"] = "🧻"; - _emojiToText["🧻"] = ":roll_of_paper:"; - _textToEmoji[":toilet:"] = "🚽"; - _emojiToText["🚽"] = ":toilet:"; - _textToEmoji[":potable_water:"] = "🚰"; - _emojiToText["🚰"] = ":potable_water:"; - _textToEmoji[":shower:"] = "🚿"; - _emojiToText["🚿"] = ":shower:"; - _textToEmoji[":bathtub:"] = "🛁"; - _emojiToText["🛁"] = ":bathtub:"; - _textToEmoji[":bath:"] = "🛀"; - _emojiToText["🛀"] = ":bath:"; - _textToEmoji[":soap:"] = "🧼"; - _emojiToText["🧼"] = ":soap:"; - _textToEmoji[":toothbrush:"] = "🪥"; - _emojiToText["🪥"] = ":toothbrush:"; - _textToEmoji[":razor:"] = "🪒"; - _emojiToText["🪒"] = ":razor:"; - _textToEmoji[":hair_pick:"] = "🪮"; - _emojiToText["🪮"] = ":hair_pick:"; - _textToEmoji[":sponge:"] = "🧽"; - _emojiToText["🧽"] = ":sponge:"; - _textToEmoji[":bucket:"] = "🪣"; - _emojiToText["🪣"] = ":bucket:"; - _textToEmoji[":squeeze_bottle:"] = "🧴"; - _emojiToText["🧴"] = ":squeeze_bottle:"; - _textToEmoji[":lotion_bottle:"] = "🧴"; - _emojiToText["🧴"] = ":lotion_bottle:"; - _textToEmoji[":bellhop:"] = "🛎️"; - _emojiToText["🛎️"] = ":bellhop:"; - _textToEmoji[":bellhop_bell:"] = "🛎️"; - _emojiToText["🛎️"] = ":bellhop_bell:"; - _textToEmoji[":key:"] = "🔑"; - _emojiToText["🔑"] = ":key:"; - _textToEmoji[":key2:"] = "🗝️"; - _emojiToText["🗝️"] = ":key2:"; - _textToEmoji[":old_key:"] = "🗝️"; - _emojiToText["🗝️"] = ":old_key:"; - _textToEmoji[":door:"] = "🚪"; - _emojiToText["🚪"] = ":door:"; - _textToEmoji[":chair:"] = "🪑"; - _emojiToText["🪑"] = ":chair:"; - _textToEmoji[":couch:"] = "🛋️"; - _emojiToText["🛋️"] = ":couch:"; - _textToEmoji[":couch_and_lamp:"] = "🛋️"; - _emojiToText["🛋️"] = ":couch_and_lamp:"; - _textToEmoji[":bed:"] = "🛏️"; - _emojiToText["🛏️"] = ":bed:"; - _textToEmoji[":sleeping_accommodation:"] = "🛌"; - _emojiToText["🛌"] = ":sleeping_accommodation:"; - _textToEmoji[":person_in_bed:"] = "🛌"; - _emojiToText["🛌"] = ":person_in_bed:"; - _textToEmoji[":teddy_bear:"] = "🧸"; - _emojiToText["🧸"] = ":teddy_bear:"; - _textToEmoji[":nesting_dolls:"] = "🪆"; - _emojiToText["🪆"] = ":nesting_dolls:"; - _textToEmoji[":frame_photo:"] = "🖼️"; - _emojiToText["🖼️"] = ":frame_photo:"; - _textToEmoji[":frame_with_picture:"] = "🖼️"; - _emojiToText["🖼️"] = ":frame_with_picture:"; - _textToEmoji[":mirror:"] = "🪞"; - _emojiToText["🪞"] = ":mirror:"; - _textToEmoji[":window:"] = "🪟"; - _emojiToText["🪟"] = ":window:"; - _textToEmoji[":shopping_bags:"] = "🛍️"; - _emojiToText["🛍️"] = ":shopping_bags:"; - _textToEmoji[":shopping_cart:"] = "🛒"; - _emojiToText["🛒"] = ":shopping_cart:"; - _textToEmoji[":shopping_trolley:"] = "🛒"; - _emojiToText["🛒"] = ":shopping_trolley:"; - _textToEmoji[":gift:"] = "🎁"; - _emojiToText["🎁"] = ":gift:"; - _textToEmoji[":wrapped_gift:"] = "🎁"; - _emojiToText["🎁"] = ":wrapped_gift:"; - _textToEmoji[":balloon:"] = "🎈"; - _emojiToText["🎈"] = ":balloon:"; - _textToEmoji[":flags:"] = "🎏"; - _emojiToText["🎏"] = ":flags:"; - _textToEmoji[":carp_streamer:"] = "🎏"; - _emojiToText["🎏"] = ":carp_streamer:"; - _textToEmoji[":ribbon:"] = "🎀"; - _emojiToText["🎀"] = ":ribbon:"; - _textToEmoji[":magic_wand:"] = "🪄"; - _emojiToText["🪄"] = ":magic_wand:"; - _textToEmoji[":piñata:"] = "🪅"; - _emojiToText["🪅"] = ":piñata:"; - _textToEmoji[":confetti_ball:"] = "🎊"; - _emojiToText["🎊"] = ":confetti_ball:"; - _textToEmoji[":tada:"] = "🎉"; - _emojiToText["🎉"] = ":tada:"; - _textToEmoji[":party_popper:"] = "🎉"; - _emojiToText["🎉"] = ":party_popper:"; - _textToEmoji[":dolls:"] = "🎎"; - _emojiToText["🎎"] = ":dolls:"; - _textToEmoji[":folding_hand_fan:"] = "🪭"; - _emojiToText["🪭"] = ":folding_hand_fan:"; - _textToEmoji[":izakaya_lantern:"] = "🏮"; - _emojiToText["🏮"] = ":izakaya_lantern:"; - _textToEmoji[":wind_chime:"] = "🎐"; - _emojiToText["🎐"] = ":wind_chime:"; - _textToEmoji[":mirror_ball:"] = "🪩"; - _emojiToText["🪩"] = ":mirror_ball:"; - _textToEmoji[":red_envelope:"] = "🧧"; - _emojiToText["🧧"] = ":red_envelope:"; - _textToEmoji[":envelope:"] = "✉️"; - _emojiToText["✉️"] = ":envelope:"; - _textToEmoji[":envelope_with_arrow:"] = "📩"; - _emojiToText["📩"] = ":envelope_with_arrow:"; - _textToEmoji[":incoming_envelope:"] = "📨"; - _emojiToText["📨"] = ":incoming_envelope:"; - _textToEmoji[":e_mail:"] = "📧"; - _emojiToText["📧"] = ":e_mail:"; - _textToEmoji[":email:"] = "📧"; - _emojiToText["📧"] = ":email:"; - _textToEmoji[":love_letter:"] = "💌"; - _emojiToText["💌"] = ":love_letter:"; - _textToEmoji[":inbox_tray:"] = "📥"; - _emojiToText["📥"] = ":inbox_tray:"; - _textToEmoji[":outbox_tray:"] = "📤"; - _emojiToText["📤"] = ":outbox_tray:"; - _textToEmoji[":package:"] = "📦"; - _emojiToText["📦"] = ":package:"; - _textToEmoji[":label:"] = "🏷️"; - _emojiToText["🏷️"] = ":label:"; - _textToEmoji[":placard:"] = "🪧"; - _emojiToText["🪧"] = ":placard:"; - _textToEmoji[":mailbox_closed:"] = "📪"; - _emojiToText["📪"] = ":mailbox_closed:"; - _textToEmoji[":mailbox:"] = "📫"; - _emojiToText["📫"] = ":mailbox:"; - _textToEmoji[":mailbox_with_mail:"] = "📬"; - _emojiToText["📬"] = ":mailbox_with_mail:"; - _textToEmoji[":mailbox_with_no_mail:"] = "📭"; - _emojiToText["📭"] = ":mailbox_with_no_mail:"; - _textToEmoji[":postbox:"] = "📮"; - _emojiToText["📮"] = ":postbox:"; - _textToEmoji[":postal_horn:"] = "📯"; - _emojiToText["📯"] = ":postal_horn:"; - _textToEmoji[":scroll:"] = "📜"; - _emojiToText["📜"] = ":scroll:"; - _textToEmoji[":page_with_curl:"] = "📃"; - _emojiToText["📃"] = ":page_with_curl:"; - _textToEmoji[":page_facing_up:"] = "📄"; - _emojiToText["📄"] = ":page_facing_up:"; - _textToEmoji[":bookmark_tabs:"] = "📑"; - _emojiToText["📑"] = ":bookmark_tabs:"; - _textToEmoji[":receipt:"] = "🧾"; - _emojiToText["🧾"] = ":receipt:"; - _textToEmoji[":bar_chart:"] = "📊"; - _emojiToText["📊"] = ":bar_chart:"; - _textToEmoji[":chart_with_upwards_trend:"] = "📈"; - _emojiToText["📈"] = ":chart_with_upwards_trend:"; - _textToEmoji[":chart_with_downwards_trend:"] = "📉"; - _emojiToText["📉"] = ":chart_with_downwards_trend:"; - _textToEmoji[":notepad_spiral:"] = "🗒️"; - _emojiToText["🗒️"] = ":notepad_spiral:"; - _textToEmoji[":spiral_note_pad:"] = "🗒️"; - _emojiToText["🗒️"] = ":spiral_note_pad:"; - _textToEmoji[":calendar_spiral:"] = "🗓️"; - _emojiToText["🗓️"] = ":calendar_spiral:"; - _textToEmoji[":spiral_calendar_pad:"] = "🗓️"; - _emojiToText["🗓️"] = ":spiral_calendar_pad:"; - _textToEmoji[":calendar:"] = "📆"; - _emojiToText["📆"] = ":calendar:"; - _textToEmoji[":date:"] = "📅"; - _emojiToText["📅"] = ":date:"; - _textToEmoji[":wastebasket:"] = "🗑️"; - _emojiToText["🗑️"] = ":wastebasket:"; - _textToEmoji[":card_index:"] = "📇"; - _emojiToText["📇"] = ":card_index:"; - _textToEmoji[":card_box:"] = "🗃️"; - _emojiToText["🗃️"] = ":card_box:"; - _textToEmoji[":card_file_box:"] = "🗃️"; - _emojiToText["🗃️"] = ":card_file_box:"; - _textToEmoji[":ballot_box:"] = "🗳️"; - _emojiToText["🗳️"] = ":ballot_box:"; - _textToEmoji[":ballot_box_with_ballot:"] = "🗳️"; - _emojiToText["🗳️"] = ":ballot_box_with_ballot:"; - _textToEmoji[":file_cabinet:"] = "🗄️"; - _emojiToText["🗄️"] = ":file_cabinet:"; - _textToEmoji[":clipboard:"] = "📋"; - _emojiToText["📋"] = ":clipboard:"; - _textToEmoji[":file_folder:"] = "📁"; - _emojiToText["📁"] = ":file_folder:"; - _textToEmoji[":open_file_folder:"] = "📂"; - _emojiToText["📂"] = ":open_file_folder:"; - _textToEmoji[":dividers:"] = "🗂️"; - _emojiToText["🗂️"] = ":dividers:"; - _textToEmoji[":card_index_dividers:"] = "🗂️"; - _emojiToText["🗂️"] = ":card_index_dividers:"; - _textToEmoji[":newspaper2:"] = "🗞️"; - _emojiToText["🗞️"] = ":newspaper2:"; - _textToEmoji[":rolled_up_newspaper:"] = "🗞️"; - _emojiToText["🗞️"] = ":rolled_up_newspaper:"; - _textToEmoji[":newspaper:"] = "📰"; - _emojiToText["📰"] = ":newspaper:"; - _textToEmoji[":notebook:"] = "📓"; - _emojiToText["📓"] = ":notebook:"; - _textToEmoji[":notebook_with_decorative_cover:"] = "📔"; - _emojiToText["📔"] = ":notebook_with_decorative_cover:"; - _textToEmoji[":ledger:"] = "📒"; - _emojiToText["📒"] = ":ledger:"; - _textToEmoji[":closed_book:"] = "📕"; - _emojiToText["📕"] = ":closed_book:"; - _textToEmoji[":green_book:"] = "📗"; - _emojiToText["📗"] = ":green_book:"; - _textToEmoji[":blue_book:"] = "📘"; - _emojiToText["📘"] = ":blue_book:"; - _textToEmoji[":orange_book:"] = "📙"; - _emojiToText["📙"] = ":orange_book:"; - _textToEmoji[":books:"] = "📚"; - _emojiToText["📚"] = ":books:"; - _textToEmoji[":book:"] = "📖"; - _emojiToText["📖"] = ":book:"; - _textToEmoji[":open_book:"] = "📖"; - _emojiToText["📖"] = ":open_book:"; - _textToEmoji[":bookmark:"] = "🔖"; - _emojiToText["🔖"] = ":bookmark:"; - _textToEmoji[":safety_pin:"] = "🧷"; - _emojiToText["🧷"] = ":safety_pin:"; - _textToEmoji[":link:"] = "🔗"; - _emojiToText["🔗"] = ":link:"; - _textToEmoji[":paperclip:"] = "📎"; - _emojiToText["📎"] = ":paperclip:"; - _textToEmoji[":paperclips:"] = "🖇️"; - _emojiToText["🖇️"] = ":paperclips:"; - _textToEmoji[":linked_paperclips:"] = "🖇️"; - _emojiToText["🖇️"] = ":linked_paperclips:"; - _textToEmoji[":triangular_ruler:"] = "📐"; - _emojiToText["📐"] = ":triangular_ruler:"; - _textToEmoji[":straight_ruler:"] = "📏"; - _emojiToText["📏"] = ":straight_ruler:"; - _textToEmoji[":abacus:"] = "🧮"; - _emojiToText["🧮"] = ":abacus:"; - _textToEmoji[":pushpin:"] = "📌"; - _emojiToText["📌"] = ":pushpin:"; - _textToEmoji[":round_pushpin:"] = "📍"; - _emojiToText["📍"] = ":round_pushpin:"; - _textToEmoji[":scissors:"] = "✂️"; - _emojiToText["✂️"] = ":scissors:"; - _textToEmoji[":pen_ballpoint:"] = "🖊️"; - _emojiToText["🖊️"] = ":pen_ballpoint:"; - _textToEmoji[":lower_left_ballpoint_pen:"] = "🖊️"; - _emojiToText["🖊️"] = ":lower_left_ballpoint_pen:"; - _textToEmoji[":pen:"] = "🖊️"; - _emojiToText["🖊️"] = ":pen:"; - _textToEmoji[":pen_fountain:"] = "🖋️"; - _emojiToText["🖋️"] = ":pen_fountain:"; - _textToEmoji[":lower_left_fountain_pen:"] = "🖋️"; - _emojiToText["🖋️"] = ":lower_left_fountain_pen:"; - _textToEmoji[":fountain_pen:"] = "🖋️"; - _emojiToText["🖋️"] = ":fountain_pen:"; - _textToEmoji[":black_nib:"] = "✒️"; - _emojiToText["✒️"] = ":black_nib:"; - _textToEmoji[":paintbrush:"] = "🖌️"; - _emojiToText["🖌️"] = ":paintbrush:"; - _textToEmoji[":lower_left_paintbrush:"] = "🖌️"; - _emojiToText["🖌️"] = ":lower_left_paintbrush:"; - _textToEmoji[":crayon:"] = "🖍️"; - _emojiToText["🖍️"] = ":crayon:"; - _textToEmoji[":lower_left_crayon:"] = "🖍️"; - _emojiToText["🖍️"] = ":lower_left_crayon:"; - _textToEmoji[":pencil:"] = "📝"; - _emojiToText["📝"] = ":pencil:"; - _textToEmoji[":memo:"] = "📝"; - _emojiToText["📝"] = ":memo:"; - _textToEmoji[":pencil2:"] = "✏️"; - _emojiToText["✏️"] = ":pencil2:"; - _textToEmoji[":mag:"] = "🔍"; - _emojiToText["🔍"] = ":mag:"; - _textToEmoji[":mag_right:"] = "🔎"; - _emojiToText["🔎"] = ":mag_right:"; - _textToEmoji[":lock_with_ink_pen:"] = "🔏"; - _emojiToText["🔏"] = ":lock_with_ink_pen:"; - _textToEmoji[":closed_lock_with_key:"] = "🔐"; - _emojiToText["🔐"] = ":closed_lock_with_key:"; - _textToEmoji[":lock:"] = "🔒"; - _emojiToText["🔒"] = ":lock:"; - _textToEmoji[":locked:"] = "🔒"; - _emojiToText["🔒"] = ":locked:"; - _textToEmoji[":unlock:"] = "🔓"; - _emojiToText["🔓"] = ":unlock:"; - _textToEmoji[":unlocked:"] = "🔓"; - _emojiToText["🔓"] = ":unlocked:"; - _textToEmoji[":grinning:"] = "😀"; - _emojiToText["😀"] = ":grinning:"; - _textToEmoji[":grinning_face:"] = "😀"; - _emojiToText["😀"] = ":grinning_face:"; - _textToEmoji[":smiley:"] = "😃"; - _emojiToText["😃"] = ":smiley:"; - _textToEmoji[":smile:"] = "😄"; - _emojiToText["😄"] = ":smile:"; - _textToEmoji[":grin:"] = "😁"; - _emojiToText["😁"] = ":grin:"; - _textToEmoji[":laughing:"] = "😆"; - _emojiToText["😆"] = ":laughing:"; - _textToEmoji[":satisfied:"] = "😆"; - _emojiToText["😆"] = ":satisfied:"; - _textToEmoji[":face_holding_back_tears:"] = "🥹"; - _emojiToText["🥹"] = ":face_holding_back_tears:"; - _textToEmoji[":sweat_smile:"] = "😅"; - _emojiToText["😅"] = ":sweat_smile:"; - _textToEmoji[":joy:"] = "😂"; - _emojiToText["😂"] = ":joy:"; - _textToEmoji[":rofl:"] = "🤣"; - _emojiToText["🤣"] = ":rofl:"; - _textToEmoji[":rolling_on_the_floor_laughing:"] = "🤣"; - _emojiToText["🤣"] = ":rolling_on_the_floor_laughing:"; - _textToEmoji[":smiling_face_with_tear:"] = "🥲"; - _emojiToText["🥲"] = ":smiling_face_with_tear:"; - _textToEmoji[":relaxed:"] = "☺️"; - _emojiToText["☺️"] = ":relaxed:"; - _textToEmoji[":smiling_face:"] = "☺️"; - _emojiToText["☺️"] = ":smiling_face:"; - _textToEmoji[":blush:"] = "😊"; - _emojiToText["😊"] = ":blush:"; - _textToEmoji[":innocent:"] = "😇"; - _emojiToText["😇"] = ":innocent:"; - _textToEmoji[":slight_smile:"] = "🙂"; - _emojiToText["🙂"] = ":slight_smile:"; - _textToEmoji[":slightly_smiling_face:"] = "🙂"; - _emojiToText["🙂"] = ":slightly_smiling_face:"; - _textToEmoji[":upside_down:"] = "🙃"; - _emojiToText["🙃"] = ":upside_down:"; - _textToEmoji[":upside_down_face:"] = "🙃"; - _emojiToText["🙃"] = ":upside_down_face:"; - _textToEmoji[":wink:"] = "😉"; - _emojiToText["😉"] = ":wink:"; - _textToEmoji[":winking_face:"] = "😉"; - _emojiToText["😉"] = ":winking_face:"; - _textToEmoji[":relieved:"] = "😌"; - _emojiToText["😌"] = ":relieved:"; - _textToEmoji[":relieved_face:"] = "😌"; - _emojiToText["😌"] = ":relieved_face:"; - _textToEmoji[":heart_eyes:"] = "😍"; - _emojiToText["😍"] = ":heart_eyes:"; - _textToEmoji[":smiling_face_with_3_hearts:"] = "🥰"; - _emojiToText["🥰"] = ":smiling_face_with_3_hearts:"; - _textToEmoji[":kissing_heart:"] = "😘"; - _emojiToText["😘"] = ":kissing_heart:"; - _textToEmoji[":kissing:"] = "😗"; - _emojiToText["😗"] = ":kissing:"; - _textToEmoji[":kissing_face:"] = "😗"; - _emojiToText["😗"] = ":kissing_face:"; - _textToEmoji[":kissing_smiling_eyes:"] = "😙"; - _emojiToText["😙"] = ":kissing_smiling_eyes:"; - _textToEmoji[":kissing_closed_eyes:"] = "😚"; - _emojiToText["😚"] = ":kissing_closed_eyes:"; - _textToEmoji[":yum:"] = "😋"; - _emojiToText["😋"] = ":yum:"; - _textToEmoji[":stuck_out_tongue:"] = "😛"; - _emojiToText["😛"] = ":stuck_out_tongue:"; - _textToEmoji[":stuck_out_tongue_closed_eyes:"] = "😝"; - _emojiToText["😝"] = ":stuck_out_tongue_closed_eyes:"; - _textToEmoji[":stuck_out_tongue_winking_eye:"] = "😜"; - _emojiToText["😜"] = ":stuck_out_tongue_winking_eye:"; - _textToEmoji[":zany_face:"] = "🤪"; - _emojiToText["🤪"] = ":zany_face:"; - _textToEmoji[":face_with_raised_eyebrow:"] = "🤨"; - _emojiToText["🤨"] = ":face_with_raised_eyebrow:"; - _textToEmoji[":face_with_monocle:"] = "🧐"; - _emojiToText["🧐"] = ":face_with_monocle:"; - _textToEmoji[":nerd:"] = "🤓"; - _emojiToText["🤓"] = ":nerd:"; - _textToEmoji[":nerd_face:"] = "🤓"; - _emojiToText["🤓"] = ":nerd_face:"; - _textToEmoji[":sunglasses:"] = "😎"; - _emojiToText["😎"] = ":sunglasses:"; - _textToEmoji[":disguised_face:"] = "🥸"; - _emojiToText["🥸"] = ":disguised_face:"; - _textToEmoji[":star_struck:"] = "🤩"; - _emojiToText["🤩"] = ":star_struck:"; - _textToEmoji[":partying_face:"] = "🥳"; - _emojiToText["🥳"] = ":partying_face:"; - _textToEmoji[":smirk:"] = "😏"; - _emojiToText["😏"] = ":smirk:"; - _textToEmoji[":smirking_face:"] = "😏"; - _emojiToText["😏"] = ":smirking_face:"; - _textToEmoji[":unamused:"] = "😒"; - _emojiToText["😒"] = ":unamused:"; - _textToEmoji[":unamused_face:"] = "😒"; - _emojiToText["😒"] = ":unamused_face:"; - _textToEmoji[":disappointed:"] = "😞"; - _emojiToText["😞"] = ":disappointed:"; - _textToEmoji[":pensive:"] = "😔"; - _emojiToText["😔"] = ":pensive:"; - _textToEmoji[":pensive_face:"] = "😔"; - _emojiToText["😔"] = ":pensive_face:"; - _textToEmoji[":worried:"] = "😟"; - _emojiToText["😟"] = ":worried:"; - _textToEmoji[":worried_face:"] = "😟"; - _emojiToText["😟"] = ":worried_face:"; - _textToEmoji[":confused:"] = "😕"; - _emojiToText["😕"] = ":confused:"; - _textToEmoji[":confused_face:"] = "😕"; - _emojiToText["😕"] = ":confused_face:"; - _textToEmoji[":slight_frown:"] = "🙁"; - _emojiToText["🙁"] = ":slight_frown:"; - _textToEmoji[":slightly_frowning_face:"] = "🙁"; - _emojiToText["🙁"] = ":slightly_frowning_face:"; - _textToEmoji[":frowning2:"] = "☹️"; - _emojiToText["☹️"] = ":frowning2:"; - _textToEmoji[":white_frowning_face:"] = "☹️"; - _emojiToText["☹️"] = ":white_frowning_face:"; - _textToEmoji[":frowning_face:"] = "☹️"; - _emojiToText["☹️"] = ":frowning_face:"; - _textToEmoji[":persevere:"] = "😣"; - _emojiToText["😣"] = ":persevere:"; - _textToEmoji[":confounded:"] = "😖"; - _emojiToText["😖"] = ":confounded:"; - _textToEmoji[":tired_face:"] = "😫"; - _emojiToText["😫"] = ":tired_face:"; - _textToEmoji[":weary:"] = "😩"; - _emojiToText["😩"] = ":weary:"; - _textToEmoji[":weary_face:"] = "😩"; - _emojiToText["😩"] = ":weary_face:"; - _textToEmoji[":pleading_face:"] = "🥺"; - _emojiToText["🥺"] = ":pleading_face:"; - _textToEmoji[":cry:"] = "😢"; - _emojiToText["😢"] = ":cry:"; - _textToEmoji[":crying_face:"] = "😢"; - _emojiToText["😢"] = ":crying_face:"; - _textToEmoji[":sob:"] = "😭"; - _emojiToText["😭"] = ":sob:"; - _textToEmoji[":triumph:"] = "😤"; - _emojiToText["😤"] = ":triumph:"; - _textToEmoji[":angry:"] = "😠"; - _emojiToText["😠"] = ":angry:"; - _textToEmoji[":angry_face:"] = "😠"; - _emojiToText["😠"] = ":angry_face:"; - _textToEmoji[":rage:"] = "😡"; - _emojiToText["😡"] = ":rage:"; - _textToEmoji[":pouting_face:"] = "😡"; - _emojiToText["😡"] = ":pouting_face:"; - _textToEmoji[":face_with_symbols_over_mouth:"] = "🤬"; - _emojiToText["🤬"] = ":face_with_symbols_over_mouth:"; - _textToEmoji[":exploding_head:"] = "🤯"; - _emojiToText["🤯"] = ":exploding_head:"; - _textToEmoji[":flushed:"] = "😳"; - _emojiToText["😳"] = ":flushed:"; - _textToEmoji[":flushed_face:"] = "😳"; - _emojiToText["😳"] = ":flushed_face:"; - _textToEmoji[":hot_face:"] = "🥵"; - _emojiToText["🥵"] = ":hot_face:"; - _textToEmoji[":cold_face:"] = "🥶"; - _emojiToText["🥶"] = ":cold_face:"; - _textToEmoji[":face_in_clouds:"] = "😶‍🌫️"; - _emojiToText["😶‍🌫️"] = ":face_in_clouds:"; - _textToEmoji[":scream:"] = "😱"; - _emojiToText["😱"] = ":scream:"; - _textToEmoji[":fearful:"] = "😨"; - _emojiToText["😨"] = ":fearful:"; - _textToEmoji[":fearful_face:"] = "😨"; - _emojiToText["😨"] = ":fearful_face:"; - _textToEmoji[":cold_sweat:"] = "😰"; - _emojiToText["😰"] = ":cold_sweat:"; - _textToEmoji[":disappointed_relieved:"] = "😥"; - _emojiToText["😥"] = ":disappointed_relieved:"; - _textToEmoji[":sweat:"] = "😓"; - _emojiToText["😓"] = ":sweat:"; - _textToEmoji[":hugging:"] = "🤗"; - _emojiToText["🤗"] = ":hugging:"; - _textToEmoji[":hugging_face:"] = "🤗"; - _emojiToText["🤗"] = ":hugging_face:"; - _textToEmoji[":thinking:"] = "🤔"; - _emojiToText["🤔"] = ":thinking:"; - _textToEmoji[":thinking_face:"] = "🤔"; - _emojiToText["🤔"] = ":thinking_face:"; - _textToEmoji[":face_with_peeking_eye:"] = "🫣"; - _emojiToText["🫣"] = ":face_with_peeking_eye:"; - _textToEmoji[":face_with_hand_over_mouth:"] = "🤭"; - _emojiToText["🤭"] = ":face_with_hand_over_mouth:"; - _textToEmoji[":face_with_open_eyes_and_hand_over_mouth:"] = "🫢"; - _emojiToText["🫢"] = ":face_with_open_eyes_and_hand_over_mouth:"; - _textToEmoji[":saluting_face:"] = "🫡"; - _emojiToText["🫡"] = ":saluting_face:"; - _textToEmoji[":shushing_face:"] = "🤫"; - _emojiToText["🤫"] = ":shushing_face:"; - _textToEmoji[":melting_face:"] = "🫠"; - _emojiToText["🫠"] = ":melting_face:"; - _textToEmoji[":lying_face:"] = "🤥"; - _emojiToText["🤥"] = ":lying_face:"; - _textToEmoji[":liar:"] = "🤥"; - _emojiToText["🤥"] = ":liar:"; - _textToEmoji[":no_mouth:"] = "😶"; - _emojiToText["😶"] = ":no_mouth:"; - _textToEmoji[":dotted_line_face:"] = "🫥"; - _emojiToText["🫥"] = ":dotted_line_face:"; - _textToEmoji[":neutral_face:"] = "😐"; - _emojiToText["😐"] = ":neutral_face:"; - _textToEmoji[":face_with_diagonal_mouth:"] = "🫤"; - _emojiToText["🫤"] = ":face_with_diagonal_mouth:"; - _textToEmoji[":expressionless:"] = "😑"; - _emojiToText["😑"] = ":expressionless:"; - _textToEmoji[":shaking_face:"] = "🫨"; - _emojiToText["🫨"] = ":shaking_face:"; - _textToEmoji[":grimacing:"] = "😬"; - _emojiToText["😬"] = ":grimacing:"; - _textToEmoji[":rolling_eyes:"] = "🙄"; - _emojiToText["🙄"] = ":rolling_eyes:"; - _textToEmoji[":face_with_rolling_eyes:"] = "🙄"; - _emojiToText["🙄"] = ":face_with_rolling_eyes:"; - _textToEmoji[":hushed:"] = "😯"; - _emojiToText["😯"] = ":hushed:"; - _textToEmoji[":hushed_face:"] = "😯"; - _emojiToText["😯"] = ":hushed_face:"; - _textToEmoji[":frowning:"] = "😦"; - _emojiToText["😦"] = ":frowning:"; - _textToEmoji[":anguished:"] = "😧"; - _emojiToText["😧"] = ":anguished:"; - _textToEmoji[":open_mouth:"] = "😮"; - _emojiToText["😮"] = ":open_mouth:"; - _textToEmoji[":astonished:"] = "😲"; - _emojiToText["😲"] = ":astonished:"; - _textToEmoji[":yawning_face:"] = "🥱"; - _emojiToText["🥱"] = ":yawning_face:"; - _textToEmoji[":sleeping:"] = "😴"; - _emojiToText["😴"] = ":sleeping:"; - _textToEmoji[":sleeping_face:"] = "😴"; - _emojiToText["😴"] = ":sleeping_face:"; - _textToEmoji[":drooling_face:"] = "🤤"; - _emojiToText["🤤"] = ":drooling_face:"; - _textToEmoji[":drool:"] = "🤤"; - _emojiToText["🤤"] = ":drool:"; - _textToEmoji[":sleepy:"] = "😪"; - _emojiToText["😪"] = ":sleepy:"; - _textToEmoji[":sleepy_face:"] = "😪"; - _emojiToText["😪"] = ":sleepy_face:"; - _textToEmoji[":face_exhaling:"] = "😮‍💨"; - _emojiToText["😮‍💨"] = ":face_exhaling:"; - _textToEmoji[":dizzy_face:"] = "😵"; - _emojiToText["😵"] = ":dizzy_face:"; - _textToEmoji[":face_with_spiral_eyes:"] = "😵‍💫"; - _emojiToText["😵‍💫"] = ":face_with_spiral_eyes:"; - _textToEmoji[":zipper_mouth:"] = "🤐"; - _emojiToText["🤐"] = ":zipper_mouth:"; - _textToEmoji[":zipper_mouth_face:"] = "🤐"; - _emojiToText["🤐"] = ":zipper_mouth_face:"; - _textToEmoji[":woozy_face:"] = "🥴"; - _emojiToText["🥴"] = ":woozy_face:"; - _textToEmoji[":nauseated_face:"] = "🤢"; - _emojiToText["🤢"] = ":nauseated_face:"; - _textToEmoji[":sick:"] = "🤢"; - _emojiToText["🤢"] = ":sick:"; - _textToEmoji[":face_vomiting:"] = "🤮"; - _emojiToText["🤮"] = ":face_vomiting:"; - _textToEmoji[":sneezing_face:"] = "🤧"; - _emojiToText["🤧"] = ":sneezing_face:"; - _textToEmoji[":sneeze:"] = "🤧"; - _emojiToText["🤧"] = ":sneeze:"; - _textToEmoji[":mask:"] = "😷"; - _emojiToText["😷"] = ":mask:"; - _textToEmoji[":thermometer_face:"] = "🤒"; - _emojiToText["🤒"] = ":thermometer_face:"; - _textToEmoji[":face_with_thermometer:"] = "🤒"; - _emojiToText["🤒"] = ":face_with_thermometer:"; - _textToEmoji[":head_bandage:"] = "🤕"; - _emojiToText["🤕"] = ":head_bandage:"; - _textToEmoji[":face_with_head_bandage:"] = "🤕"; - _emojiToText["🤕"] = ":face_with_head_bandage:"; - _textToEmoji[":money_mouth:"] = "🤑"; - _emojiToText["🤑"] = ":money_mouth:"; - _textToEmoji[":money_mouth_face:"] = "🤑"; - _emojiToText["🤑"] = ":money_mouth_face:"; - _textToEmoji[":cowboy:"] = "🤠"; - _emojiToText["🤠"] = ":cowboy:"; - _textToEmoji[":face_with_cowboy_hat:"] = "🤠"; - _emojiToText["🤠"] = ":face_with_cowboy_hat:"; - _textToEmoji[":smiling_imp:"] = "😈"; - _emojiToText["😈"] = ":smiling_imp:"; - _textToEmoji[":imp:"] = "👿"; - _emojiToText["👿"] = ":imp:"; - _textToEmoji[":japanese_ogre:"] = "👹"; - _emojiToText["👹"] = ":japanese_ogre:"; - _textToEmoji[":ogre:"] = "👹"; - _emojiToText["👹"] = ":ogre:"; - _textToEmoji[":japanese_goblin:"] = "👺"; - _emojiToText["👺"] = ":japanese_goblin:"; - _textToEmoji[":goblin:"] = "👺"; - _emojiToText["👺"] = ":goblin:"; - _textToEmoji[":clown:"] = "🤡"; - _emojiToText["🤡"] = ":clown:"; - _textToEmoji[":clown_face:"] = "🤡"; - _emojiToText["🤡"] = ":clown_face:"; - _textToEmoji[":poop:"] = "💩"; - _emojiToText["💩"] = ":poop:"; - _textToEmoji[":shit:"] = "💩"; - _emojiToText["💩"] = ":shit:"; - _textToEmoji[":hankey:"] = "💩"; - _emojiToText["💩"] = ":hankey:"; - _textToEmoji[":poo:"] = "💩"; - _emojiToText["💩"] = ":poo:"; - _textToEmoji[":pile_of_poo:"] = "💩"; - _emojiToText["💩"] = ":pile_of_poo:"; - _textToEmoji[":ghost:"] = "👻"; - _emojiToText["👻"] = ":ghost:"; - _textToEmoji[":skull:"] = "💀"; - _emojiToText["💀"] = ":skull:"; - _textToEmoji[":skeleton:"] = "💀"; - _emojiToText["💀"] = ":skeleton:"; - _textToEmoji[":skull_crossbones:"] = "☠️"; - _emojiToText["☠️"] = ":skull_crossbones:"; - _textToEmoji[":skull_and_crossbones:"] = "☠️"; - _emojiToText["☠️"] = ":skull_and_crossbones:"; - _textToEmoji[":alien:"] = "👽"; - _emojiToText["👽"] = ":alien:"; - _textToEmoji[":space_invader:"] = "👾"; - _emojiToText["👾"] = ":space_invader:"; - _textToEmoji[":alien_monster:"] = "👾"; - _emojiToText["👾"] = ":alien_monster:"; - _textToEmoji[":robot:"] = "🤖"; - _emojiToText["🤖"] = ":robot:"; - _textToEmoji[":robot_face:"] = "🤖"; - _emojiToText["🤖"] = ":robot_face:"; - _textToEmoji[":jack_o_lantern:"] = "🎃"; - _emojiToText["🎃"] = ":jack_o_lantern:"; - _textToEmoji[":smiley_cat:"] = "😺"; - _emojiToText["😺"] = ":smiley_cat:"; - _textToEmoji[":grinning_cat:"] = "😺"; - _emojiToText["😺"] = ":grinning_cat:"; - _textToEmoji[":smile_cat:"] = "😸"; - _emojiToText["😸"] = ":smile_cat:"; - _textToEmoji[":joy_cat:"] = "😹"; - _emojiToText["😹"] = ":joy_cat:"; - _textToEmoji[":heart_eyes_cat:"] = "😻"; - _emojiToText["😻"] = ":heart_eyes_cat:"; - _textToEmoji[":smirk_cat:"] = "😼"; - _emojiToText["😼"] = ":smirk_cat:"; - _textToEmoji[":kissing_cat:"] = "😽"; - _emojiToText["😽"] = ":kissing_cat:"; - _textToEmoji[":scream_cat:"] = "🙀"; - _emojiToText["🙀"] = ":scream_cat:"; - _textToEmoji[":weary_cat:"] = "🙀"; - _emojiToText["🙀"] = ":weary_cat:"; - _textToEmoji[":crying_cat_face:"] = "😿"; - _emojiToText["😿"] = ":crying_cat_face:"; - _textToEmoji[":crying_cat:"] = "😿"; - _emojiToText["😿"] = ":crying_cat:"; - _textToEmoji[":pouting_cat:"] = "😾"; - _emojiToText["😾"] = ":pouting_cat:"; - _textToEmoji[":heart_hands:"] = "🫶"; - _emojiToText["🫶"] = ":heart_hands:"; - _textToEmoji[":palms_up_together:"] = "🤲"; - _emojiToText["🤲"] = ":palms_up_together:"; - _textToEmoji[":open_hands:"] = "👐"; - _emojiToText["👐"] = ":open_hands:"; - _textToEmoji[":raised_hands:"] = "🙌"; - _emojiToText["🙌"] = ":raised_hands:"; - _textToEmoji[":raising_hands:"] = "🙌"; - _emojiToText["🙌"] = ":raising_hands:"; - _textToEmoji[":clap:"] = "👏"; - _emojiToText["👏"] = ":clap:"; - _textToEmoji[":handshake:"] = "🤝"; - _emojiToText["🤝"] = ":handshake:"; - _textToEmoji[":shaking_hands:"] = "🤝"; - _emojiToText["🤝"] = ":shaking_hands:"; - _textToEmoji[":thumbsup:"] = "👍"; - _emojiToText["👍"] = ":thumbsup:"; - _textToEmoji[":+1:"] = "👍"; - _emojiToText["👍"] = ":+1:"; - _textToEmoji[":thumbup:"] = "👍"; - _emojiToText["👍"] = ":thumbup:"; - _textToEmoji[":thumbs_up:"] = "👍"; - _emojiToText["👍"] = ":thumbs_up:"; - _textToEmoji[":thumbsdown:"] = "👎"; - _emojiToText["👎"] = ":thumbsdown:"; - _textToEmoji[":-1:"] = "👎"; - _emojiToText["👎"] = ":-1:"; - _textToEmoji[":thumbdown:"] = "👎"; - _emojiToText["👎"] = ":thumbdown:"; - _textToEmoji[":thumbs_down:"] = "👎"; - _emojiToText["👎"] = ":thumbs_down:"; - _textToEmoji[":punch:"] = "👊"; - _emojiToText["👊"] = ":punch:"; - _textToEmoji[":oncoming_fist:"] = "👊"; - _emojiToText["👊"] = ":oncoming_fist:"; - _textToEmoji[":fist:"] = "✊"; - _emojiToText["✊"] = ":fist:"; - _textToEmoji[":raised_fist:"] = "✊"; - _emojiToText["✊"] = ":raised_fist:"; - _textToEmoji[":left_facing_fist:"] = "🤛"; - _emojiToText["🤛"] = ":left_facing_fist:"; - _textToEmoji[":left_fist:"] = "🤛"; - _emojiToText["🤛"] = ":left_fist:"; - _textToEmoji[":right_facing_fist:"] = "🤜"; - _emojiToText["🤜"] = ":right_facing_fist:"; - _textToEmoji[":right_fist:"] = "🤜"; - _emojiToText["🤜"] = ":right_fist:"; - _textToEmoji[":leftwards_pushing_hand:"] = "🫷"; - _emojiToText["🫷"] = ":leftwards_pushing_hand:"; - _textToEmoji[":rightwards_pushing_hand:"] = "🫸"; - _emojiToText["🫸"] = ":rightwards_pushing_hand:"; - _textToEmoji[":fingers_crossed:"] = "🤞"; - _emojiToText["🤞"] = ":fingers_crossed:"; - _textToEmoji[":hand_with_index_and_middle_finger_crossed:"] = "🤞"; - _emojiToText["🤞"] = ":hand_with_index_and_middle_finger_crossed:"; - _textToEmoji[":v:"] = "✌️"; - _emojiToText["✌️"] = ":v:"; - _textToEmoji[":victory_hand:"] = "✌️"; - _emojiToText["✌️"] = ":victory_hand:"; - _textToEmoji[":hand_with_index_finger_and_thumb_crossed:"] = "🫰"; - _emojiToText["🫰"] = ":hand_with_index_finger_and_thumb_crossed:"; - _textToEmoji[":love_you_gesture:"] = "🤟"; - _emojiToText["🤟"] = ":love_you_gesture:"; - _textToEmoji[":metal:"] = "🤘"; - _emojiToText["🤘"] = ":metal:"; - _textToEmoji[":sign_of_the_horns:"] = "🤘"; - _emojiToText["🤘"] = ":sign_of_the_horns:"; - _textToEmoji[":ok_hand:"] = "👌"; - _emojiToText["👌"] = ":ok_hand:"; - _textToEmoji[":pinched_fingers:"] = "🤌"; - _emojiToText["🤌"] = ":pinched_fingers:"; - _textToEmoji[":pinching_hand:"] = "🤏"; - _emojiToText["🤏"] = ":pinching_hand:"; - _textToEmoji[":palm_down_hand:"] = "🫳"; - _emojiToText["🫳"] = ":palm_down_hand:"; - _textToEmoji[":palm_up_hand:"] = "🫴"; - _emojiToText["🫴"] = ":palm_up_hand:"; - _textToEmoji[":point_left:"] = "👈"; - _emojiToText["👈"] = ":point_left:"; - _textToEmoji[":point_right:"] = "👉"; - _emojiToText["👉"] = ":point_right:"; - _textToEmoji[":point_up_2:"] = "👆"; - _emojiToText["👆"] = ":point_up_2:"; - _textToEmoji[":point_down:"] = "👇"; - _emojiToText["👇"] = ":point_down:"; - _textToEmoji[":point_up:"] = "☝️"; - _emojiToText["☝️"] = ":point_up:"; - _textToEmoji[":raised_hand:"] = "✋"; - _emojiToText["✋"] = ":raised_hand:"; - _textToEmoji[":raised_back_of_hand:"] = "🤚"; - _emojiToText["🤚"] = ":raised_back_of_hand:"; - _textToEmoji[":back_of_hand:"] = "🤚"; - _emojiToText["🤚"] = ":back_of_hand:"; - _textToEmoji[":hand_splayed:"] = "🖐️"; - _emojiToText["🖐️"] = ":hand_splayed:"; - _textToEmoji[":raised_hand_with_fingers_splayed:"] = "🖐️"; - _emojiToText["🖐️"] = ":raised_hand_with_fingers_splayed:"; - _textToEmoji[":vulcan:"] = "🖖"; - _emojiToText["🖖"] = ":vulcan:"; - _textToEmoji[":raised_hand_with_part_between_middle_and_ring_fingers:"] = "🖖"; - _emojiToText["🖖"] = ":raised_hand_with_part_between_middle_and_ring_fingers:"; - _textToEmoji[":vulcan_salute:"] = "🖖"; - _emojiToText["🖖"] = ":vulcan_salute:"; - _textToEmoji[":wave:"] = "👋"; - _emojiToText["👋"] = ":wave:"; - _textToEmoji[":waving_hand:"] = "👋"; - _emojiToText["👋"] = ":waving_hand:"; - _textToEmoji[":call_me:"] = "🤙"; - _emojiToText["🤙"] = ":call_me:"; - _textToEmoji[":call_me_hand:"] = "🤙"; - _emojiToText["🤙"] = ":call_me_hand:"; - _textToEmoji[":leftwards_hand:"] = "🫲"; - _emojiToText["🫲"] = ":leftwards_hand:"; - _textToEmoji[":rightwards_hand:"] = "🫱"; - _emojiToText["🫱"] = ":rightwards_hand:"; - _textToEmoji[":muscle:"] = "💪"; - _emojiToText["💪"] = ":muscle:"; - _textToEmoji[":flexed_biceps:"] = "💪"; - _emojiToText["💪"] = ":flexed_biceps:"; - _textToEmoji[":mechanical_arm:"] = "🦾"; - _emojiToText["🦾"] = ":mechanical_arm:"; - _textToEmoji[":middle_finger:"] = "🖕"; - _emojiToText["🖕"] = ":middle_finger:"; - _textToEmoji[":reversed_hand_with_middle_finger_extended:"] = "🖕"; - _emojiToText["🖕"] = ":reversed_hand_with_middle_finger_extended:"; - _textToEmoji[":writing_hand:"] = "✍️"; - _emojiToText["✍️"] = ":writing_hand:"; - _textToEmoji[":pray:"] = "🙏"; - _emojiToText["🙏"] = ":pray:"; - _textToEmoji[":folded_hands:"] = "🙏"; - _emojiToText["🙏"] = ":folded_hands:"; - _textToEmoji[":index_pointing_at_the_viewer:"] = "🫵"; - _emojiToText["🫵"] = ":index_pointing_at_the_viewer:"; - _textToEmoji[":foot:"] = "🦶"; - _emojiToText["🦶"] = ":foot:"; - _textToEmoji[":leg:"] = "🦵"; - _emojiToText["🦵"] = ":leg:"; - _textToEmoji[":mechanical_leg:"] = "🦿"; - _emojiToText["🦿"] = ":mechanical_leg:"; - _textToEmoji[":lipstick:"] = "💄"; - _emojiToText["💄"] = ":lipstick:"; - _textToEmoji[":kiss:"] = "💋"; - _emojiToText["💋"] = ":kiss:"; - _textToEmoji[":kiss_mark:"] = "💋"; - _emojiToText["💋"] = ":kiss_mark:"; - _textToEmoji[":lips:"] = "👄"; - _emojiToText["👄"] = ":lips:"; - _textToEmoji[":mouth:"] = "👄"; - _emojiToText["👄"] = ":mouth:"; - _textToEmoji[":biting_lip:"] = "🫦"; - _emojiToText["🫦"] = ":biting_lip:"; - _textToEmoji[":tooth:"] = "🦷"; - _emojiToText["🦷"] = ":tooth:"; - _textToEmoji[":tongue:"] = "👅"; - _emojiToText["👅"] = ":tongue:"; - _textToEmoji[":ear:"] = "👂"; - _emojiToText["👂"] = ":ear:"; - _textToEmoji[":ear_with_hearing_aid:"] = "🦻"; - _emojiToText["🦻"] = ":ear_with_hearing_aid:"; - _textToEmoji[":nose:"] = "👃"; - _emojiToText["👃"] = ":nose:"; - _textToEmoji[":footprints:"] = "👣"; - _emojiToText["👣"] = ":footprints:"; - _textToEmoji[":eye:"] = "👁️"; - _emojiToText["👁️"] = ":eye:"; - _textToEmoji[":eyes:"] = "👀"; - _emojiToText["👀"] = ":eyes:"; - _textToEmoji[":anatomical_heart:"] = "🫀"; - _emojiToText["🫀"] = ":anatomical_heart:"; - _textToEmoji[":lungs:"] = "🫁"; - _emojiToText["🫁"] = ":lungs:"; - _textToEmoji[":brain:"] = "🧠"; - _emojiToText["🧠"] = ":brain:"; - _textToEmoji[":speaking_head:"] = "🗣️"; - _emojiToText["🗣️"] = ":speaking_head:"; - _textToEmoji[":speaking_head_in_silhouette:"] = "🗣️"; - _emojiToText["🗣️"] = ":speaking_head_in_silhouette:"; - _textToEmoji[":bust_in_silhouette:"] = "👤"; - _emojiToText["👤"] = ":bust_in_silhouette:"; - _textToEmoji[":busts_in_silhouette:"] = "👥"; - _emojiToText["👥"] = ":busts_in_silhouette:"; - _textToEmoji[":people_hugging:"] = "🫂"; - _emojiToText["🫂"] = ":people_hugging:"; - _textToEmoji[":baby:"] = "👶"; - _emojiToText["👶"] = ":baby:"; - _textToEmoji[":child:"] = "🧒"; - _emojiToText["🧒"] = ":child:"; - _textToEmoji[":girl:"] = "👧"; - _emojiToText["👧"] = ":girl:"; - _textToEmoji[":boy:"] = "👦"; - _emojiToText["👦"] = ":boy:"; - _textToEmoji[":adult:"] = "🧑"; - _emojiToText["🧑"] = ":adult:"; - _textToEmoji[":person:"] = "🧑"; - _emojiToText["🧑"] = ":person:"; - _textToEmoji[":woman:"] = "👩"; - _emojiToText["👩"] = ":woman:"; - _textToEmoji[":man:"] = "👨"; - _emojiToText["👨"] = ":man:"; - _textToEmoji[":person_curly_hair:"] = "🧑‍🦱"; - _emojiToText["🧑‍🦱"] = ":person_curly_hair:"; - _textToEmoji[":woman_curly_haired:"] = "👩‍🦱"; - _emojiToText["👩‍🦱"] = ":woman_curly_haired:"; - _textToEmoji[":man_curly_haired:"] = "👨‍🦱"; - _emojiToText["👨‍🦱"] = ":man_curly_haired:"; - _textToEmoji[":person_red_hair:"] = "🧑‍🦰"; - _emojiToText["🧑‍🦰"] = ":person_red_hair:"; - _textToEmoji[":woman_red_haired:"] = "👩‍🦰"; - _emojiToText["👩‍🦰"] = ":woman_red_haired:"; - _textToEmoji[":man_red_haired:"] = "👨‍🦰"; - _emojiToText["👨‍🦰"] = ":man_red_haired:"; - _textToEmoji[":man_red_hair:"] = "👨‍🦰"; - _emojiToText["👨‍🦰"] = ":man_red_hair:"; - _textToEmoji[":blond_haired_person:"] = "👱"; - _emojiToText["👱"] = ":blond_haired_person:"; - _textToEmoji[":person_with_blond_hair:"] = "👱"; - _emojiToText["👱"] = ":person_with_blond_hair:"; - _textToEmoji[":blond_haired_woman:"] = "👱‍♀️"; - _emojiToText["👱‍♀️"] = ":blond_haired_woman:"; - _textToEmoji[":blond_haired_man:"] = "👱‍♂️"; - _emojiToText["👱‍♂️"] = ":blond_haired_man:"; - _textToEmoji[":person_white_hair:"] = "🧑‍🦳"; - _emojiToText["🧑‍🦳"] = ":person_white_hair:"; - _textToEmoji[":woman_white_haired:"] = "👩‍🦳"; - _emojiToText["👩‍🦳"] = ":woman_white_haired:"; - _textToEmoji[":man_white_haired:"] = "👨‍🦳"; - _emojiToText["👨‍🦳"] = ":man_white_haired:"; - _textToEmoji[":person_bald:"] = "🧑‍🦲"; - _emojiToText["🧑‍🦲"] = ":person_bald:"; - _textToEmoji[":woman_bald:"] = "👩‍🦲"; - _emojiToText["👩‍🦲"] = ":woman_bald:"; - _textToEmoji[":man_bald:"] = "👨‍🦲"; - _emojiToText["👨‍🦲"] = ":man_bald:"; - _textToEmoji[":bearded_person:"] = "🧔"; - _emojiToText["🧔"] = ":bearded_person:"; - _textToEmoji[":person_beard:"] = "🧔"; - _emojiToText["🧔"] = ":person_beard:"; - _textToEmoji[":woman_beard:"] = "🧔‍♀️"; - _emojiToText["🧔‍♀️"] = ":woman_beard:"; - _textToEmoji[":man_beard:"] = "🧔‍♂️"; - _emojiToText["🧔‍♂️"] = ":man_beard:"; - _textToEmoji[":older_adult:"] = "🧓"; - _emojiToText["🧓"] = ":older_adult:"; - _textToEmoji[":older_person:"] = "🧓"; - _emojiToText["🧓"] = ":older_person:"; - _textToEmoji[":older_woman:"] = "👵"; - _emojiToText["👵"] = ":older_woman:"; - _textToEmoji[":grandma:"] = "👵"; - _emojiToText["👵"] = ":grandma:"; - _textToEmoji[":old_woman:"] = "👵"; - _emojiToText["👵"] = ":old_woman:"; - _textToEmoji[":older_man:"] = "👴"; - _emojiToText["👴"] = ":older_man:"; - _textToEmoji[":old_man:"] = "👴"; - _emojiToText["👴"] = ":old_man:"; - _textToEmoji[":man_with_chinese_cap:"] = "👲"; - _emojiToText["👲"] = ":man_with_chinese_cap:"; - _textToEmoji[":man_with_gua_pi_mao:"] = "👲"; - _emojiToText["👲"] = ":man_with_gua_pi_mao:"; - _textToEmoji[":person_wearing_turban:"] = "👳"; - _emojiToText["👳"] = ":person_wearing_turban:"; - _textToEmoji[":man_with_turban:"] = "👳"; - _emojiToText["👳"] = ":man_with_turban:"; - _textToEmoji[":woman_wearing_turban:"] = "👳‍♀️"; - _emojiToText["👳‍♀️"] = ":woman_wearing_turban:"; - _textToEmoji[":man_wearing_turban:"] = "👳‍♂️"; - _emojiToText["👳‍♂️"] = ":man_wearing_turban:"; - _textToEmoji[":woman_with_headscarf:"] = "🧕"; - _emojiToText["🧕"] = ":woman_with_headscarf:"; - _textToEmoji[":police_officer:"] = "👮"; - _emojiToText["👮"] = ":police_officer:"; - _textToEmoji[":cop:"] = "👮"; - _emojiToText["👮"] = ":cop:"; - _textToEmoji[":woman_police_officer:"] = "👮‍♀️"; - _emojiToText["👮‍♀️"] = ":woman_police_officer:"; - _textToEmoji[":man_police_officer:"] = "👮‍♂️"; - _emojiToText["👮‍♂️"] = ":man_police_officer:"; - _textToEmoji[":construction_worker:"] = "👷"; - _emojiToText["👷"] = ":construction_worker:"; - _textToEmoji[":woman_construction_worker:"] = "👷‍♀️"; - _emojiToText["👷‍♀️"] = ":woman_construction_worker:"; - _textToEmoji[":man_construction_worker:"] = "👷‍♂️"; - _emojiToText["👷‍♂️"] = ":man_construction_worker:"; - _textToEmoji[":guard:"] = "💂"; - _emojiToText["💂"] = ":guard:"; - _textToEmoji[":guardsman:"] = "💂"; - _emojiToText["💂"] = ":guardsman:"; - _textToEmoji[":woman_guard:"] = "💂‍♀️"; - _emojiToText["💂‍♀️"] = ":woman_guard:"; - _textToEmoji[":man_guard:"] = "💂‍♂️"; - _emojiToText["💂‍♂️"] = ":man_guard:"; - _textToEmoji[":detective:"] = "🕵️"; - _emojiToText["🕵️"] = ":detective:"; - _textToEmoji[":spy:"] = "🕵️"; - _emojiToText["🕵️"] = ":spy:"; - _textToEmoji[":sleuth_or_spy:"] = "🕵️"; - _emojiToText["🕵️"] = ":sleuth_or_spy:"; - _textToEmoji[":woman_detective:"] = "🕵️‍♀️"; - _emojiToText["🕵️‍♀️"] = ":woman_detective:"; - _textToEmoji[":man_detective:"] = "🕵️‍♂️"; - _emojiToText["🕵️‍♂️"] = ":man_detective:"; - _textToEmoji[":health_worker:"] = "🧑‍⚕️"; - _emojiToText["🧑‍⚕️"] = ":health_worker:"; - _textToEmoji[":woman_health_worker:"] = "👩‍⚕️"; - _emojiToText["👩‍⚕️"] = ":woman_health_worker:"; - _textToEmoji[":man_health_worker:"] = "👨‍⚕️"; - _emojiToText["👨‍⚕️"] = ":man_health_worker:"; - _textToEmoji[":farmer:"] = "🧑‍🌾"; - _emojiToText["🧑‍🌾"] = ":farmer:"; - _textToEmoji[":woman_farmer:"] = "👩‍🌾"; - _emojiToText["👩‍🌾"] = ":woman_farmer:"; - _textToEmoji[":man_farmer:"] = "👨‍🌾"; - _emojiToText["👨‍🌾"] = ":man_farmer:"; - _textToEmoji[":cook:"] = "🧑‍🍳"; - _emojiToText["🧑‍🍳"] = ":cook:"; - _textToEmoji[":woman_cook:"] = "👩‍🍳"; - _emojiToText["👩‍🍳"] = ":woman_cook:"; - _textToEmoji[":man_cook:"] = "👨‍🍳"; - _emojiToText["👨‍🍳"] = ":man_cook:"; - _textToEmoji[":student:"] = "🧑‍🎓"; - _emojiToText["🧑‍🎓"] = ":student:"; - _textToEmoji[":woman_student:"] = "👩‍🎓"; - _emojiToText["👩‍🎓"] = ":woman_student:"; - _textToEmoji[":man_student:"] = "👨‍🎓"; - _emojiToText["👨‍🎓"] = ":man_student:"; - _textToEmoji[":singer:"] = "🧑‍🎤"; - _emojiToText["🧑‍🎤"] = ":singer:"; - _textToEmoji[":woman_singer:"] = "👩‍🎤"; - _emojiToText["👩‍🎤"] = ":woman_singer:"; - _textToEmoji[":man_singer:"] = "👨‍🎤"; - _emojiToText["👨‍🎤"] = ":man_singer:"; - _textToEmoji[":teacher:"] = "🧑‍🏫"; - _emojiToText["🧑‍🏫"] = ":teacher:"; - _textToEmoji[":woman_teacher:"] = "👩‍🏫"; - _emojiToText["👩‍🏫"] = ":woman_teacher:"; - _textToEmoji[":man_teacher:"] = "👨‍🏫"; - _emojiToText["👨‍🏫"] = ":man_teacher:"; - _textToEmoji[":factory_worker:"] = "🧑‍🏭"; - _emojiToText["🧑‍🏭"] = ":factory_worker:"; - _textToEmoji[":woman_factory_worker:"] = "👩‍🏭"; - _emojiToText["👩‍🏭"] = ":woman_factory_worker:"; - _textToEmoji[":man_factory_worker:"] = "👨‍🏭"; - _emojiToText["👨‍🏭"] = ":man_factory_worker:"; - _textToEmoji[":technologist:"] = "🧑‍💻"; - _emojiToText["🧑‍💻"] = ":technologist:"; - _textToEmoji[":woman_technologist:"] = "👩‍💻"; - _emojiToText["👩‍💻"] = ":woman_technologist:"; - _textToEmoji[":man_technologist:"] = "👨‍💻"; - _emojiToText["👨‍💻"] = ":man_technologist:"; - _textToEmoji[":office_worker:"] = "🧑‍💼"; - _emojiToText["🧑‍💼"] = ":office_worker:"; - _textToEmoji[":woman_office_worker:"] = "👩‍💼"; - _emojiToText["👩‍💼"] = ":woman_office_worker:"; - _textToEmoji[":man_office_worker:"] = "👨‍💼"; - _emojiToText["👨‍💼"] = ":man_office_worker:"; - _textToEmoji[":mechanic:"] = "🧑‍🔧"; - _emojiToText["🧑‍🔧"] = ":mechanic:"; - _textToEmoji[":woman_mechanic:"] = "👩‍🔧"; - _emojiToText["👩‍🔧"] = ":woman_mechanic:"; - _textToEmoji[":man_mechanic:"] = "👨‍🔧"; - _emojiToText["👨‍🔧"] = ":man_mechanic:"; - _textToEmoji[":scientist:"] = "🧑‍🔬"; - _emojiToText["🧑‍🔬"] = ":scientist:"; - _textToEmoji[":woman_scientist:"] = "👩‍🔬"; - _emojiToText["👩‍🔬"] = ":woman_scientist:"; - _textToEmoji[":man_scientist:"] = "👨‍🔬"; - _emojiToText["👨‍🔬"] = ":man_scientist:"; - _textToEmoji[":artist:"] = "🧑‍🎨"; - _emojiToText["🧑‍🎨"] = ":artist:"; - _textToEmoji[":woman_artist:"] = "👩‍🎨"; - _emojiToText["👩‍🎨"] = ":woman_artist:"; - _textToEmoji[":man_artist:"] = "👨‍🎨"; - _emojiToText["👨‍🎨"] = ":man_artist:"; - _textToEmoji[":firefighter:"] = "🧑‍🚒"; - _emojiToText["🧑‍🚒"] = ":firefighter:"; - _textToEmoji[":woman_firefighter:"] = "👩‍🚒"; - _emojiToText["👩‍🚒"] = ":woman_firefighter:"; - _textToEmoji[":man_firefighter:"] = "👨‍🚒"; - _emojiToText["👨‍🚒"] = ":man_firefighter:"; - _textToEmoji[":pilot:"] = "🧑‍✈️"; - _emojiToText["🧑‍✈️"] = ":pilot:"; - _textToEmoji[":woman_pilot:"] = "👩‍✈️"; - _emojiToText["👩‍✈️"] = ":woman_pilot:"; - _textToEmoji[":man_pilot:"] = "👨‍✈️"; - _emojiToText["👨‍✈️"] = ":man_pilot:"; - _textToEmoji[":astronaut:"] = "🧑‍🚀"; - _emojiToText["🧑‍🚀"] = ":astronaut:"; - _textToEmoji[":woman_astronaut:"] = "👩‍🚀"; - _emojiToText["👩‍🚀"] = ":woman_astronaut:"; - _textToEmoji[":man_astronaut:"] = "👨‍🚀"; - _emojiToText["👨‍🚀"] = ":man_astronaut:"; - _textToEmoji[":judge:"] = "🧑‍⚖️"; - _emojiToText["🧑‍⚖️"] = ":judge:"; - _textToEmoji[":woman_judge:"] = "👩‍⚖️"; - _emojiToText["👩‍⚖️"] = ":woman_judge:"; - _textToEmoji[":man_judge:"] = "👨‍⚖️"; - _emojiToText["👨‍⚖️"] = ":man_judge:"; - _textToEmoji[":person_with_veil:"] = "👰"; - _emojiToText["👰"] = ":person_with_veil:"; - _textToEmoji[":woman_with_veil:"] = "👰‍♀️"; - _emojiToText["👰‍♀️"] = ":woman_with_veil:"; - _textToEmoji[":bride_with_veil:"] = "👰‍♀️"; - _emojiToText["👰‍♀️"] = ":bride_with_veil:"; - _textToEmoji[":man_with_veil:"] = "👰‍♂️"; - _emojiToText["👰‍♂️"] = ":man_with_veil:"; - _textToEmoji[":person_in_tuxedo:"] = "🤵"; - _emojiToText["🤵"] = ":person_in_tuxedo:"; - _textToEmoji[":woman_in_tuxedo:"] = "🤵‍♀️"; - _emojiToText["🤵‍♀️"] = ":woman_in_tuxedo:"; - _textToEmoji[":man_in_tuxedo:"] = "🤵‍♂️"; - _emojiToText["🤵‍♂️"] = ":man_in_tuxedo:"; - _textToEmoji[":person_with_crown:"] = "🫅"; - _emojiToText["🫅"] = ":person_with_crown:"; - _textToEmoji[":princess:"] = "👸"; - _emojiToText["👸"] = ":princess:"; - _textToEmoji[":prince:"] = "🤴"; - _emojiToText["🤴"] = ":prince:"; - _textToEmoji[":superhero:"] = "🦸"; - _emojiToText["🦸"] = ":superhero:"; - _textToEmoji[":woman_superhero:"] = "🦸‍♀️"; - _emojiToText["🦸‍♀️"] = ":woman_superhero:"; - _textToEmoji[":man_superhero:"] = "🦸‍♂️"; - _emojiToText["🦸‍♂️"] = ":man_superhero:"; - _textToEmoji[":supervillain:"] = "🦹"; - _emojiToText["🦹"] = ":supervillain:"; - _textToEmoji[":woman_supervillain:"] = "🦹‍♀️"; - _emojiToText["🦹‍♀️"] = ":woman_supervillain:"; - _textToEmoji[":man_supervillain:"] = "🦹‍♂️"; - _emojiToText["🦹‍♂️"] = ":man_supervillain:"; - _textToEmoji[":ninja:"] = "🥷"; - _emojiToText["🥷"] = ":ninja:"; - _textToEmoji[":mx_claus:"] = "🧑‍🎄"; - _emojiToText["🧑‍🎄"] = ":mx_claus:"; - _textToEmoji[":mrs_claus:"] = "🤶"; - _emojiToText["🤶"] = ":mrs_claus:"; - _textToEmoji[":mother_christmas:"] = "🤶"; - _emojiToText["🤶"] = ":mother_christmas:"; - _textToEmoji[":santa:"] = "🎅"; - _emojiToText["🎅"] = ":santa:"; - _textToEmoji[":santa_claus:"] = "🎅"; - _emojiToText["🎅"] = ":santa_claus:"; - _textToEmoji[":mage:"] = "🧙"; - _emojiToText["🧙"] = ":mage:"; - _textToEmoji[":woman_mage:"] = "🧙‍♀️"; - _emojiToText["🧙‍♀️"] = ":woman_mage:"; - _textToEmoji[":man_mage:"] = "🧙‍♂️"; - _emojiToText["🧙‍♂️"] = ":man_mage:"; - _textToEmoji[":elf:"] = "🧝"; - _emojiToText["🧝"] = ":elf:"; - _textToEmoji[":woman_elf:"] = "🧝‍♀️"; - _emojiToText["🧝‍♀️"] = ":woman_elf:"; - _textToEmoji[":man_elf:"] = "🧝‍♂️"; - _emojiToText["🧝‍♂️"] = ":man_elf:"; - _textToEmoji[":troll:"] = "🧌"; - _emojiToText["🧌"] = ":troll:"; - _textToEmoji[":vampire:"] = "🧛"; - _emojiToText["🧛"] = ":vampire:"; - _textToEmoji[":woman_vampire:"] = "🧛‍♀️"; - _emojiToText["🧛‍♀️"] = ":woman_vampire:"; - _textToEmoji[":man_vampire:"] = "🧛‍♂️"; - _emojiToText["🧛‍♂️"] = ":man_vampire:"; - _textToEmoji[":zombie:"] = "🧟"; - _emojiToText["🧟"] = ":zombie:"; - _textToEmoji[":woman_zombie:"] = "🧟‍♀️"; - _emojiToText["🧟‍♀️"] = ":woman_zombie:"; - _textToEmoji[":man_zombie:"] = "🧟‍♂️"; - _emojiToText["🧟‍♂️"] = ":man_zombie:"; - _textToEmoji[":genie:"] = "🧞"; - _emojiToText["🧞"] = ":genie:"; - _textToEmoji[":woman_genie:"] = "🧞‍♀️"; - _emojiToText["🧞‍♀️"] = ":woman_genie:"; - _textToEmoji[":man_genie:"] = "🧞‍♂️"; - _emojiToText["🧞‍♂️"] = ":man_genie:"; - _textToEmoji[":merperson:"] = "🧜"; - _emojiToText["🧜"] = ":merperson:"; - _textToEmoji[":mermaid:"] = "🧜‍♀️"; - _emojiToText["🧜‍♀️"] = ":mermaid:"; - _textToEmoji[":merman:"] = "🧜‍♂️"; - _emojiToText["🧜‍♂️"] = ":merman:"; - _textToEmoji[":fairy:"] = "🧚"; - _emojiToText["🧚"] = ":fairy:"; - _textToEmoji[":woman_fairy:"] = "🧚‍♀️"; - _emojiToText["🧚‍♀️"] = ":woman_fairy:"; - _textToEmoji[":man_fairy:"] = "🧚‍♂️"; - _emojiToText["🧚‍♂️"] = ":man_fairy:"; - _textToEmoji[":angel:"] = "👼"; - _emojiToText["👼"] = ":angel:"; - _textToEmoji[":baby_angel:"] = "👼"; - _emojiToText["👼"] = ":baby_angel:"; - _textToEmoji[":pregnant_person:"] = "🫄"; - _emojiToText["🫄"] = ":pregnant_person:"; - _textToEmoji[":pregnant_woman:"] = "🤰"; - _emojiToText["🤰"] = ":pregnant_woman:"; - _textToEmoji[":expecting_woman:"] = "🤰"; - _emojiToText["🤰"] = ":expecting_woman:"; - _textToEmoji[":pregnant_man:"] = "🫃"; - _emojiToText["🫃"] = ":pregnant_man:"; - _textToEmoji[":breast_feeding:"] = "🤱"; - _emojiToText["🤱"] = ":breast_feeding:"; - _textToEmoji[":person_feeding_baby:"] = "🧑‍🍼"; - _emojiToText["🧑‍🍼"] = ":person_feeding_baby:"; - _textToEmoji[":woman_feeding_baby:"] = "👩‍🍼"; - _emojiToText["👩‍🍼"] = ":woman_feeding_baby:"; - _textToEmoji[":man_feeding_baby:"] = "👨‍🍼"; - _emojiToText["👨‍🍼"] = ":man_feeding_baby:"; - _textToEmoji[":person_bowing:"] = "🙇"; - _emojiToText["🙇"] = ":person_bowing:"; - _textToEmoji[":bow:"] = "🙇"; - _emojiToText["🙇"] = ":bow:"; - _textToEmoji[":woman_bowing:"] = "🙇‍♀️"; - _emojiToText["🙇‍♀️"] = ":woman_bowing:"; - _textToEmoji[":man_bowing:"] = "🙇‍♂️"; - _emojiToText["🙇‍♂️"] = ":man_bowing:"; - _textToEmoji[":person_tipping_hand:"] = "💁"; - _emojiToText["💁"] = ":person_tipping_hand:"; - _textToEmoji[":information_desk_person:"] = "💁"; - _emojiToText["💁"] = ":information_desk_person:"; - _textToEmoji[":woman_tipping_hand:"] = "💁‍♀️"; - _emojiToText["💁‍♀️"] = ":woman_tipping_hand:"; - _textToEmoji[":man_tipping_hand:"] = "💁‍♂️"; - _emojiToText["💁‍♂️"] = ":man_tipping_hand:"; - _textToEmoji[":person_gesturing_no:"] = "🙅"; - _emojiToText["🙅"] = ":person_gesturing_no:"; - _textToEmoji[":no_good:"] = "🙅"; - _emojiToText["🙅"] = ":no_good:"; - _textToEmoji[":woman_gesturing_no:"] = "🙅‍♀️"; - _emojiToText["🙅‍♀️"] = ":woman_gesturing_no:"; - _textToEmoji[":man_gesturing_no:"] = "🙅‍♂️"; - _emojiToText["🙅‍♂️"] = ":man_gesturing_no:"; - _textToEmoji[":person_gesturing_ok:"] = "🙆"; - _emojiToText["🙆"] = ":person_gesturing_ok:"; - _textToEmoji[":woman_gesturing_ok:"] = "🙆‍♀️"; - _emojiToText["🙆‍♀️"] = ":woman_gesturing_ok:"; - _textToEmoji[":man_gesturing_ok:"] = "🙆‍♂️"; - _emojiToText["🙆‍♂️"] = ":man_gesturing_ok:"; - _textToEmoji[":person_raising_hand:"] = "🙋"; - _emojiToText["🙋"] = ":person_raising_hand:"; - _textToEmoji[":raising_hand:"] = "🙋"; - _emojiToText["🙋"] = ":raising_hand:"; - _textToEmoji[":woman_raising_hand:"] = "🙋‍♀️"; - _emojiToText["🙋‍♀️"] = ":woman_raising_hand:"; - _textToEmoji[":man_raising_hand:"] = "🙋‍♂️"; - _emojiToText["🙋‍♂️"] = ":man_raising_hand:"; - _textToEmoji[":deaf_person:"] = "🧏"; - _emojiToText["🧏"] = ":deaf_person:"; - _textToEmoji[":deaf_woman:"] = "🧏‍♀️"; - _emojiToText["🧏‍♀️"] = ":deaf_woman:"; - _textToEmoji[":deaf_man:"] = "🧏‍♂️"; - _emojiToText["🧏‍♂️"] = ":deaf_man:"; - _textToEmoji[":person_facepalming:"] = "🤦"; - _emojiToText["🤦"] = ":person_facepalming:"; - _textToEmoji[":face_palm:"] = "🤦"; - _emojiToText["🤦"] = ":face_palm:"; - _textToEmoji[":facepalm:"] = "🤦"; - _emojiToText["🤦"] = ":facepalm:"; - _textToEmoji[":woman_facepalming:"] = "🤦‍♀️"; - _emojiToText["🤦‍♀️"] = ":woman_facepalming:"; - _textToEmoji[":man_facepalming:"] = "🤦‍♂️"; - _emojiToText["🤦‍♂️"] = ":man_facepalming:"; - _textToEmoji[":person_shrugging:"] = "🤷"; - _emojiToText["🤷"] = ":person_shrugging:"; - _textToEmoji[":shrug:"] = "🤷"; - _emojiToText["🤷"] = ":shrug:"; - _textToEmoji[":woman_shrugging:"] = "🤷‍♀️"; - _emojiToText["🤷‍♀️"] = ":woman_shrugging:"; - _textToEmoji[":man_shrugging:"] = "🤷‍♂️"; - _emojiToText["🤷‍♂️"] = ":man_shrugging:"; - _textToEmoji[":person_pouting:"] = "🙎"; - _emojiToText["🙎"] = ":person_pouting:"; - _textToEmoji[":person_with_pouting_face:"] = "🙎"; - _emojiToText["🙎"] = ":person_with_pouting_face:"; - _textToEmoji[":woman_pouting:"] = "🙎‍♀️"; - _emojiToText["🙎‍♀️"] = ":woman_pouting:"; - _textToEmoji[":man_pouting:"] = "🙎‍♂️"; - _emojiToText["🙎‍♂️"] = ":man_pouting:"; - _textToEmoji[":person_frowning:"] = "🙍"; - _emojiToText["🙍"] = ":person_frowning:"; - _textToEmoji[":woman_frowning:"] = "🙍‍♀️"; - _emojiToText["🙍‍♀️"] = ":woman_frowning:"; - _textToEmoji[":man_frowning:"] = "🙍‍♂️"; - _emojiToText["🙍‍♂️"] = ":man_frowning:"; - _textToEmoji[":person_getting_haircut:"] = "💇"; - _emojiToText["💇"] = ":person_getting_haircut:"; - _textToEmoji[":haircut:"] = "💇"; - _emojiToText["💇"] = ":haircut:"; - _textToEmoji[":woman_getting_haircut:"] = "💇‍♀️"; - _emojiToText["💇‍♀️"] = ":woman_getting_haircut:"; - _textToEmoji[":man_getting_haircut:"] = "💇‍♂️"; - _emojiToText["💇‍♂️"] = ":man_getting_haircut:"; - _textToEmoji[":person_getting_massage:"] = "💆"; - _emojiToText["💆"] = ":person_getting_massage:"; - _textToEmoji[":massage:"] = "💆"; - _emojiToText["💆"] = ":massage:"; - _textToEmoji[":woman_getting_face_massage:"] = "💆‍♀️"; - _emojiToText["💆‍♀️"] = ":woman_getting_face_massage:"; - _textToEmoji[":man_getting_face_massage:"] = "💆‍♂️"; - _emojiToText["💆‍♂️"] = ":man_getting_face_massage:"; - _textToEmoji[":person_in_steamy_room:"] = "🧖"; - _emojiToText["🧖"] = ":person_in_steamy_room:"; - _textToEmoji[":woman_in_steamy_room:"] = "🧖‍♀️"; - _emojiToText["🧖‍♀️"] = ":woman_in_steamy_room:"; - _textToEmoji[":man_in_steamy_room:"] = "🧖‍♂️"; - _emojiToText["🧖‍♂️"] = ":man_in_steamy_room:"; - _textToEmoji[":nail_care:"] = "💅"; - _emojiToText["💅"] = ":nail_care:"; - _textToEmoji[":nail_polish:"] = "💅"; - _emojiToText["💅"] = ":nail_polish:"; - _textToEmoji[":selfie:"] = "🤳"; - _emojiToText["🤳"] = ":selfie:"; - _textToEmoji[":dancer:"] = "💃"; - _emojiToText["💃"] = ":dancer:"; - _textToEmoji[":woman_dancing:"] = "💃"; - _emojiToText["💃"] = ":woman_dancing:"; - _textToEmoji[":man_dancing:"] = "🕺"; - _emojiToText["🕺"] = ":man_dancing:"; - _textToEmoji[":male_dancer:"] = "🕺"; - _emojiToText["🕺"] = ":male_dancer:"; - _textToEmoji[":people_with_bunny_ears_partying:"] = "👯"; - _emojiToText["👯"] = ":people_with_bunny_ears_partying:"; - _textToEmoji[":dancers:"] = "👯"; - _emojiToText["👯"] = ":dancers:"; - _textToEmoji[":women_with_bunny_ears_partying:"] = "👯‍♀️"; - _emojiToText["👯‍♀️"] = ":women_with_bunny_ears_partying:"; - _textToEmoji[":men_with_bunny_ears_partying:"] = "👯‍♂️"; - _emojiToText["👯‍♂️"] = ":men_with_bunny_ears_partying:"; - _textToEmoji[":levitate:"] = "🕴️"; - _emojiToText["🕴️"] = ":levitate:"; - _textToEmoji[":man_in_business_suit_levitating:"] = "🕴️"; - _emojiToText["🕴️"] = ":man_in_business_suit_levitating:"; - _textToEmoji[":person_in_manual_wheelchair:"] = "🧑‍🦽"; - _emojiToText["🧑‍🦽"] = ":person_in_manual_wheelchair:"; - _textToEmoji[":woman_in_manual_wheelchair:"] = "👩‍🦽"; - _emojiToText["👩‍🦽"] = ":woman_in_manual_wheelchair:"; - _textToEmoji[":man_in_manual_wheelchair:"] = "👨‍🦽"; - _emojiToText["👨‍🦽"] = ":man_in_manual_wheelchair:"; - _textToEmoji[":person_in_motorized_wheelchair:"] = "🧑‍🦼"; - _emojiToText["🧑‍🦼"] = ":person_in_motorized_wheelchair:"; - _textToEmoji[":woman_in_motorized_wheelchair:"] = "👩‍🦼"; - _emojiToText["👩‍🦼"] = ":woman_in_motorized_wheelchair:"; - _textToEmoji[":man_in_motorized_wheelchair:"] = "👨‍🦼"; - _emojiToText["👨‍🦼"] = ":man_in_motorized_wheelchair:"; - _textToEmoji[":person_walking:"] = "🚶"; - _emojiToText["🚶"] = ":person_walking:"; - _textToEmoji[":walking:"] = "🚶"; - _emojiToText["🚶"] = ":walking:"; - _textToEmoji[":woman_walking:"] = "🚶‍♀️"; - _emojiToText["🚶‍♀️"] = ":woman_walking:"; - _textToEmoji[":man_walking:"] = "🚶‍♂️"; - _emojiToText["🚶‍♂️"] = ":man_walking:"; - _textToEmoji[":person_with_probing_cane:"] = "🧑‍🦯"; - _emojiToText["🧑‍🦯"] = ":person_with_probing_cane:"; - _textToEmoji[":woman_with_probing_cane:"] = "👩‍🦯"; - _emojiToText["👩‍🦯"] = ":woman_with_probing_cane:"; - _textToEmoji[":man_with_probing_cane:"] = "👨‍🦯"; - _emojiToText["👨‍🦯"] = ":man_with_probing_cane:"; - _textToEmoji[":person_kneeling:"] = "🧎"; - _emojiToText["🧎"] = ":person_kneeling:"; - _textToEmoji[":woman_kneeling:"] = "🧎‍♀️"; - _emojiToText["🧎‍♀️"] = ":woman_kneeling:"; - _textToEmoji[":man_kneeling:"] = "🧎‍♂️"; - _emojiToText["🧎‍♂️"] = ":man_kneeling:"; - _textToEmoji[":person_running:"] = "🏃"; - _emojiToText["🏃"] = ":person_running:"; - _textToEmoji[":runner:"] = "🏃"; - _emojiToText["🏃"] = ":runner:"; - _textToEmoji[":woman_running:"] = "🏃‍♀️"; - _emojiToText["🏃‍♀️"] = ":woman_running:"; - _textToEmoji[":man_running:"] = "🏃‍♂️"; - _emojiToText["🏃‍♂️"] = ":man_running:"; - _textToEmoji[":person_standing:"] = "🧍"; - _emojiToText["🧍"] = ":person_standing:"; - _textToEmoji[":woman_standing:"] = "🧍‍♀️"; - _emojiToText["🧍‍♀️"] = ":woman_standing:"; - _textToEmoji[":man_standing:"] = "🧍‍♂️"; - _emojiToText["🧍‍♂️"] = ":man_standing:"; - _textToEmoji[":people_holding_hands:"] = "🧑‍🤝‍🧑"; - _emojiToText["🧑‍🤝‍🧑"] = ":people_holding_hands:"; - _textToEmoji[":couple:"] = "👫"; - _emojiToText["👫"] = ":couple:"; - _textToEmoji[":two_women_holding_hands:"] = "👭"; - _emojiToText["👭"] = ":two_women_holding_hands:"; - _textToEmoji[":two_men_holding_hands:"] = "👬"; - _emojiToText["👬"] = ":two_men_holding_hands:"; - _textToEmoji[":couple_with_heart:"] = "💑"; - _emojiToText["💑"] = ":couple_with_heart:"; - _textToEmoji[":couple_with_heart_woman_man:"] = "👩‍❤️‍👨"; - _emojiToText["👩‍❤️‍👨"] = ":couple_with_heart_woman_man:"; - _textToEmoji[":couple_ww:"] = "👩‍❤️‍👩"; - _emojiToText["👩‍❤️‍👩"] = ":couple_ww:"; - _textToEmoji[":couple_with_heart_ww:"] = "👩‍❤️‍👩"; - _emojiToText["👩‍❤️‍👩"] = ":couple_with_heart_ww:"; - _textToEmoji[":couple_mm:"] = "👨‍❤️‍👨"; - _emojiToText["👨‍❤️‍👨"] = ":couple_mm:"; - _textToEmoji[":couple_with_heart_mm:"] = "👨‍❤️‍👨"; - _emojiToText["👨‍❤️‍👨"] = ":couple_with_heart_mm:"; - _textToEmoji[":couplekiss:"] = "💏"; - _emojiToText["💏"] = ":couplekiss:"; - _textToEmoji[":kiss_woman_man:"] = "👩‍❤️‍💋‍👨"; - _emojiToText["👩‍❤️‍💋‍👨"] = ":kiss_woman_man:"; - _textToEmoji[":kiss_ww:"] = "👩‍❤️‍💋‍👩"; - _emojiToText["👩‍❤️‍💋‍👩"] = ":kiss_ww:"; - _textToEmoji[":couplekiss_ww:"] = "👩‍❤️‍💋‍👩"; - _emojiToText["👩‍❤️‍💋‍👩"] = ":couplekiss_ww:"; - _textToEmoji[":kiss_mm:"] = "👨‍❤️‍💋‍👨"; - _emojiToText["👨‍❤️‍💋‍👨"] = ":kiss_mm:"; - _textToEmoji[":couplekiss_mm:"] = "👨‍❤️‍💋‍👨"; - _emojiToText["👨‍❤️‍💋‍👨"] = ":couplekiss_mm:"; - _textToEmoji[":kiss_man_man:"] = "👨‍❤️‍💋‍👨"; - _emojiToText["👨‍❤️‍💋‍👨"] = ":kiss_man_man:"; - _textToEmoji[":family:"] = "👪"; - _emojiToText["👪"] = ":family:"; - _textToEmoji[":family_man_woman_boy:"] = "👨‍👩‍👦"; - _emojiToText["👨‍👩‍👦"] = ":family_man_woman_boy:"; - _textToEmoji[":family_mwg:"] = "👨‍👩‍👧"; - _emojiToText["👨‍👩‍👧"] = ":family_mwg:"; - _textToEmoji[":family_mwgb:"] = "👨‍👩‍👧‍👦"; - _emojiToText["👨‍👩‍👧‍👦"] = ":family_mwgb:"; - _textToEmoji[":family_mwbb:"] = "👨‍👩‍👦‍👦"; - _emojiToText["👨‍👩‍👦‍👦"] = ":family_mwbb:"; - _textToEmoji[":family_mwgg:"] = "👨‍👩‍👧‍👧"; - _emojiToText["👨‍👩‍👧‍👧"] = ":family_mwgg:"; - _textToEmoji[":family_wwb:"] = "👩‍👩‍👦"; - _emojiToText["👩‍👩‍👦"] = ":family_wwb:"; - _textToEmoji[":family_wwg:"] = "👩‍👩‍👧"; - _emojiToText["👩‍👩‍👧"] = ":family_wwg:"; - _textToEmoji[":family_wwgb:"] = "👩‍👩‍👧‍👦"; - _emojiToText["👩‍👩‍👧‍👦"] = ":family_wwgb:"; - _textToEmoji[":family_wwbb:"] = "👩‍👩‍👦‍👦"; - _emojiToText["👩‍👩‍👦‍👦"] = ":family_wwbb:"; - _textToEmoji[":family_wwgg:"] = "👩‍👩‍👧‍👧"; - _emojiToText["👩‍👩‍👧‍👧"] = ":family_wwgg:"; - _textToEmoji[":family_mmb:"] = "👨‍👨‍👦"; - _emojiToText["👨‍👨‍👦"] = ":family_mmb:"; - _textToEmoji[":family_mmg:"] = "👨‍👨‍👧"; - _emojiToText["👨‍👨‍👧"] = ":family_mmg:"; - _textToEmoji[":family_mmgb:"] = "👨‍👨‍👧‍👦"; - _emojiToText["👨‍👨‍👧‍👦"] = ":family_mmgb:"; - _textToEmoji[":family_mmbb:"] = "👨‍👨‍👦‍👦"; - _emojiToText["👨‍👨‍👦‍👦"] = ":family_mmbb:"; - _textToEmoji[":family_mmgg:"] = "👨‍👨‍👧‍👧"; - _emojiToText["👨‍👨‍👧‍👧"] = ":family_mmgg:"; - _textToEmoji[":family_woman_boy:"] = "👩‍👦"; - _emojiToText["👩‍👦"] = ":family_woman_boy:"; - _textToEmoji[":family_woman_girl:"] = "👩‍👧"; - _emojiToText["👩‍👧"] = ":family_woman_girl:"; - _textToEmoji[":family_woman_girl_boy:"] = "👩‍👧‍👦"; - _emojiToText["👩‍👧‍👦"] = ":family_woman_girl_boy:"; - _textToEmoji[":family_woman_boy_boy:"] = "👩‍👦‍👦"; - _emojiToText["👩‍👦‍👦"] = ":family_woman_boy_boy:"; - _textToEmoji[":family_woman_girl_girl:"] = "👩‍👧‍👧"; - _emojiToText["👩‍👧‍👧"] = ":family_woman_girl_girl:"; - _textToEmoji[":family_man_boy:"] = "👨‍👦"; - _emojiToText["👨‍👦"] = ":family_man_boy:"; - _textToEmoji[":family_man_girl:"] = "👨‍👧"; - _emojiToText["👨‍👧"] = ":family_man_girl:"; - _textToEmoji[":family_man_girl_boy:"] = "👨‍👧‍👦"; - _emojiToText["👨‍👧‍👦"] = ":family_man_girl_boy:"; - _textToEmoji[":family_man_boy_boy:"] = "👨‍👦‍👦"; - _emojiToText["👨‍👦‍👦"] = ":family_man_boy_boy:"; - _textToEmoji[":family_man_girl_girl:"] = "👨‍👧‍👧"; - _emojiToText["👨‍👧‍👧"] = ":family_man_girl_girl:"; - _textToEmoji[":knot:"] = "🪢"; - _emojiToText["🪢"] = ":knot:"; - _textToEmoji[":yarn:"] = "🧶"; - _emojiToText["🧶"] = ":yarn:"; - _textToEmoji[":thread:"] = "🧵"; - _emojiToText["🧵"] = ":thread:"; - _textToEmoji[":sewing_needle:"] = "🪡"; - _emojiToText["🪡"] = ":sewing_needle:"; - _textToEmoji[":coat:"] = "🧥"; - _emojiToText["🧥"] = ":coat:"; - _textToEmoji[":lab_coat:"] = "🥼"; - _emojiToText["🥼"] = ":lab_coat:"; - _textToEmoji[":safety_vest:"] = "🦺"; - _emojiToText["🦺"] = ":safety_vest:"; - _textToEmoji[":womans_clothes:"] = "👚"; - _emojiToText["👚"] = ":womans_clothes:"; - _textToEmoji[":shirt:"] = "👕"; - _emojiToText["👕"] = ":shirt:"; - _textToEmoji[":t_shirt:"] = "👕"; - _emojiToText["👕"] = ":t_shirt:"; - _textToEmoji[":jeans:"] = "👖"; - _emojiToText["👖"] = ":jeans:"; - _textToEmoji[":briefs:"] = "🩲"; - _emojiToText["🩲"] = ":briefs:"; - _textToEmoji[":shorts:"] = "🩳"; - _emojiToText["🩳"] = ":shorts:"; - _textToEmoji[":necktie:"] = "👔"; - _emojiToText["👔"] = ":necktie:"; - _textToEmoji[":dress:"] = "👗"; - _emojiToText["👗"] = ":dress:"; - _textToEmoji[":bikini:"] = "👙"; - _emojiToText["👙"] = ":bikini:"; - _textToEmoji[":one_piece_swimsuit:"] = "🩱"; - _emojiToText["🩱"] = ":one_piece_swimsuit:"; - _textToEmoji[":kimono:"] = "👘"; - _emojiToText["👘"] = ":kimono:"; - _textToEmoji[":sari:"] = "🥻"; - _emojiToText["🥻"] = ":sari:"; - _textToEmoji[":thong_sandal:"] = "🩴"; - _emojiToText["🩴"] = ":thong_sandal:"; - _textToEmoji[":womans_flat_shoe:"] = "🥿"; - _emojiToText["🥿"] = ":womans_flat_shoe:"; - _textToEmoji[":flat_shoe:"] = "🥿"; - _emojiToText["🥿"] = ":flat_shoe:"; - _textToEmoji[":high_heel:"] = "👠"; - _emojiToText["👠"] = ":high_heel:"; - _textToEmoji[":sandal:"] = "👡"; - _emojiToText["👡"] = ":sandal:"; - _textToEmoji[":womans_sandal:"] = "👡"; - _emojiToText["👡"] = ":womans_sandal:"; - _textToEmoji[":boot:"] = "👢"; - _emojiToText["👢"] = ":boot:"; - _textToEmoji[":womans_boot:"] = "👢"; - _emojiToText["👢"] = ":womans_boot:"; - _textToEmoji[":mans_shoe:"] = "👞"; - _emojiToText["👞"] = ":mans_shoe:"; - _textToEmoji[":athletic_shoe:"] = "👟"; - _emojiToText["👟"] = ":athletic_shoe:"; - _textToEmoji[":running_shoe:"] = "👟"; - _emojiToText["👟"] = ":running_shoe:"; - _textToEmoji[":hiking_boot:"] = "🥾"; - _emojiToText["🥾"] = ":hiking_boot:"; - _textToEmoji[":socks:"] = "🧦"; - _emojiToText["🧦"] = ":socks:"; - _textToEmoji[":gloves:"] = "🧤"; - _emojiToText["🧤"] = ":gloves:"; - _textToEmoji[":scarf:"] = "🧣"; - _emojiToText["🧣"] = ":scarf:"; - _textToEmoji[":tophat:"] = "🎩"; - _emojiToText["🎩"] = ":tophat:"; - _textToEmoji[":top_hat:"] = "🎩"; - _emojiToText["🎩"] = ":top_hat:"; - _textToEmoji[":billed_cap:"] = "🧢"; - _emojiToText["🧢"] = ":billed_cap:"; - _textToEmoji[":womans_hat:"] = "👒"; - _emojiToText["👒"] = ":womans_hat:"; - _textToEmoji[":mortar_board:"] = "🎓"; - _emojiToText["🎓"] = ":mortar_board:"; - _textToEmoji[":helmet_with_cross:"] = "⛑️"; - _emojiToText["⛑️"] = ":helmet_with_cross:"; - _textToEmoji[":helmet_with_white_cross:"] = "⛑️"; - _emojiToText["⛑️"] = ":helmet_with_white_cross:"; - _textToEmoji[":military_helmet:"] = "🪖"; - _emojiToText["🪖"] = ":military_helmet:"; - _textToEmoji[":crown:"] = "👑"; - _emojiToText["👑"] = ":crown:"; - _textToEmoji[":ring:"] = "💍"; - _emojiToText["💍"] = ":ring:"; - _textToEmoji[":pouch:"] = "👝"; - _emojiToText["👝"] = ":pouch:"; - _textToEmoji[":clutch_bag:"] = "👝"; - _emojiToText["👝"] = ":clutch_bag:"; - _textToEmoji[":purse:"] = "👛"; - _emojiToText["👛"] = ":purse:"; - _textToEmoji[":handbag:"] = "👜"; - _emojiToText["👜"] = ":handbag:"; - _textToEmoji[":briefcase:"] = "💼"; - _emojiToText["💼"] = ":briefcase:"; - _textToEmoji[":school_satchel:"] = "🎒"; - _emojiToText["🎒"] = ":school_satchel:"; - _textToEmoji[":backpack:"] = "🎒"; - _emojiToText["🎒"] = ":backpack:"; - _textToEmoji[":luggage:"] = "🧳"; - _emojiToText["🧳"] = ":luggage:"; - _textToEmoji[":eyeglasses:"] = "👓"; - _emojiToText["👓"] = ":eyeglasses:"; - _textToEmoji[":glasses:"] = "👓"; - _emojiToText["👓"] = ":glasses:"; - _textToEmoji[":dark_sunglasses:"] = "🕶️"; - _emojiToText["🕶️"] = ":dark_sunglasses:"; - _textToEmoji[":goggles:"] = "🥽"; - _emojiToText["🥽"] = ":goggles:"; - _textToEmoji[":closed_umbrella:"] = "🌂"; - _emojiToText["🌂"] = ":closed_umbrella:"; - _textToEmoji[":pink_heart:"] = "🩷"; - _emojiToText["🩷"] = ":pink_heart:"; - _textToEmoji[":heart:"] = "❤️"; - _emojiToText["❤️"] = ":heart:"; - _textToEmoji[":red_heart:"] = "❤️"; - _emojiToText["❤️"] = ":red_heart:"; - _textToEmoji[":orange_heart:"] = "🧡"; - _emojiToText["🧡"] = ":orange_heart:"; - _textToEmoji[":yellow_heart:"] = "💛"; - _emojiToText["💛"] = ":yellow_heart:"; - _textToEmoji[":green_heart:"] = "💚"; - _emojiToText["💚"] = ":green_heart:"; - _textToEmoji[":light_blue_heart:"] = "🩵"; - _emojiToText["🩵"] = ":light_blue_heart:"; - _textToEmoji[":blue_heart:"] = "💙"; - _emojiToText["💙"] = ":blue_heart:"; - _textToEmoji[":purple_heart:"] = "💜"; - _emojiToText["💜"] = ":purple_heart:"; - _textToEmoji[":black_heart:"] = "🖤"; - _emojiToText["🖤"] = ":black_heart:"; - _textToEmoji[":grey_heart:"] = "🩶"; - _emojiToText["🩶"] = ":grey_heart:"; - _textToEmoji[":white_heart:"] = "🤍"; - _emojiToText["🤍"] = ":white_heart:"; - _textToEmoji[":brown_heart:"] = "🤎"; - _emojiToText["🤎"] = ":brown_heart:"; - _textToEmoji[":broken_heart:"] = "💔"; - _emojiToText["💔"] = ":broken_heart:"; - _textToEmoji[":heart_exclamation:"] = "❣️"; - _emojiToText["❣️"] = ":heart_exclamation:"; - _textToEmoji[":heavy_heart_exclamation_mark_ornament:"] = "❣️"; - _emojiToText["❣️"] = ":heavy_heart_exclamation_mark_ornament:"; - _textToEmoji[":two_hearts:"] = "💕"; - _emojiToText["💕"] = ":two_hearts:"; - _textToEmoji[":revolving_hearts:"] = "💞"; - _emojiToText["💞"] = ":revolving_hearts:"; - _textToEmoji[":heartbeat:"] = "💓"; - _emojiToText["💓"] = ":heartbeat:"; - _textToEmoji[":beating_heart:"] = "💓"; - _emojiToText["💓"] = ":beating_heart:"; - _textToEmoji[":heartpulse:"] = "💗"; - _emojiToText["💗"] = ":heartpulse:"; - _textToEmoji[":growing_heart:"] = "💗"; - _emojiToText["💗"] = ":growing_heart:"; - _textToEmoji[":sparkling_heart:"] = "💖"; - _emojiToText["💖"] = ":sparkling_heart:"; - _textToEmoji[":cupid:"] = "💘"; - _emojiToText["💘"] = ":cupid:"; - _textToEmoji[":gift_heart:"] = "💝"; - _emojiToText["💝"] = ":gift_heart:"; - _textToEmoji[":mending_heart:"] = "❤️‍🩹"; - _emojiToText["❤️‍🩹"] = ":mending_heart:"; - _textToEmoji[":heart_on_fire:"] = "❤️‍🔥"; - _emojiToText["❤️‍🔥"] = ":heart_on_fire:"; - _textToEmoji[":heart_decoration:"] = "💟"; - _emojiToText["💟"] = ":heart_decoration:"; - _textToEmoji[":peace:"] = "☮️"; - _emojiToText["☮️"] = ":peace:"; - _textToEmoji[":peace_symbol:"] = "☮️"; - _emojiToText["☮️"] = ":peace_symbol:"; - _textToEmoji[":cross:"] = "✝️"; - _emojiToText["✝️"] = ":cross:"; - _textToEmoji[":latin_cross:"] = "✝️"; - _emojiToText["✝️"] = ":latin_cross:"; - _textToEmoji[":star_and_crescent:"] = "☪️"; - _emojiToText["☪️"] = ":star_and_crescent:"; - _textToEmoji[":om_symbol:"] = "🕉️"; - _emojiToText["🕉️"] = ":om_symbol:"; - _textToEmoji[":wheel_of_dharma:"] = "☸️"; - _emojiToText["☸️"] = ":wheel_of_dharma:"; - _textToEmoji[":khanda:"] = "🪯"; - _emojiToText["🪯"] = ":khanda:"; - _textToEmoji[":star_of_david:"] = "✡️"; - _emojiToText["✡️"] = ":star_of_david:"; - _textToEmoji[":six_pointed_star:"] = "🔯"; - _emojiToText["🔯"] = ":six_pointed_star:"; - _textToEmoji[":menorah:"] = "🕎"; - _emojiToText["🕎"] = ":menorah:"; - _textToEmoji[":yin_yang:"] = "☯️"; - _emojiToText["☯️"] = ":yin_yang:"; - _textToEmoji[":orthodox_cross:"] = "☦️"; - _emojiToText["☦️"] = ":orthodox_cross:"; - _textToEmoji[":place_of_worship:"] = "🛐"; - _emojiToText["🛐"] = ":place_of_worship:"; - _textToEmoji[":worship_symbol:"] = "🛐"; - _emojiToText["🛐"] = ":worship_symbol:"; - _textToEmoji[":ophiuchus:"] = "⛎"; - _emojiToText["⛎"] = ":ophiuchus:"; - _textToEmoji[":aries:"] = "♈"; - _emojiToText["♈"] = ":aries:"; - _textToEmoji[":taurus:"] = "♉"; - _emojiToText["♉"] = ":taurus:"; - _textToEmoji[":gemini:"] = "♊"; - _emojiToText["♊"] = ":gemini:"; - _textToEmoji[":cancer:"] = "♋"; - _emojiToText["♋"] = ":cancer:"; - _textToEmoji[":leo:"] = "♌"; - _emojiToText["♌"] = ":leo:"; - _textToEmoji[":virgo:"] = "♍"; - _emojiToText["♍"] = ":virgo:"; - _textToEmoji[":libra:"] = "♎"; - _emojiToText["♎"] = ":libra:"; - _textToEmoji[":scorpius:"] = "♏"; - _emojiToText["♏"] = ":scorpius:"; - _textToEmoji[":scorpio:"] = "♏"; - _emojiToText["♏"] = ":scorpio:"; - _textToEmoji[":sagittarius:"] = "♐"; - _emojiToText["♐"] = ":sagittarius:"; - _textToEmoji[":capricorn:"] = "♑"; - _emojiToText["♑"] = ":capricorn:"; - _textToEmoji[":aquarius:"] = "♒"; - _emojiToText["♒"] = ":aquarius:"; - _textToEmoji[":pisces:"] = "♓"; - _emojiToText["♓"] = ":pisces:"; - _textToEmoji[":id:"] = "🆔"; - _emojiToText["🆔"] = ":id:"; - _textToEmoji[":atom:"] = "⚛️"; - _emojiToText["⚛️"] = ":atom:"; - _textToEmoji[":atom_symbol:"] = "⚛️"; - _emojiToText["⚛️"] = ":atom_symbol:"; - _textToEmoji[":accept:"] = "🉑"; - _emojiToText["🉑"] = ":accept:"; - _textToEmoji[":radioactive:"] = "☢️"; - _emojiToText["☢️"] = ":radioactive:"; - _textToEmoji[":radioactive_sign:"] = "☢️"; - _emojiToText["☢️"] = ":radioactive_sign:"; - _textToEmoji[":biohazard:"] = "☣️"; - _emojiToText["☣️"] = ":biohazard:"; - _textToEmoji[":biohazard_sign:"] = "☣️"; - _emojiToText["☣️"] = ":biohazard_sign:"; - _textToEmoji[":mobile_phone_off:"] = "📴"; - _emojiToText["📴"] = ":mobile_phone_off:"; - _textToEmoji[":vibration_mode:"] = "📳"; - _emojiToText["📳"] = ":vibration_mode:"; - _textToEmoji[":u6709:"] = "🈶"; - _emojiToText["🈶"] = ":u6709:"; - _textToEmoji[":u7121:"] = "🈚"; - _emojiToText["🈚"] = ":u7121:"; - _textToEmoji[":u7533:"] = "🈸"; - _emojiToText["🈸"] = ":u7533:"; - _textToEmoji[":u55b6:"] = "🈺"; - _emojiToText["🈺"] = ":u55b6:"; - _textToEmoji[":u6708:"] = "🈷️"; - _emojiToText["🈷️"] = ":u6708:"; - _textToEmoji[":eight_pointed_black_star:"] = "✴️"; - _emojiToText["✴️"] = ":eight_pointed_black_star:"; - _textToEmoji[":vs:"] = "🆚"; - _emojiToText["🆚"] = ":vs:"; - _textToEmoji[":white_flower:"] = "💮"; - _emojiToText["💮"] = ":white_flower:"; - _textToEmoji[":ideograph_advantage:"] = "🉐"; - _emojiToText["🉐"] = ":ideograph_advantage:"; - _textToEmoji[":secret:"] = "㊙️"; - _emojiToText["㊙️"] = ":secret:"; - _textToEmoji[":congratulations:"] = "㊗️"; - _emojiToText["㊗️"] = ":congratulations:"; - _textToEmoji[":u5408:"] = "🈴"; - _emojiToText["🈴"] = ":u5408:"; - _textToEmoji[":u6e80:"] = "🈵"; - _emojiToText["🈵"] = ":u6e80:"; - _textToEmoji[":u5272:"] = "🈹"; - _emojiToText["🈹"] = ":u5272:"; - _textToEmoji[":u7981:"] = "🈲"; - _emojiToText["🈲"] = ":u7981:"; - _textToEmoji[":a:"] = "🅰️"; - _emojiToText["🅰️"] = ":a:"; - _textToEmoji[":b:"] = "🅱️"; - _emojiToText["🅱️"] = ":b:"; - _textToEmoji[":ab:"] = "🆎"; - _emojiToText["🆎"] = ":ab:"; - _textToEmoji[":cl:"] = "🆑"; - _emojiToText["🆑"] = ":cl:"; - _textToEmoji[":o2:"] = "🅾️"; - _emojiToText["🅾️"] = ":o2:"; - _textToEmoji[":sos:"] = "🆘"; - _emojiToText["🆘"] = ":sos:"; - _textToEmoji[":x:"] = "❌"; - _emojiToText["❌"] = ":x:"; - _textToEmoji[":cross_mark:"] = "❌"; - _emojiToText["❌"] = ":cross_mark:"; - _textToEmoji[":o:"] = "⭕"; - _emojiToText["⭕"] = ":o:"; - _textToEmoji[":octagonal_sign:"] = "🛑"; - _emojiToText["🛑"] = ":octagonal_sign:"; - _textToEmoji[":stop_sign:"] = "🛑"; - _emojiToText["🛑"] = ":stop_sign:"; - _textToEmoji[":no_entry:"] = "⛔"; - _emojiToText["⛔"] = ":no_entry:"; - _textToEmoji[":name_badge:"] = "📛"; - _emojiToText["📛"] = ":name_badge:"; - _textToEmoji[":no_entry_sign:"] = "🚫"; - _emojiToText["🚫"] = ":no_entry_sign:"; - _textToEmoji[":prohibited:"] = "🚫"; - _emojiToText["🚫"] = ":prohibited:"; - _textToEmoji[":anger:"] = "💢"; - _emojiToText["💢"] = ":anger:"; - _textToEmoji[":hotsprings:"] = "♨️"; - _emojiToText["♨️"] = ":hotsprings:"; - _textToEmoji[":hot_springs:"] = "♨️"; - _emojiToText["♨️"] = ":hot_springs:"; - _textToEmoji[":no_pedestrians:"] = "🚷"; - _emojiToText["🚷"] = ":no_pedestrians:"; - _textToEmoji[":do_not_litter:"] = "🚯"; - _emojiToText["🚯"] = ":do_not_litter:"; - _textToEmoji[":no_littering:"] = "🚯"; - _emojiToText["🚯"] = ":no_littering:"; - _textToEmoji[":no_bicycles:"] = "🚳"; - _emojiToText["🚳"] = ":no_bicycles:"; - _textToEmoji[":non_potable_water:"] = "🚱"; - _emojiToText["🚱"] = ":non_potable_water:"; - _textToEmoji[":underage:"] = "🔞"; - _emojiToText["🔞"] = ":underage:"; - _textToEmoji[":no_mobile_phones:"] = "📵"; - _emojiToText["📵"] = ":no_mobile_phones:"; - _textToEmoji[":no_smoking:"] = "🚭"; - _emojiToText["🚭"] = ":no_smoking:"; - _textToEmoji[":exclamation:"] = "❗"; - _emojiToText["❗"] = ":exclamation:"; - _textToEmoji[":grey_exclamation:"] = "❕"; - _emojiToText["❕"] = ":grey_exclamation:"; - _textToEmoji[":question:"] = "❓"; - _emojiToText["❓"] = ":question:"; - _textToEmoji[":question_mark:"] = "❓"; - _emojiToText["❓"] = ":question_mark:"; - _textToEmoji[":grey_question:"] = "❔"; - _emojiToText["❔"] = ":grey_question:"; - _textToEmoji[":bangbang:"] = "‼️"; - _emojiToText["‼️"] = ":bangbang:"; - _textToEmoji[":interrobang:"] = "⁉️"; - _emojiToText["⁉️"] = ":interrobang:"; - _textToEmoji[":low_brightness:"] = "🔅"; - _emojiToText["🔅"] = ":low_brightness:"; - _textToEmoji[":high_brightness:"] = "🔆"; - _emojiToText["🔆"] = ":high_brightness:"; - _textToEmoji[":part_alternation_mark:"] = "〽️"; - _emojiToText["〽️"] = ":part_alternation_mark:"; - _textToEmoji[":warning:"] = "⚠️"; - _emojiToText["⚠️"] = ":warning:"; - _textToEmoji[":children_crossing:"] = "🚸"; - _emojiToText["🚸"] = ":children_crossing:"; - _textToEmoji[":trident:"] = "🔱"; - _emojiToText["🔱"] = ":trident:"; - _textToEmoji[":fleur_de_lis:"] = "⚜️"; - _emojiToText["⚜️"] = ":fleur_de_lis:"; - _textToEmoji[":beginner:"] = "🔰"; - _emojiToText["🔰"] = ":beginner:"; - _textToEmoji[":recycle:"] = "♻️"; - _emojiToText["♻️"] = ":recycle:"; - _textToEmoji[":white_check_mark:"] = "✅"; - _emojiToText["✅"] = ":white_check_mark:"; - _textToEmoji[":u6307:"] = "🈯"; - _emojiToText["🈯"] = ":u6307:"; - _textToEmoji[":chart:"] = "💹"; - _emojiToText["💹"] = ":chart:"; - _textToEmoji[":sparkle:"] = "❇️"; - _emojiToText["❇️"] = ":sparkle:"; - _textToEmoji[":eight_spoked_asterisk:"] = "✳️"; - _emojiToText["✳️"] = ":eight_spoked_asterisk:"; - _textToEmoji[":negative_squared_cross_mark:"] = "❎"; - _emojiToText["❎"] = ":negative_squared_cross_mark:"; - _textToEmoji[":globe_with_meridians:"] = "🌐"; - _emojiToText["🌐"] = ":globe_with_meridians:"; - _textToEmoji[":diamond_shape_with_a_dot_inside:"] = "💠"; - _emojiToText["💠"] = ":diamond_shape_with_a_dot_inside:"; - _textToEmoji[":m:"] = "Ⓜ️"; - _emojiToText["Ⓜ️"] = ":m:"; - _textToEmoji[":circled_m:"] = "Ⓜ️"; - _emojiToText["Ⓜ️"] = ":circled_m:"; - _textToEmoji[":cyclone:"] = "🌀"; - _emojiToText["🌀"] = ":cyclone:"; - _textToEmoji[":zzz:"] = "💤"; - _emojiToText["💤"] = ":zzz:"; - _textToEmoji[":atm:"] = "🏧"; - _emojiToText["🏧"] = ":atm:"; - _textToEmoji[":wc:"] = "🚾"; - _emojiToText["🚾"] = ":wc:"; - _textToEmoji[":water_closet:"] = "🚾"; - _emojiToText["🚾"] = ":water_closet:"; - _textToEmoji[":wheelchair:"] = "♿"; - _emojiToText["♿"] = ":wheelchair:"; - _textToEmoji[":parking:"] = "🅿️"; - _emojiToText["🅿️"] = ":parking:"; - _textToEmoji[":elevator:"] = "🛗"; - _emojiToText["🛗"] = ":elevator:"; - _textToEmoji[":u7a7a:"] = "🈳"; - _emojiToText["🈳"] = ":u7a7a:"; - _textToEmoji[":sa:"] = "🈂️"; - _emojiToText["🈂️"] = ":sa:"; - _textToEmoji[":passport_control:"] = "🛂"; - _emojiToText["🛂"] = ":passport_control:"; - _textToEmoji[":customs:"] = "🛃"; - _emojiToText["🛃"] = ":customs:"; - _textToEmoji[":baggage_claim:"] = "🛄"; - _emojiToText["🛄"] = ":baggage_claim:"; - _textToEmoji[":left_luggage:"] = "🛅"; - _emojiToText["🛅"] = ":left_luggage:"; - _textToEmoji[":wireless:"] = "🛜"; - _emojiToText["🛜"] = ":wireless:"; - _textToEmoji[":mens:"] = "🚹"; - _emojiToText["🚹"] = ":mens:"; - _textToEmoji[":mens_room:"] = "🚹"; - _emojiToText["🚹"] = ":mens_room:"; - _textToEmoji[":womens:"] = "🚺"; - _emojiToText["🚺"] = ":womens:"; - _textToEmoji[":womens_room:"] = "🚺"; - _emojiToText["🚺"] = ":womens_room:"; - _textToEmoji[":baby_symbol:"] = "🚼"; - _emojiToText["🚼"] = ":baby_symbol:"; - _textToEmoji[":restroom:"] = "🚻"; - _emojiToText["🚻"] = ":restroom:"; - _textToEmoji[":put_litter_in_its_place:"] = "🚮"; - _emojiToText["🚮"] = ":put_litter_in_its_place:"; - _textToEmoji[":cinema:"] = "🎦"; - _emojiToText["🎦"] = ":cinema:"; - _textToEmoji[":signal_strength:"] = "📶"; - _emojiToText["📶"] = ":signal_strength:"; - _textToEmoji[":antenna_bars:"] = "📶"; - _emojiToText["📶"] = ":antenna_bars:"; - _textToEmoji[":koko:"] = "🈁"; - _emojiToText["🈁"] = ":koko:"; - _textToEmoji[":symbols:"] = "🔣"; - _emojiToText["🔣"] = ":symbols:"; - _textToEmoji[":input_symbols:"] = "🔣"; - _emojiToText["🔣"] = ":input_symbols:"; - _textToEmoji[":information_source:"] = "ℹ️"; - _emojiToText["ℹ️"] = ":information_source:"; - _textToEmoji[":information:"] = "ℹ️"; - _emojiToText["ℹ️"] = ":information:"; - _textToEmoji[":abc:"] = "🔤"; - _emojiToText["🔤"] = ":abc:"; - _textToEmoji[":abcd:"] = "🔡"; - _emojiToText["🔡"] = ":abcd:"; - _textToEmoji[":capital_abcd:"] = "🔠"; - _emojiToText["🔠"] = ":capital_abcd:"; - _textToEmoji[":ng:"] = "🆖"; - _emojiToText["🆖"] = ":ng:"; - _textToEmoji[":ok:"] = "🆗"; - _emojiToText["🆗"] = ":ok:"; - _textToEmoji[":up:"] = "🆙"; - _emojiToText["🆙"] = ":up:"; - _textToEmoji[":cool:"] = "🆒"; - _emojiToText["🆒"] = ":cool:"; - _textToEmoji[":new:"] = "🆕"; - _emojiToText["🆕"] = ":new:"; - _textToEmoji[":free:"] = "🆓"; - _emojiToText["🆓"] = ":free:"; - _textToEmoji[":zero:"] = "0️⃣"; - _emojiToText["0️⃣"] = ":zero:"; - _textToEmoji[":one:"] = "1️⃣"; - _emojiToText["1️⃣"] = ":one:"; - _textToEmoji[":two:"] = "2️⃣"; - _emojiToText["2️⃣"] = ":two:"; - _textToEmoji[":three:"] = "3️⃣"; - _emojiToText["3️⃣"] = ":three:"; - _textToEmoji[":four:"] = "4️⃣"; - _emojiToText["4️⃣"] = ":four:"; - _textToEmoji[":five:"] = "5️⃣"; - _emojiToText["5️⃣"] = ":five:"; - _textToEmoji[":six:"] = "6️⃣"; - _emojiToText["6️⃣"] = ":six:"; - _textToEmoji[":seven:"] = "7️⃣"; - _emojiToText["7️⃣"] = ":seven:"; - _textToEmoji[":eight:"] = "8️⃣"; - _emojiToText["8️⃣"] = ":eight:"; - _textToEmoji[":nine:"] = "9️⃣"; - _emojiToText["9️⃣"] = ":nine:"; - _textToEmoji[":keycap_ten:"] = "🔟"; - _emojiToText["🔟"] = ":keycap_ten:"; - _textToEmoji[":input_numbers:"] = "🔢"; - _emojiToText["🔢"] = ":input_numbers:"; - _textToEmoji[":hash:"] = "#️⃣"; - _emojiToText["#️⃣"] = ":hash:"; - _textToEmoji[":asterisk:"] = "*️⃣"; - _emojiToText["*️⃣"] = ":asterisk:"; - _textToEmoji[":keycap_asterisk:"] = "*️⃣"; - _emojiToText["*️⃣"] = ":keycap_asterisk:"; - _textToEmoji[":eject:"] = "⏏️"; - _emojiToText["⏏️"] = ":eject:"; - _textToEmoji[":eject_symbol:"] = "⏏️"; - _emojiToText["⏏️"] = ":eject_symbol:"; - _textToEmoji[":arrow_forward:"] = "▶️"; - _emojiToText["▶️"] = ":arrow_forward:"; - _textToEmoji[":pause_button:"] = "⏸️"; - _emojiToText["⏸️"] = ":pause_button:"; - _textToEmoji[":double_vertical_bar:"] = "⏸️"; - _emojiToText["⏸️"] = ":double_vertical_bar:"; - _textToEmoji[":play_pause:"] = "⏯️"; - _emojiToText["⏯️"] = ":play_pause:"; - _textToEmoji[":stop_button:"] = "⏹️"; - _emojiToText["⏹️"] = ":stop_button:"; - _textToEmoji[":record_button:"] = "⏺️"; - _emojiToText["⏺️"] = ":record_button:"; - _textToEmoji[":track_next:"] = "⏭️"; - _emojiToText["⏭️"] = ":track_next:"; - _textToEmoji[":next_track:"] = "⏭️"; - _emojiToText["⏭️"] = ":next_track:"; - _textToEmoji[":track_previous:"] = "⏮️"; - _emojiToText["⏮️"] = ":track_previous:"; - _textToEmoji[":previous_track:"] = "⏮️"; - _emojiToText["⏮️"] = ":previous_track:"; - _textToEmoji[":fast_forward:"] = "⏩"; - _emojiToText["⏩"] = ":fast_forward:"; - _textToEmoji[":rewind:"] = "⏪"; - _emojiToText["⏪"] = ":rewind:"; - _textToEmoji[":arrow_double_up:"] = "⏫"; - _emojiToText["⏫"] = ":arrow_double_up:"; - _textToEmoji[":arrow_double_down:"] = "⏬"; - _emojiToText["⏬"] = ":arrow_double_down:"; - _textToEmoji[":arrow_backward:"] = "◀️"; - _emojiToText["◀️"] = ":arrow_backward:"; - _textToEmoji[":arrow_up_small:"] = "🔼"; - _emojiToText["🔼"] = ":arrow_up_small:"; - _textToEmoji[":arrow_down_small:"] = "🔽"; - _emojiToText["🔽"] = ":arrow_down_small:"; - _textToEmoji[":arrow_right:"] = "➡️"; - _emojiToText["➡️"] = ":arrow_right:"; - _textToEmoji[":right_arrow:"] = "➡️"; - _emojiToText["➡️"] = ":right_arrow:"; - _textToEmoji[":arrow_left:"] = "⬅️"; - _emojiToText["⬅️"] = ":arrow_left:"; - _textToEmoji[":left_arrow:"] = "⬅️"; - _emojiToText["⬅️"] = ":left_arrow:"; - _textToEmoji[":arrow_up:"] = "⬆️"; - _emojiToText["⬆️"] = ":arrow_up:"; - _textToEmoji[":up_arrow:"] = "⬆️"; - _emojiToText["⬆️"] = ":up_arrow:"; - _textToEmoji[":arrow_down:"] = "⬇️"; - _emojiToText["⬇️"] = ":arrow_down:"; - _textToEmoji[":down_arrow:"] = "⬇️"; - _emojiToText["⬇️"] = ":down_arrow:"; - _textToEmoji[":arrow_upper_right:"] = "↗️"; - _emojiToText["↗️"] = ":arrow_upper_right:"; - _textToEmoji[":arrow_lower_right:"] = "↘️"; - _emojiToText["↘️"] = ":arrow_lower_right:"; - _textToEmoji[":arrow_lower_left:"] = "↙️"; - _emojiToText["↙️"] = ":arrow_lower_left:"; - _textToEmoji[":arrow_upper_left:"] = "↖️"; - _emojiToText["↖️"] = ":arrow_upper_left:"; - _textToEmoji[":up_left_arrow:"] = "↖️"; - _emojiToText["↖️"] = ":up_left_arrow:"; - _textToEmoji[":arrow_up_down:"] = "↕️"; - _emojiToText["↕️"] = ":arrow_up_down:"; - _textToEmoji[":up_down_arrow:"] = "↕️"; - _emojiToText["↕️"] = ":up_down_arrow:"; - _textToEmoji[":left_right_arrow:"] = "↔️"; - _emojiToText["↔️"] = ":left_right_arrow:"; - _textToEmoji[":arrow_right_hook:"] = "↪️"; - _emojiToText["↪️"] = ":arrow_right_hook:"; - _textToEmoji[":leftwards_arrow_with_hook:"] = "↩️"; - _emojiToText["↩️"] = ":leftwards_arrow_with_hook:"; - _textToEmoji[":arrow_heading_up:"] = "⤴️"; - _emojiToText["⤴️"] = ":arrow_heading_up:"; - _textToEmoji[":arrow_heading_down:"] = "⤵️"; - _emojiToText["⤵️"] = ":arrow_heading_down:"; - _textToEmoji[":twisted_rightwards_arrows:"] = "🔀"; - _emojiToText["🔀"] = ":twisted_rightwards_arrows:"; - _textToEmoji[":repeat:"] = "🔁"; - _emojiToText["🔁"] = ":repeat:"; - _textToEmoji[":repeat_one:"] = "🔂"; - _emojiToText["🔂"] = ":repeat_one:"; - _textToEmoji[":arrows_counterclockwise:"] = "🔄"; - _emojiToText["🔄"] = ":arrows_counterclockwise:"; - _textToEmoji[":arrows_clockwise:"] = "🔃"; - _emojiToText["🔃"] = ":arrows_clockwise:"; - _textToEmoji[":musical_note:"] = "🎵"; - _emojiToText["🎵"] = ":musical_note:"; - _textToEmoji[":notes:"] = "🎶"; - _emojiToText["🎶"] = ":notes:"; - _textToEmoji[":musical_notes:"] = "🎶"; - _emojiToText["🎶"] = ":musical_notes:"; - _textToEmoji[":heavy_plus_sign:"] = "➕"; - _emojiToText["➕"] = ":heavy_plus_sign:"; - _textToEmoji[":heavy_minus_sign:"] = "➖"; - _emojiToText["➖"] = ":heavy_minus_sign:"; - _textToEmoji[":heavy_division_sign:"] = "➗"; - _emojiToText["➗"] = ":heavy_division_sign:"; - _textToEmoji[":heavy_multiplication_x:"] = "✖️"; - _emojiToText["✖️"] = ":heavy_multiplication_x:"; - _textToEmoji[":heavy_equals_sign:"] = "🟰"; - _emojiToText["🟰"] = ":heavy_equals_sign:"; - _textToEmoji[":infinity:"] = "♾️"; - _emojiToText["♾️"] = ":infinity:"; - _textToEmoji[":heavy_dollar_sign:"] = "💲"; - _emojiToText["💲"] = ":heavy_dollar_sign:"; - _textToEmoji[":currency_exchange:"] = "💱"; - _emojiToText["💱"] = ":currency_exchange:"; - _textToEmoji[":tm:"] = "™️"; - _emojiToText["™️"] = ":tm:"; - _textToEmoji[":trade_mark:"] = "™️"; - _emojiToText["™️"] = ":trade_mark:"; - _textToEmoji[":copyright:"] = "©️"; - _emojiToText["©️"] = ":copyright:"; - _textToEmoji[":registered:"] = "®️"; - _emojiToText["®️"] = ":registered:"; - _textToEmoji[":wavy_dash:"] = "〰️"; - _emojiToText["〰️"] = ":wavy_dash:"; - _textToEmoji[":curly_loop:"] = "➰"; - _emojiToText["➰"] = ":curly_loop:"; - _textToEmoji[":loop:"] = "➿"; - _emojiToText["➿"] = ":loop:"; - _textToEmoji[":end:"] = "🔚"; - _emojiToText["🔚"] = ":end:"; - _textToEmoji[":end_arrow:"] = "🔚"; - _emojiToText["🔚"] = ":end_arrow:"; - _textToEmoji[":back:"] = "🔙"; - _emojiToText["🔙"] = ":back:"; - _textToEmoji[":back_arrow:"] = "🔙"; - _emojiToText["🔙"] = ":back_arrow:"; - _textToEmoji[":on:"] = "🔛"; - _emojiToText["🔛"] = ":on:"; - _textToEmoji[":on_arrow:"] = "🔛"; - _emojiToText["🔛"] = ":on_arrow:"; - _textToEmoji[":top:"] = "🔝"; - _emojiToText["🔝"] = ":top:"; - _textToEmoji[":top_arrow:"] = "🔝"; - _emojiToText["🔝"] = ":top_arrow:"; - _textToEmoji[":soon:"] = "🔜"; - _emojiToText["🔜"] = ":soon:"; - _textToEmoji[":soon_arrow:"] = "🔜"; - _emojiToText["🔜"] = ":soon_arrow:"; - _textToEmoji[":heavy_check_mark:"] = "✔️"; - _emojiToText["✔️"] = ":heavy_check_mark:"; - _textToEmoji[":check_mark:"] = "✔️"; - _emojiToText["✔️"] = ":check_mark:"; - _textToEmoji[":ballot_box_with_check:"] = "☑️"; - _emojiToText["☑️"] = ":ballot_box_with_check:"; - _textToEmoji[":radio_button:"] = "🔘"; - _emojiToText["🔘"] = ":radio_button:"; - _textToEmoji[":white_circle:"] = "⚪"; - _emojiToText["⚪"] = ":white_circle:"; - _textToEmoji[":black_circle:"] = "⚫"; - _emojiToText["⚫"] = ":black_circle:"; - _textToEmoji[":red_circle:"] = "🔴"; - _emojiToText["🔴"] = ":red_circle:"; - _textToEmoji[":blue_circle:"] = "🔵"; - _emojiToText["🔵"] = ":blue_circle:"; - _textToEmoji[":brown_circle:"] = "🟤"; - _emojiToText["🟤"] = ":brown_circle:"; - _textToEmoji[":purple_circle:"] = "🟣"; - _emojiToText["🟣"] = ":purple_circle:"; - _textToEmoji[":green_circle:"] = "🟢"; - _emojiToText["🟢"] = ":green_circle:"; - _textToEmoji[":yellow_circle:"] = "🟡"; - _emojiToText["🟡"] = ":yellow_circle:"; - _textToEmoji[":orange_circle:"] = "🟠"; - _emojiToText["🟠"] = ":orange_circle:"; - _textToEmoji[":small_red_triangle:"] = "🔺"; - _emojiToText["🔺"] = ":small_red_triangle:"; - _textToEmoji[":small_red_triangle_down:"] = "🔻"; - _emojiToText["🔻"] = ":small_red_triangle_down:"; - _textToEmoji[":small_orange_diamond:"] = "🔸"; - _emojiToText["🔸"] = ":small_orange_diamond:"; - _textToEmoji[":small_blue_diamond:"] = "🔹"; - _emojiToText["🔹"] = ":small_blue_diamond:"; - _textToEmoji[":large_orange_diamond:"] = "🔶"; - _emojiToText["🔶"] = ":large_orange_diamond:"; - _textToEmoji[":large_blue_diamond:"] = "🔷"; - _emojiToText["🔷"] = ":large_blue_diamond:"; - _textToEmoji[":white_square_button:"] = "🔳"; - _emojiToText["🔳"] = ":white_square_button:"; - _textToEmoji[":black_square_button:"] = "🔲"; - _emojiToText["🔲"] = ":black_square_button:"; - _textToEmoji[":black_small_square:"] = "▪️"; - _emojiToText["▪️"] = ":black_small_square:"; - _textToEmoji[":white_small_square:"] = "▫️"; - _emojiToText["▫️"] = ":white_small_square:"; - _textToEmoji[":black_medium_small_square:"] = "◾"; - _emojiToText["◾"] = ":black_medium_small_square:"; - _textToEmoji[":white_medium_small_square:"] = "◽"; - _emojiToText["◽"] = ":white_medium_small_square:"; - _textToEmoji[":black_medium_square:"] = "◼️"; - _emojiToText["◼️"] = ":black_medium_square:"; - _textToEmoji[":white_medium_square:"] = "◻️"; - _emojiToText["◻️"] = ":white_medium_square:"; - _textToEmoji[":black_large_square:"] = "⬛"; - _emojiToText["⬛"] = ":black_large_square:"; - _textToEmoji[":white_large_square:"] = "⬜"; - _emojiToText["⬜"] = ":white_large_square:"; - _textToEmoji[":orange_square:"] = "🟧"; - _emojiToText["🟧"] = ":orange_square:"; - _textToEmoji[":blue_square:"] = "🟦"; - _emojiToText["🟦"] = ":blue_square:"; - _textToEmoji[":red_square:"] = "🟥"; - _emojiToText["🟥"] = ":red_square:"; - _textToEmoji[":brown_square:"] = "🟫"; - _emojiToText["🟫"] = ":brown_square:"; - _textToEmoji[":purple_square:"] = "🟪"; - _emojiToText["🟪"] = ":purple_square:"; - _textToEmoji[":green_square:"] = "🟩"; - _emojiToText["🟩"] = ":green_square:"; - _textToEmoji[":yellow_square:"] = "🟨"; - _emojiToText["🟨"] = ":yellow_square:"; - _textToEmoji[":speaker:"] = "🔈"; - _emojiToText["🔈"] = ":speaker:"; - _textToEmoji[":mute:"] = "🔇"; - _emojiToText["🔇"] = ":mute:"; - _textToEmoji[":muted_speaker:"] = "🔇"; - _emojiToText["🔇"] = ":muted_speaker:"; - _textToEmoji[":sound:"] = "🔉"; - _emojiToText["🔉"] = ":sound:"; - _textToEmoji[":loud_sound:"] = "🔊"; - _emojiToText["🔊"] = ":loud_sound:"; - _textToEmoji[":bell:"] = "🔔"; - _emojiToText["🔔"] = ":bell:"; - _textToEmoji[":no_bell:"] = "🔕"; - _emojiToText["🔕"] = ":no_bell:"; - _textToEmoji[":mega:"] = "📣"; - _emojiToText["📣"] = ":mega:"; - _textToEmoji[":megaphone:"] = "📣"; - _emojiToText["📣"] = ":megaphone:"; - _textToEmoji[":loudspeaker:"] = "📢"; - _emojiToText["📢"] = ":loudspeaker:"; - _textToEmoji[":speech_left:"] = "🗨️"; - _emojiToText["🗨️"] = ":speech_left:"; - _textToEmoji[":left_speech_bubble:"] = "🗨️"; - _emojiToText["🗨️"] = ":left_speech_bubble:"; - _textToEmoji[":eye_in_speech_bubble:"] = "👁‍🗨"; - _emojiToText["👁‍🗨"] = ":eye_in_speech_bubble:"; - _textToEmoji[":speech_balloon:"] = "💬"; - _emojiToText["💬"] = ":speech_balloon:"; - _textToEmoji[":thought_balloon:"] = "💭"; - _emojiToText["💭"] = ":thought_balloon:"; - _textToEmoji[":anger_right:"] = "🗯️"; - _emojiToText["🗯️"] = ":anger_right:"; - _textToEmoji[":right_anger_bubble:"] = "🗯️"; - _emojiToText["🗯️"] = ":right_anger_bubble:"; - _textToEmoji[":spades:"] = "♠️"; - _emojiToText["♠️"] = ":spades:"; - _textToEmoji[":spade_suit:"] = "♠️"; - _emojiToText["♠️"] = ":spade_suit:"; - _textToEmoji[":clubs:"] = "♣️"; - _emojiToText["♣️"] = ":clubs:"; - _textToEmoji[":club_suit:"] = "♣️"; - _emojiToText["♣️"] = ":club_suit:"; - _textToEmoji[":hearts:"] = "♥️"; - _emojiToText["♥️"] = ":hearts:"; - _textToEmoji[":heart_suit:"] = "♥️"; - _emojiToText["♥️"] = ":heart_suit:"; - _textToEmoji[":diamonds:"] = "♦️"; - _emojiToText["♦️"] = ":diamonds:"; - _textToEmoji[":diamond_suit:"] = "♦️"; - _emojiToText["♦️"] = ":diamond_suit:"; - _textToEmoji[":black_joker:"] = "🃏"; - _emojiToText["🃏"] = ":black_joker:"; - _textToEmoji[":joker:"] = "🃏"; - _emojiToText["🃏"] = ":joker:"; - _textToEmoji[":flower_playing_cards:"] = "🎴"; - _emojiToText["🎴"] = ":flower_playing_cards:"; - _textToEmoji[":mahjong:"] = "🀄"; - _emojiToText["🀄"] = ":mahjong:"; - _textToEmoji[":clock1:"] = "🕐"; - _emojiToText["🕐"] = ":clock1:"; - _textToEmoji[":one_oclock:"] = "🕐"; - _emojiToText["🕐"] = ":one_oclock:"; - _textToEmoji[":clock2:"] = "🕑"; - _emojiToText["🕑"] = ":clock2:"; - _textToEmoji[":two_oclock:"] = "🕑"; - _emojiToText["🕑"] = ":two_oclock:"; - _textToEmoji[":clock3:"] = "🕒"; - _emojiToText["🕒"] = ":clock3:"; - _textToEmoji[":three_oclock:"] = "🕒"; - _emojiToText["🕒"] = ":three_oclock:"; - _textToEmoji[":clock4:"] = "🕓"; - _emojiToText["🕓"] = ":clock4:"; - _textToEmoji[":four_oclock:"] = "🕓"; - _emojiToText["🕓"] = ":four_oclock:"; - _textToEmoji[":clock5:"] = "🕔"; - _emojiToText["🕔"] = ":clock5:"; - _textToEmoji[":five_oclock:"] = "🕔"; - _emojiToText["🕔"] = ":five_oclock:"; - _textToEmoji[":clock6:"] = "🕕"; - _emojiToText["🕕"] = ":clock6:"; - _textToEmoji[":six_oclock:"] = "🕕"; - _emojiToText["🕕"] = ":six_oclock:"; - _textToEmoji[":clock7:"] = "🕖"; - _emojiToText["🕖"] = ":clock7:"; - _textToEmoji[":seven_oclock:"] = "🕖"; - _emojiToText["🕖"] = ":seven_oclock:"; - _textToEmoji[":clock8:"] = "🕗"; - _emojiToText["🕗"] = ":clock8:"; - _textToEmoji[":eight_oclock:"] = "🕗"; - _emojiToText["🕗"] = ":eight_oclock:"; - _textToEmoji[":clock9:"] = "🕘"; - _emojiToText["🕘"] = ":clock9:"; - _textToEmoji[":nine_oclock:"] = "🕘"; - _emojiToText["🕘"] = ":nine_oclock:"; - _textToEmoji[":clock10:"] = "🕙"; - _emojiToText["🕙"] = ":clock10:"; - _textToEmoji[":ten_oclock:"] = "🕙"; - _emojiToText["🕙"] = ":ten_oclock:"; - _textToEmoji[":clock11:"] = "🕚"; - _emojiToText["🕚"] = ":clock11:"; - _textToEmoji[":eleven_oclock:"] = "🕚"; - _emojiToText["🕚"] = ":eleven_oclock:"; - _textToEmoji[":clock12:"] = "🕛"; - _emojiToText["🕛"] = ":clock12:"; - _textToEmoji[":twelve_oclock:"] = "🕛"; - _emojiToText["🕛"] = ":twelve_oclock:"; - _textToEmoji[":clock130:"] = "🕜"; - _emojiToText["🕜"] = ":clock130:"; - _textToEmoji[":one_thirty:"] = "🕜"; - _emojiToText["🕜"] = ":one_thirty:"; - _textToEmoji[":clock230:"] = "🕝"; - _emojiToText["🕝"] = ":clock230:"; - _textToEmoji[":two_thirty:"] = "🕝"; - _emojiToText["🕝"] = ":two_thirty:"; - _textToEmoji[":clock330:"] = "🕞"; - _emojiToText["🕞"] = ":clock330:"; - _textToEmoji[":three_thirty:"] = "🕞"; - _emojiToText["🕞"] = ":three_thirty:"; - _textToEmoji[":clock430:"] = "🕟"; - _emojiToText["🕟"] = ":clock430:"; - _textToEmoji[":four_thirty:"] = "🕟"; - _emojiToText["🕟"] = ":four_thirty:"; - _textToEmoji[":clock530:"] = "🕠"; - _emojiToText["🕠"] = ":clock530:"; - _textToEmoji[":five_thirty:"] = "🕠"; - _emojiToText["🕠"] = ":five_thirty:"; - _textToEmoji[":clock630:"] = "🕡"; - _emojiToText["🕡"] = ":clock630:"; - _textToEmoji[":six_thirty:"] = "🕡"; - _emojiToText["🕡"] = ":six_thirty:"; - _textToEmoji[":clock730:"] = "🕢"; - _emojiToText["🕢"] = ":clock730:"; - _textToEmoji[":seven_thirty:"] = "🕢"; - _emojiToText["🕢"] = ":seven_thirty:"; - _textToEmoji[":clock830:"] = "🕣"; - _emojiToText["🕣"] = ":clock830:"; - _textToEmoji[":eight_thirty:"] = "🕣"; - _emojiToText["🕣"] = ":eight_thirty:"; - _textToEmoji[":clock930:"] = "🕤"; - _emojiToText["🕤"] = ":clock930:"; - _textToEmoji[":nine_thirty:"] = "🕤"; - _emojiToText["🕤"] = ":nine_thirty:"; - _textToEmoji[":clock1030:"] = "🕥"; - _emojiToText["🕥"] = ":clock1030:"; - _textToEmoji[":ten_thirty:"] = "🕥"; - _emojiToText["🕥"] = ":ten_thirty:"; - _textToEmoji[":clock1130:"] = "🕦"; - _emojiToText["🕦"] = ":clock1130:"; - _textToEmoji[":eleven_thirty:"] = "🕦"; - _emojiToText["🕦"] = ":eleven_thirty:"; - _textToEmoji[":clock1230:"] = "🕧"; - _emojiToText["🕧"] = ":clock1230:"; - _textToEmoji[":twelve_thirty:"] = "🕧"; - _emojiToText["🕧"] = ":twelve_thirty:"; - _textToEmoji[":female_sign:"] = "♀️"; - _emojiToText["♀️"] = ":female_sign:"; - _textToEmoji[":male_sign:"] = "♂️"; - _emojiToText["♂️"] = ":male_sign:"; - _textToEmoji[":transgender_symbol:"] = "⚧"; - _emojiToText["⚧"] = ":transgender_symbol:"; - _textToEmoji[":medical_symbol:"] = "⚕️"; - _emojiToText["⚕️"] = ":medical_symbol:"; - _textToEmoji[":regional_indicator_z:"] = "🇿"; - _emojiToText["🇿"] = ":regional_indicator_z:"; - _textToEmoji[":regional_indicator_y:"] = "🇾"; - _emojiToText["🇾"] = ":regional_indicator_y:"; - _textToEmoji[":regional_indicator_x:"] = "🇽"; - _emojiToText["🇽"] = ":regional_indicator_x:"; - _textToEmoji[":regional_indicator_w:"] = "🇼"; - _emojiToText["🇼"] = ":regional_indicator_w:"; - _textToEmoji[":regional_indicator_v:"] = "🇻"; - _emojiToText["🇻"] = ":regional_indicator_v:"; - _textToEmoji[":regional_indicator_u:"] = "🇺"; - _emojiToText["🇺"] = ":regional_indicator_u:"; - _textToEmoji[":regional_indicator_t:"] = "🇹"; - _emojiToText["🇹"] = ":regional_indicator_t:"; - _textToEmoji[":regional_indicator_s:"] = "🇸"; - _emojiToText["🇸"] = ":regional_indicator_s:"; - _textToEmoji[":regional_indicator_r:"] = "🇷"; - _emojiToText["🇷"] = ":regional_indicator_r:"; - _textToEmoji[":regional_indicator_q:"] = "🇶"; - _emojiToText["🇶"] = ":regional_indicator_q:"; - _textToEmoji[":regional_indicator_p:"] = "🇵"; - _emojiToText["🇵"] = ":regional_indicator_p:"; - _textToEmoji[":regional_indicator_o:"] = "🇴"; - _emojiToText["🇴"] = ":regional_indicator_o:"; - _textToEmoji[":regional_indicator_n:"] = "🇳"; - _emojiToText["🇳"] = ":regional_indicator_n:"; - _textToEmoji[":regional_indicator_m:"] = "🇲"; - _emojiToText["🇲"] = ":regional_indicator_m:"; - _textToEmoji[":regional_indicator_l:"] = "🇱"; - _emojiToText["🇱"] = ":regional_indicator_l:"; - _textToEmoji[":regional_indicator_k:"] = "🇰"; - _emojiToText["🇰"] = ":regional_indicator_k:"; - _textToEmoji[":regional_indicator_j:"] = "🇯"; - _emojiToText["🇯"] = ":regional_indicator_j:"; - _textToEmoji[":regional_indicator_i:"] = "🇮"; - _emojiToText["🇮"] = ":regional_indicator_i:"; - _textToEmoji[":regional_indicator_h:"] = "🇭"; - _emojiToText["🇭"] = ":regional_indicator_h:"; - _textToEmoji[":regional_indicator_g:"] = "🇬"; - _emojiToText["🇬"] = ":regional_indicator_g:"; - _textToEmoji[":regional_indicator_f:"] = "🇫"; - _emojiToText["🇫"] = ":regional_indicator_f:"; - _textToEmoji[":regional_indicator_e:"] = "🇪"; - _emojiToText["🇪"] = ":regional_indicator_e:"; - _textToEmoji[":regional_indicator_d:"] = "🇩"; - _emojiToText["🇩"] = ":regional_indicator_d:"; - _textToEmoji[":regional_indicator_c:"] = "🇨"; - _emojiToText["🇨"] = ":regional_indicator_c:"; - _textToEmoji[":regional_indicator_b:"] = "🇧"; - _emojiToText["🇧"] = ":regional_indicator_b:"; - _textToEmoji[":regional_indicator_a:"] = "🇦"; - _emojiToText["🇦"] = ":regional_indicator_a:"; - _textToEmoji[":red_car:"] = "🚗"; - _emojiToText["🚗"] = ":red_car:"; - _textToEmoji[":automobile:"] = "🚗"; - _emojiToText["🚗"] = ":automobile:"; - _textToEmoji[":taxi:"] = "🚕"; - _emojiToText["🚕"] = ":taxi:"; - _textToEmoji[":blue_car:"] = "🚙"; - _emojiToText["🚙"] = ":blue_car:"; - _textToEmoji[":pickup_truck:"] = "🛻"; - _emojiToText["🛻"] = ":pickup_truck:"; - _textToEmoji[":minibus:"] = "🚐"; - _emojiToText["🚐"] = ":minibus:"; - _textToEmoji[":bus:"] = "🚌"; - _emojiToText["🚌"] = ":bus:"; - _textToEmoji[":trolleybus:"] = "🚎"; - _emojiToText["🚎"] = ":trolleybus:"; - _textToEmoji[":race_car:"] = "🏎️"; - _emojiToText["🏎️"] = ":race_car:"; - _textToEmoji[":racing_car:"] = "🏎️"; - _emojiToText["🏎️"] = ":racing_car:"; - _textToEmoji[":police_car:"] = "🚓"; - _emojiToText["🚓"] = ":police_car:"; - _textToEmoji[":ambulance:"] = "🚑"; - _emojiToText["🚑"] = ":ambulance:"; - _textToEmoji[":fire_engine:"] = "🚒"; - _emojiToText["🚒"] = ":fire_engine:"; - _textToEmoji[":truck:"] = "🚚"; - _emojiToText["🚚"] = ":truck:"; - _textToEmoji[":articulated_lorry:"] = "🚛"; - _emojiToText["🚛"] = ":articulated_lorry:"; - _textToEmoji[":tractor:"] = "🚜"; - _emojiToText["🚜"] = ":tractor:"; - _textToEmoji[":probing_cane:"] = "🦯"; - _emojiToText["🦯"] = ":probing_cane:"; - _textToEmoji[":manual_wheelchair:"] = "🦽"; - _emojiToText["🦽"] = ":manual_wheelchair:"; - _textToEmoji[":motorized_wheelchair:"] = "🦼"; - _emojiToText["🦼"] = ":motorized_wheelchair:"; - _textToEmoji[":crutch:"] = "🩼"; - _emojiToText["🩼"] = ":crutch:"; - _textToEmoji[":scooter:"] = "🛴"; - _emojiToText["🛴"] = ":scooter:"; - _textToEmoji[":kick_scooter:"] = "🛴"; - _emojiToText["🛴"] = ":kick_scooter:"; - _textToEmoji[":bike:"] = "🚲"; - _emojiToText["🚲"] = ":bike:"; - _textToEmoji[":bicycle:"] = "🚲"; - _emojiToText["🚲"] = ":bicycle:"; - _textToEmoji[":motor_scooter:"] = "🛵"; - _emojiToText["🛵"] = ":motor_scooter:"; - _textToEmoji[":motorbike:"] = "🛵"; - _emojiToText["🛵"] = ":motorbike:"; - _textToEmoji[":motorcycle:"] = "🏍️"; - _emojiToText["🏍️"] = ":motorcycle:"; - _textToEmoji[":racing_motorcycle:"] = "🏍️"; - _emojiToText["🏍️"] = ":racing_motorcycle:"; - _textToEmoji[":auto_rickshaw:"] = "🛺"; - _emojiToText["🛺"] = ":auto_rickshaw:"; - _textToEmoji[":wheel:"] = "🛞"; - _emojiToText["🛞"] = ":wheel:"; - _textToEmoji[":rotating_light:"] = "🚨"; - _emojiToText["🚨"] = ":rotating_light:"; - _textToEmoji[":oncoming_police_car:"] = "🚔"; - _emojiToText["🚔"] = ":oncoming_police_car:"; - _textToEmoji[":oncoming_bus:"] = "🚍"; - _emojiToText["🚍"] = ":oncoming_bus:"; - _textToEmoji[":oncoming_automobile:"] = "🚘"; - _emojiToText["🚘"] = ":oncoming_automobile:"; - _textToEmoji[":oncoming_taxi:"] = "🚖"; - _emojiToText["🚖"] = ":oncoming_taxi:"; - _textToEmoji[":aerial_tramway:"] = "🚡"; - _emojiToText["🚡"] = ":aerial_tramway:"; - _textToEmoji[":mountain_cableway:"] = "🚠"; - _emojiToText["🚠"] = ":mountain_cableway:"; - _textToEmoji[":suspension_railway:"] = "🚟"; - _emojiToText["🚟"] = ":suspension_railway:"; - _textToEmoji[":railway_car:"] = "🚃"; - _emojiToText["🚃"] = ":railway_car:"; - _textToEmoji[":train:"] = "🚋"; - _emojiToText["🚋"] = ":train:"; - _textToEmoji[":tram_car:"] = "🚋"; - _emojiToText["🚋"] = ":tram_car:"; - _textToEmoji[":mountain_railway:"] = "🚞"; - _emojiToText["🚞"] = ":mountain_railway:"; - _textToEmoji[":monorail:"] = "🚝"; - _emojiToText["🚝"] = ":monorail:"; - _textToEmoji[":bullettrain_side:"] = "🚄"; - _emojiToText["🚄"] = ":bullettrain_side:"; - _textToEmoji[":bullettrain_front:"] = "🚅"; - _emojiToText["🚅"] = ":bullettrain_front:"; - _textToEmoji[":bullet_train:"] = "🚅"; - _emojiToText["🚅"] = ":bullet_train:"; - _textToEmoji[":light_rail:"] = "🚈"; - _emojiToText["🚈"] = ":light_rail:"; - _textToEmoji[":steam_locomotive:"] = "🚂"; - _emojiToText["🚂"] = ":steam_locomotive:"; - _textToEmoji[":locomotive:"] = "🚂"; - _emojiToText["🚂"] = ":locomotive:"; - _textToEmoji[":train2:"] = "🚆"; - _emojiToText["🚆"] = ":train2:"; - _textToEmoji[":metro:"] = "🚇"; - _emojiToText["🚇"] = ":metro:"; - _textToEmoji[":tram:"] = "🚊"; - _emojiToText["🚊"] = ":tram:"; - _textToEmoji[":station:"] = "🚉"; - _emojiToText["🚉"] = ":station:"; - _textToEmoji[":airplane:"] = "✈️"; - _emojiToText["✈️"] = ":airplane:"; - _textToEmoji[":airplane_departure:"] = "🛫"; - _emojiToText["🛫"] = ":airplane_departure:"; - _textToEmoji[":airplane_arriving:"] = "🛬"; - _emojiToText["🛬"] = ":airplane_arriving:"; - _textToEmoji[":airplane_small:"] = "🛩️"; - _emojiToText["🛩️"] = ":airplane_small:"; - _textToEmoji[":small_airplane:"] = "🛩️"; - _emojiToText["🛩️"] = ":small_airplane:"; - _textToEmoji[":seat:"] = "💺"; - _emojiToText["💺"] = ":seat:"; - _textToEmoji[":satellite_orbital:"] = "🛰️"; - _emojiToText["🛰️"] = ":satellite_orbital:"; - _textToEmoji[":rocket:"] = "🚀"; - _emojiToText["🚀"] = ":rocket:"; - _textToEmoji[":flying_saucer:"] = "🛸"; - _emojiToText["🛸"] = ":flying_saucer:"; - _textToEmoji[":helicopter:"] = "🚁"; - _emojiToText["🚁"] = ":helicopter:"; - _textToEmoji[":canoe:"] = "🛶"; - _emojiToText["🛶"] = ":canoe:"; - _textToEmoji[":kayak:"] = "🛶"; - _emojiToText["🛶"] = ":kayak:"; - _textToEmoji[":sailboat:"] = "⛵"; - _emojiToText["⛵"] = ":sailboat:"; - _textToEmoji[":speedboat:"] = "🚤"; - _emojiToText["🚤"] = ":speedboat:"; - _textToEmoji[":motorboat:"] = "🛥️"; - _emojiToText["🛥️"] = ":motorboat:"; - _textToEmoji[":motor_boat:"] = "🛥️"; - _emojiToText["🛥️"] = ":motor_boat:"; - _textToEmoji[":cruise_ship:"] = "🛳️"; - _emojiToText["🛳️"] = ":cruise_ship:"; - _textToEmoji[":passenger_ship:"] = "🛳️"; - _emojiToText["🛳️"] = ":passenger_ship:"; - _textToEmoji[":ferry:"] = "⛴️"; - _emojiToText["⛴️"] = ":ferry:"; - _textToEmoji[":ship:"] = "🚢"; - _emojiToText["🚢"] = ":ship:"; - _textToEmoji[":ring_buoy:"] = "🛟"; - _emojiToText["🛟"] = ":ring_buoy:"; - _textToEmoji[":anchor:"] = "⚓"; - _emojiToText["⚓"] = ":anchor:"; - _textToEmoji[":hook:"] = "🪝"; - _emojiToText["🪝"] = ":hook:"; - _textToEmoji[":fuelpump:"] = "⛽"; - _emojiToText["⛽"] = ":fuelpump:"; - _textToEmoji[":fuel_pump:"] = "⛽"; - _emojiToText["⛽"] = ":fuel_pump:"; - _textToEmoji[":construction:"] = "🚧"; - _emojiToText["🚧"] = ":construction:"; - _textToEmoji[":vertical_traffic_light:"] = "🚦"; - _emojiToText["🚦"] = ":vertical_traffic_light:"; - _textToEmoji[":traffic_light:"] = "🚥"; - _emojiToText["🚥"] = ":traffic_light:"; - _textToEmoji[":busstop:"] = "🚏"; - _emojiToText["🚏"] = ":busstop:"; - _textToEmoji[":bus_stop:"] = "🚏"; - _emojiToText["🚏"] = ":bus_stop:"; - _textToEmoji[":map:"] = "🗺️"; - _emojiToText["🗺️"] = ":map:"; - _textToEmoji[":world_map:"] = "🗺️"; - _emojiToText["🗺️"] = ":world_map:"; - _textToEmoji[":moyai:"] = "🗿"; - _emojiToText["🗿"] = ":moyai:"; - _textToEmoji[":moai:"] = "🗿"; - _emojiToText["🗿"] = ":moai:"; - _textToEmoji[":statue_of_liberty:"] = "🗽"; - _emojiToText["🗽"] = ":statue_of_liberty:"; - _textToEmoji[":tokyo_tower:"] = "🗼"; - _emojiToText["🗼"] = ":tokyo_tower:"; - _textToEmoji[":european_castle:"] = "🏰"; - _emojiToText["🏰"] = ":european_castle:"; - _textToEmoji[":castle:"] = "🏰"; - _emojiToText["🏰"] = ":castle:"; - _textToEmoji[":japanese_castle:"] = "🏯"; - _emojiToText["🏯"] = ":japanese_castle:"; - _textToEmoji[":stadium:"] = "🏟️"; - _emojiToText["🏟️"] = ":stadium:"; - _textToEmoji[":ferris_wheel:"] = "🎡"; - _emojiToText["🎡"] = ":ferris_wheel:"; - _textToEmoji[":roller_coaster:"] = "🎢"; - _emojiToText["🎢"] = ":roller_coaster:"; - _textToEmoji[":carousel_horse:"] = "🎠"; - _emojiToText["🎠"] = ":carousel_horse:"; - _textToEmoji[":fountain:"] = "⛲"; - _emojiToText["⛲"] = ":fountain:"; - _textToEmoji[":beach_umbrella:"] = "⛱️"; - _emojiToText["⛱️"] = ":beach_umbrella:"; - _textToEmoji[":umbrella_on_ground:"] = "⛱️"; - _emojiToText["⛱️"] = ":umbrella_on_ground:"; - _textToEmoji[":beach:"] = "🏖️"; - _emojiToText["🏖️"] = ":beach:"; - _textToEmoji[":beach_with_umbrella:"] = "🏖️"; - _emojiToText["🏖️"] = ":beach_with_umbrella:"; - _textToEmoji[":island:"] = "🏝️"; - _emojiToText["🏝️"] = ":island:"; - _textToEmoji[":desert_island:"] = "🏝️"; - _emojiToText["🏝️"] = ":desert_island:"; - _textToEmoji[":desert:"] = "🏜️"; - _emojiToText["🏜️"] = ":desert:"; - _textToEmoji[":volcano:"] = "🌋"; - _emojiToText["🌋"] = ":volcano:"; - _textToEmoji[":mountain:"] = "⛰️"; - _emojiToText["⛰️"] = ":mountain:"; - _textToEmoji[":mountain_snow:"] = "🏔️"; - _emojiToText["🏔️"] = ":mountain_snow:"; - _textToEmoji[":snow_capped_mountain:"] = "🏔️"; - _emojiToText["🏔️"] = ":snow_capped_mountain:"; - _textToEmoji[":mount_fuji:"] = "🗻"; - _emojiToText["🗻"] = ":mount_fuji:"; - _textToEmoji[":camping:"] = "🏕️"; - _emojiToText["🏕️"] = ":camping:"; - _textToEmoji[":tent:"] = "⛺"; - _emojiToText["⛺"] = ":tent:"; - _textToEmoji[":house:"] = "🏠"; - _emojiToText["🏠"] = ":house:"; - _textToEmoji[":house_with_garden:"] = "🏡"; - _emojiToText["🏡"] = ":house_with_garden:"; - _textToEmoji[":homes:"] = "🏘️"; - _emojiToText["🏘️"] = ":homes:"; - _textToEmoji[":house_buildings:"] = "🏘️"; - _emojiToText["🏘️"] = ":house_buildings:"; - _textToEmoji[":houses:"] = "🏘️"; - _emojiToText["🏘️"] = ":houses:"; - _textToEmoji[":house_abandoned:"] = "🏚️"; - _emojiToText["🏚️"] = ":house_abandoned:"; - _textToEmoji[":derelict_house_building:"] = "🏚️"; - _emojiToText["🏚️"] = ":derelict_house_building:"; - _textToEmoji[":hut:"] = "🛖"; - _emojiToText["🛖"] = ":hut:"; - _textToEmoji[":construction_site:"] = "🏗️"; - _emojiToText["🏗️"] = ":construction_site:"; - _textToEmoji[":building_construction:"] = "🏗️"; - _emojiToText["🏗️"] = ":building_construction:"; - _textToEmoji[":factory:"] = "🏭"; - _emojiToText["🏭"] = ":factory:"; - _textToEmoji[":office:"] = "🏢"; - _emojiToText["🏢"] = ":office:"; - _textToEmoji[":department_store:"] = "🏬"; - _emojiToText["🏬"] = ":department_store:"; - _textToEmoji[":post_office:"] = "🏣"; - _emojiToText["🏣"] = ":post_office:"; - _textToEmoji[":european_post_office:"] = "🏤"; - _emojiToText["🏤"] = ":european_post_office:"; - _textToEmoji[":hospital:"] = "🏥"; - _emojiToText["🏥"] = ":hospital:"; - _textToEmoji[":bank:"] = "🏦"; - _emojiToText["🏦"] = ":bank:"; - _textToEmoji[":hotel:"] = "🏨"; - _emojiToText["🏨"] = ":hotel:"; - _textToEmoji[":convenience_store:"] = "🏪"; - _emojiToText["🏪"] = ":convenience_store:"; - _textToEmoji[":school:"] = "🏫"; - _emojiToText["🏫"] = ":school:"; - _textToEmoji[":love_hotel:"] = "🏩"; - _emojiToText["🏩"] = ":love_hotel:"; - _textToEmoji[":wedding:"] = "💒"; - _emojiToText["💒"] = ":wedding:"; - _textToEmoji[":classical_building:"] = "🏛️"; - _emojiToText["🏛️"] = ":classical_building:"; - _textToEmoji[":church:"] = "⛪"; - _emojiToText["⛪"] = ":church:"; - _textToEmoji[":mosque:"] = "🕌"; - _emojiToText["🕌"] = ":mosque:"; - _textToEmoji[":synagogue:"] = "🕍"; - _emojiToText["🕍"] = ":synagogue:"; - _textToEmoji[":hindu_temple:"] = "🛕"; - _emojiToText["🛕"] = ":hindu_temple:"; - _textToEmoji[":kaaba:"] = "🕋"; - _emojiToText["🕋"] = ":kaaba:"; - _textToEmoji[":shinto_shrine:"] = "⛩️"; - _emojiToText["⛩️"] = ":shinto_shrine:"; - _textToEmoji[":railway_track:"] = "🛤️"; - _emojiToText["🛤️"] = ":railway_track:"; - _textToEmoji[":railroad_track:"] = "🛤️"; - _emojiToText["🛤️"] = ":railroad_track:"; - _textToEmoji[":motorway:"] = "🛣️"; - _emojiToText["🛣️"] = ":motorway:"; - _textToEmoji[":japan:"] = "🗾"; - _emojiToText["🗾"] = ":japan:"; - _textToEmoji[":map_of_japan:"] = "🗾"; - _emojiToText["🗾"] = ":map_of_japan:"; - _textToEmoji[":rice_scene:"] = "🎑"; - _emojiToText["🎑"] = ":rice_scene:"; - _textToEmoji[":park:"] = "🏞️"; - _emojiToText["🏞️"] = ":park:"; - _textToEmoji[":national_park:"] = "🏞️"; - _emojiToText["🏞️"] = ":national_park:"; - _textToEmoji[":sunrise:"] = "🌅"; - _emojiToText["🌅"] = ":sunrise:"; - _textToEmoji[":sunrise_over_mountains:"] = "🌄"; - _emojiToText["🌄"] = ":sunrise_over_mountains:"; - _textToEmoji[":stars:"] = "🌠"; - _emojiToText["🌠"] = ":stars:"; - _textToEmoji[":shooting_star:"] = "🌠"; - _emojiToText["🌠"] = ":shooting_star:"; - _textToEmoji[":sparkler:"] = "🎇"; - _emojiToText["🎇"] = ":sparkler:"; - _textToEmoji[":fireworks:"] = "🎆"; - _emojiToText["🎆"] = ":fireworks:"; - _textToEmoji[":city_sunset:"] = "🌇"; - _emojiToText["🌇"] = ":city_sunset:"; - _textToEmoji[":city_sunrise:"] = "🌇"; - _emojiToText["🌇"] = ":city_sunrise:"; - _textToEmoji[":sunset:"] = "🌇"; - _emojiToText["🌇"] = ":sunset:"; - _textToEmoji[":city_dusk:"] = "🌆"; - _emojiToText["🌆"] = ":city_dusk:"; - _textToEmoji[":cityscape:"] = "🏙️"; - _emojiToText["🏙️"] = ":cityscape:"; - _textToEmoji[":night_with_stars:"] = "🌃"; - _emojiToText["🌃"] = ":night_with_stars:"; - _textToEmoji[":milky_way:"] = "🌌"; - _emojiToText["🌌"] = ":milky_way:"; - _textToEmoji[":bridge_at_night:"] = "🌉"; - _emojiToText["🌉"] = ":bridge_at_night:"; - _textToEmoji[":foggy:"] = "🌁"; - _emojiToText["🌁"] = ":foggy:"; - } + _textToEmoji[":100:"] = "💯"; + _emojiToText["💯"] = ":100:"; + _textToEmoji[":1234:"] = "🔢"; + _emojiToText["🔢"] = ":1234:"; + _textToEmoji[":soccer:"] = "⚽"; + _emojiToText["⚽"] = ":soccer:"; + _textToEmoji[":soccer_ball:"] = "⚽"; + _emojiToText["⚽"] = ":soccer_ball:"; + _textToEmoji[":basketball:"] = "🏀"; + _emojiToText["🏀"] = ":basketball:"; + _textToEmoji[":football:"] = "🏈"; + _emojiToText["🏈"] = ":football:"; + _textToEmoji[":baseball:"] = "⚾"; + _emojiToText["⚾"] = ":baseball:"; + _textToEmoji[":softball:"] = "🥎"; + _emojiToText["🥎"] = ":softball:"; + _textToEmoji[":tennis:"] = "🎾"; + _emojiToText["🎾"] = ":tennis:"; + _textToEmoji[":volleyball:"] = "🏐"; + _emojiToText["🏐"] = ":volleyball:"; + _textToEmoji[":rugby_football:"] = "🏉"; + _emojiToText["🏉"] = ":rugby_football:"; + _textToEmoji[":flying_disc:"] = "🥏"; + _emojiToText["🥏"] = ":flying_disc:"; + _textToEmoji[":8ball:"] = "🎱"; + _emojiToText["🎱"] = ":8ball:"; + _textToEmoji[":yo_yo:"] = "🪀"; + _emojiToText["🪀"] = ":yo_yo:"; + _textToEmoji[":ping_pong:"] = "🏓"; + _emojiToText["🏓"] = ":ping_pong:"; + _textToEmoji[":table_tennis:"] = "🏓"; + _emojiToText["🏓"] = ":table_tennis:"; + _textToEmoji[":badminton:"] = "🏸"; + _emojiToText["🏸"] = ":badminton:"; + _textToEmoji[":hockey:"] = "🏒"; + _emojiToText["🏒"] = ":hockey:"; + _textToEmoji[":ice_hockey:"] = "🏒"; + _emojiToText["🏒"] = ":ice_hockey:"; + _textToEmoji[":field_hockey:"] = "🏑"; + _emojiToText["🏑"] = ":field_hockey:"; + _textToEmoji[":lacrosse:"] = "🥍"; + _emojiToText["🥍"] = ":lacrosse:"; + _textToEmoji[":cricket_game:"] = "🏏"; + _emojiToText["🏏"] = ":cricket_game:"; + _textToEmoji[":cricket_bat_ball:"] = "🏏"; + _emojiToText["🏏"] = ":cricket_bat_ball:"; + _textToEmoji[":boomerang:"] = "🪃"; + _emojiToText["🪃"] = ":boomerang:"; + _textToEmoji[":goal:"] = "🥅"; + _emojiToText["🥅"] = ":goal:"; + _textToEmoji[":goal_net:"] = "🥅"; + _emojiToText["🥅"] = ":goal_net:"; + _textToEmoji[":golf:"] = "⛳"; + _emojiToText["⛳"] = ":golf:"; + _textToEmoji[":flag_in_hole:"] = "⛳"; + _emojiToText["⛳"] = ":flag_in_hole:"; + _textToEmoji[":kite:"] = "🪁"; + _emojiToText["🪁"] = ":kite:"; + _textToEmoji[":playground_slide:"] = "🛝"; + _emojiToText["🛝"] = ":playground_slide:"; + _textToEmoji[":bow_and_arrow:"] = "🏹"; + _emojiToText["🏹"] = ":bow_and_arrow:"; + _textToEmoji[":archery:"] = "🏹"; + _emojiToText["🏹"] = ":archery:"; + _textToEmoji[":fishing_pole_and_fish:"] = "🎣"; + _emojiToText["🎣"] = ":fishing_pole_and_fish:"; + _textToEmoji[":fishing_pole:"] = "🎣"; + _emojiToText["🎣"] = ":fishing_pole:"; + _textToEmoji[":diving_mask:"] = "🤿"; + _emojiToText["🤿"] = ":diving_mask:"; + _textToEmoji[":boxing_glove:"] = "🥊"; + _emojiToText["🥊"] = ":boxing_glove:"; + _textToEmoji[":boxing_gloves:"] = "🥊"; + _emojiToText["🥊"] = ":boxing_gloves:"; + _textToEmoji[":martial_arts_uniform:"] = "🥋"; + _emojiToText["🥋"] = ":martial_arts_uniform:"; + _textToEmoji[":karate_uniform:"] = "🥋"; + _emojiToText["🥋"] = ":karate_uniform:"; + _textToEmoji[":running_shirt_with_sash:"] = "🎽"; + _emojiToText["🎽"] = ":running_shirt_with_sash:"; + _textToEmoji[":running_shirt:"] = "🎽"; + _emojiToText["🎽"] = ":running_shirt:"; + _textToEmoji[":skateboard:"] = "🛹"; + _emojiToText["🛹"] = ":skateboard:"; + _textToEmoji[":roller_skate:"] = "🛼"; + _emojiToText["🛼"] = ":roller_skate:"; + _textToEmoji[":sled:"] = "🛷"; + _emojiToText["🛷"] = ":sled:"; + _textToEmoji[":ice_skate:"] = "⛸️"; + _emojiToText["⛸️"] = ":ice_skate:"; + _textToEmoji[":curling_stone:"] = "🥌"; + _emojiToText["🥌"] = ":curling_stone:"; + _textToEmoji[":ski:"] = "🎿"; + _emojiToText["🎿"] = ":ski:"; + _textToEmoji[":skis:"] = "🎿"; + _emojiToText["🎿"] = ":skis:"; + _textToEmoji[":skier:"] = "⛷️"; + _emojiToText["⛷️"] = ":skier:"; + _textToEmoji[":snowboarder:"] = "🏂"; + _emojiToText["🏂"] = ":snowboarder:"; + _textToEmoji[":parachute:"] = "🪂"; + _emojiToText["🪂"] = ":parachute:"; + _textToEmoji[":person_lifting_weights:"] = "🏋️"; + _emojiToText["🏋️"] = ":person_lifting_weights:"; + _textToEmoji[":lifter:"] = "🏋️"; + _emojiToText["🏋️"] = ":lifter:"; + _textToEmoji[":weight_lifter:"] = "🏋️"; + _emojiToText["🏋️"] = ":weight_lifter:"; + _textToEmoji[":woman_lifting_weights:"] = "🏋️‍♀️"; + _emojiToText["🏋️‍♀️"] = ":woman_lifting_weights:"; + _textToEmoji[":man_lifting_weights:"] = "🏋️‍♂️"; + _emojiToText["🏋️‍♂️"] = ":man_lifting_weights:"; + _textToEmoji[":people_wrestling:"] = "🤼"; + _emojiToText["🤼"] = ":people_wrestling:"; + _textToEmoji[":wrestlers:"] = "🤼"; + _emojiToText["🤼"] = ":wrestlers:"; + _textToEmoji[":wrestling:"] = "🤼"; + _emojiToText["🤼"] = ":wrestling:"; + _textToEmoji[":women_wrestling:"] = "🤼‍♀️"; + _emojiToText["🤼‍♀️"] = ":women_wrestling:"; + _textToEmoji[":men_wrestling:"] = "🤼‍♂️"; + _emojiToText["🤼‍♂️"] = ":men_wrestling:"; + _textToEmoji[":person_doing_cartwheel:"] = "🤸"; + _emojiToText["🤸"] = ":person_doing_cartwheel:"; + _textToEmoji[":cartwheel:"] = "🤸"; + _emojiToText["🤸"] = ":cartwheel:"; + _textToEmoji[":woman_cartwheeling:"] = "🤸‍♀️"; + _emojiToText["🤸‍♀️"] = ":woman_cartwheeling:"; + _textToEmoji[":man_cartwheeling:"] = "🤸‍♂️"; + _emojiToText["🤸‍♂️"] = ":man_cartwheeling:"; + _textToEmoji[":person_bouncing_ball:"] = "⛹️"; + _emojiToText["⛹️"] = ":person_bouncing_ball:"; + _textToEmoji[":basketball_player:"] = "⛹️"; + _emojiToText["⛹️"] = ":basketball_player:"; + _textToEmoji[":person_with_ball:"] = "⛹️"; + _emojiToText["⛹️"] = ":person_with_ball:"; + _textToEmoji[":woman_bouncing_ball:"] = "⛹️‍♀️"; + _emojiToText["⛹️‍♀️"] = ":woman_bouncing_ball:"; + _textToEmoji[":man_bouncing_ball:"] = "⛹️‍♂️"; + _emojiToText["⛹️‍♂️"] = ":man_bouncing_ball:"; + _textToEmoji[":person_fencing:"] = "🤺"; + _emojiToText["🤺"] = ":person_fencing:"; + _textToEmoji[":fencer:"] = "🤺"; + _emojiToText["🤺"] = ":fencer:"; + _textToEmoji[":fencing:"] = "🤺"; + _emojiToText["🤺"] = ":fencing:"; + _textToEmoji[":person_playing_handball:"] = "🤾"; + _emojiToText["🤾"] = ":person_playing_handball:"; + _textToEmoji[":handball:"] = "🤾"; + _emojiToText["🤾"] = ":handball:"; + _textToEmoji[":woman_playing_handball:"] = "🤾‍♀️"; + _emojiToText["🤾‍♀️"] = ":woman_playing_handball:"; + _textToEmoji[":man_playing_handball:"] = "🤾‍♂️"; + _emojiToText["🤾‍♂️"] = ":man_playing_handball:"; + _textToEmoji[":person_golfing:"] = "🏌️"; + _emojiToText["🏌️"] = ":person_golfing:"; + _textToEmoji[":golfer:"] = "🏌️"; + _emojiToText["🏌️"] = ":golfer:"; + _textToEmoji[":woman_golfing:"] = "🏌️‍♀️"; + _emojiToText["🏌️‍♀️"] = ":woman_golfing:"; + _textToEmoji[":man_golfing:"] = "🏌️‍♂️"; + _emojiToText["🏌️‍♂️"] = ":man_golfing:"; + _textToEmoji[":horse_racing:"] = "🏇"; + _emojiToText["🏇"] = ":horse_racing:"; + _textToEmoji[":person_in_lotus_position:"] = "🧘"; + _emojiToText["🧘"] = ":person_in_lotus_position:"; + _textToEmoji[":woman_in_lotus_position:"] = "🧘‍♀️"; + _emojiToText["🧘‍♀️"] = ":woman_in_lotus_position:"; + _textToEmoji[":man_in_lotus_position:"] = "🧘‍♂️"; + _emojiToText["🧘‍♂️"] = ":man_in_lotus_position:"; + _textToEmoji[":person_surfing:"] = "🏄"; + _emojiToText["🏄"] = ":person_surfing:"; + _textToEmoji[":surfer:"] = "🏄"; + _emojiToText["🏄"] = ":surfer:"; + _textToEmoji[":woman_surfing:"] = "🏄‍♀️"; + _emojiToText["🏄‍♀️"] = ":woman_surfing:"; + _textToEmoji[":man_surfing:"] = "🏄‍♂️"; + _emojiToText["🏄‍♂️"] = ":man_surfing:"; + _textToEmoji[":person_swimming:"] = "🏊"; + _emojiToText["🏊"] = ":person_swimming:"; + _textToEmoji[":swimmer:"] = "🏊"; + _emojiToText["🏊"] = ":swimmer:"; + _textToEmoji[":woman_swimming:"] = "🏊‍♀️"; + _emojiToText["🏊‍♀️"] = ":woman_swimming:"; + _textToEmoji[":man_swimming:"] = "🏊‍♂️"; + _emojiToText["🏊‍♂️"] = ":man_swimming:"; + _textToEmoji[":person_playing_water_polo:"] = "🤽"; + _emojiToText["🤽"] = ":person_playing_water_polo:"; + _textToEmoji[":water_polo:"] = "🤽"; + _emojiToText["🤽"] = ":water_polo:"; + _textToEmoji[":woman_playing_water_polo:"] = "🤽‍♀️"; + _emojiToText["🤽‍♀️"] = ":woman_playing_water_polo:"; + _textToEmoji[":man_playing_water_polo:"] = "🤽‍♂️"; + _emojiToText["🤽‍♂️"] = ":man_playing_water_polo:"; + _textToEmoji[":person_rowing_boat:"] = "🚣"; + _emojiToText["🚣"] = ":person_rowing_boat:"; + _textToEmoji[":rowboat:"] = "🚣"; + _emojiToText["🚣"] = ":rowboat:"; + _textToEmoji[":woman_rowing_boat:"] = "🚣‍♀️"; + _emojiToText["🚣‍♀️"] = ":woman_rowing_boat:"; + _textToEmoji[":man_rowing_boat:"] = "🚣‍♂️"; + _emojiToText["🚣‍♂️"] = ":man_rowing_boat:"; + _textToEmoji[":person_climbing:"] = "🧗"; + _emojiToText["🧗"] = ":person_climbing:"; + _textToEmoji[":woman_climbing:"] = "🧗‍♀️"; + _emojiToText["🧗‍♀️"] = ":woman_climbing:"; + _textToEmoji[":man_climbing:"] = "🧗‍♂️"; + _emojiToText["🧗‍♂️"] = ":man_climbing:"; + _textToEmoji[":person_mountain_biking:"] = "🚵"; + _emojiToText["🚵"] = ":person_mountain_biking:"; + _textToEmoji[":mountain_bicyclist:"] = "🚵"; + _emojiToText["🚵"] = ":mountain_bicyclist:"; + _textToEmoji[":woman_mountain_biking:"] = "🚵‍♀️"; + _emojiToText["🚵‍♀️"] = ":woman_mountain_biking:"; + _textToEmoji[":man_mountain_biking:"] = "🚵‍♂️"; + _emojiToText["🚵‍♂️"] = ":man_mountain_biking:"; + _textToEmoji[":person_biking:"] = "🚴"; + _emojiToText["🚴"] = ":person_biking:"; + _textToEmoji[":bicyclist:"] = "🚴"; + _emojiToText["🚴"] = ":bicyclist:"; + _textToEmoji[":woman_biking:"] = "🚴‍♀️"; + _emojiToText["🚴‍♀️"] = ":woman_biking:"; + _textToEmoji[":man_biking:"] = "🚴‍♂️"; + _emojiToText["🚴‍♂️"] = ":man_biking:"; + _textToEmoji[":trophy:"] = "🏆"; + _emojiToText["🏆"] = ":trophy:"; + _textToEmoji[":first_place:"] = "🥇"; + _emojiToText["🥇"] = ":first_place:"; + _textToEmoji[":first_place_medal:"] = "🥇"; + _emojiToText["🥇"] = ":first_place_medal:"; + _textToEmoji[":second_place:"] = "🥈"; + _emojiToText["🥈"] = ":second_place:"; + _textToEmoji[":second_place_medal:"] = "🥈"; + _emojiToText["🥈"] = ":second_place_medal:"; + _textToEmoji[":third_place:"] = "🥉"; + _emojiToText["🥉"] = ":third_place:"; + _textToEmoji[":third_place_medal:"] = "🥉"; + _emojiToText["🥉"] = ":third_place_medal:"; + _textToEmoji[":medal:"] = "🏅"; + _emojiToText["🏅"] = ":medal:"; + _textToEmoji[":sports_medal:"] = "🏅"; + _emojiToText["🏅"] = ":sports_medal:"; + _textToEmoji[":military_medal:"] = "🎖️"; + _emojiToText["🎖️"] = ":military_medal:"; + _textToEmoji[":rosette:"] = "🏵️"; + _emojiToText["🏵️"] = ":rosette:"; + _textToEmoji[":reminder_ribbon:"] = "🎗️"; + _emojiToText["🎗️"] = ":reminder_ribbon:"; + _textToEmoji[":ticket:"] = "🎫"; + _emojiToText["🎫"] = ":ticket:"; + _textToEmoji[":tickets:"] = "🎟️"; + _emojiToText["🎟️"] = ":tickets:"; + _textToEmoji[":admission_tickets:"] = "🎟️"; + _emojiToText["🎟️"] = ":admission_tickets:"; + _textToEmoji[":circus_tent:"] = "🎪"; + _emojiToText["🎪"] = ":circus_tent:"; + _textToEmoji[":person_juggling:"] = "🤹"; + _emojiToText["🤹"] = ":person_juggling:"; + _textToEmoji[":juggling:"] = "🤹"; + _emojiToText["🤹"] = ":juggling:"; + _textToEmoji[":juggler:"] = "🤹"; + _emojiToText["🤹"] = ":juggler:"; + _textToEmoji[":woman_juggling:"] = "🤹‍♀️"; + _emojiToText["🤹‍♀️"] = ":woman_juggling:"; + _textToEmoji[":man_juggling:"] = "🤹‍♂️"; + _emojiToText["🤹‍♂️"] = ":man_juggling:"; + _textToEmoji[":performing_arts:"] = "🎭"; + _emojiToText["🎭"] = ":performing_arts:"; + _textToEmoji[":ballet_shoes:"] = "🩰"; + _emojiToText["🩰"] = ":ballet_shoes:"; + _textToEmoji[":art:"] = "🎨"; + _emojiToText["🎨"] = ":art:"; + _textToEmoji[":clapper:"] = "🎬"; + _emojiToText["🎬"] = ":clapper:"; + _textToEmoji[":clapper_board:"] = "🎬"; + _emojiToText["🎬"] = ":clapper_board:"; + _textToEmoji[":microphone:"] = "🎤"; + _emojiToText["🎤"] = ":microphone:"; + _textToEmoji[":headphones:"] = "🎧"; + _emojiToText["🎧"] = ":headphones:"; + _textToEmoji[":headphone:"] = "🎧"; + _emojiToText["🎧"] = ":headphone:"; + _textToEmoji[":musical_score:"] = "🎼"; + _emojiToText["🎼"] = ":musical_score:"; + _textToEmoji[":musical_keyboard:"] = "🎹"; + _emojiToText["🎹"] = ":musical_keyboard:"; + _textToEmoji[":maracas:"] = "🪇"; + _emojiToText["🪇"] = ":maracas:"; + _textToEmoji[":drum:"] = "🥁"; + _emojiToText["🥁"] = ":drum:"; + _textToEmoji[":drum_with_drumsticks:"] = "🥁"; + _emojiToText["🥁"] = ":drum_with_drumsticks:"; + _textToEmoji[":long_drum:"] = "🪘"; + _emojiToText["🪘"] = ":long_drum:"; + _textToEmoji[":saxophone:"] = "🎷"; + _emojiToText["🎷"] = ":saxophone:"; + _textToEmoji[":trumpet:"] = "🎺"; + _emojiToText["🎺"] = ":trumpet:"; + _textToEmoji[":accordion:"] = "🪗"; + _emojiToText["🪗"] = ":accordion:"; + _textToEmoji[":guitar:"] = "🎸"; + _emojiToText["🎸"] = ":guitar:"; + _textToEmoji[":banjo:"] = "🪕"; + _emojiToText["🪕"] = ":banjo:"; + _textToEmoji[":violin:"] = "🎻"; + _emojiToText["🎻"] = ":violin:"; + _textToEmoji[":flute:"] = "🪈"; + _emojiToText["🪈"] = ":flute:"; + _textToEmoji[":game_die:"] = "🎲"; + _emojiToText["🎲"] = ":game_die:"; + _textToEmoji[":chess_pawn:"] = "♟️"; + _emojiToText["♟️"] = ":chess_pawn:"; + _textToEmoji[":dart:"] = "🎯"; + _emojiToText["🎯"] = ":dart:"; + _textToEmoji[":direct_hit:"] = "🎯"; + _emojiToText["🎯"] = ":direct_hit:"; + _textToEmoji[":bowling:"] = "🎳"; + _emojiToText["🎳"] = ":bowling:"; + _textToEmoji[":video_game:"] = "🎮"; + _emojiToText["🎮"] = ":video_game:"; + _textToEmoji[":slot_machine:"] = "🎰"; + _emojiToText["🎰"] = ":slot_machine:"; + _textToEmoji[":jigsaw:"] = "🧩"; + _emojiToText["🧩"] = ":jigsaw:"; + _textToEmoji[":puzzle_piece:"] = "🧩"; + _emojiToText["🧩"] = ":puzzle_piece:"; + _textToEmoji[":flag_white:"] = "🏳️"; + _emojiToText["🏳️"] = ":flag_white:"; + _textToEmoji[":flag_black:"] = "🏴"; + _emojiToText["🏴"] = ":flag_black:"; + _textToEmoji[":pirate_flag:"] = "🏴‍☠️"; + _emojiToText["🏴‍☠️"] = ":pirate_flag:"; + _textToEmoji[":checkered_flag:"] = "🏁"; + _emojiToText["🏁"] = ":checkered_flag:"; + _textToEmoji[":triangular_flag_on_post:"] = "🚩"; + _emojiToText["🚩"] = ":triangular_flag_on_post:"; + _textToEmoji[":rainbow_flag:"] = "🏳️‍🌈"; + _emojiToText["🏳️‍🌈"] = ":rainbow_flag:"; + _textToEmoji[":gay_pride_flag:"] = "🏳️‍🌈"; + _emojiToText["🏳️‍🌈"] = ":gay_pride_flag:"; + _textToEmoji[":transgender_flag:"] = "🏳️‍⚧️"; + _emojiToText["🏳️‍⚧️"] = ":transgender_flag:"; + _textToEmoji[":united_nations:"] = "🇺🇳"; + _emojiToText["🇺🇳"] = ":united_nations:"; + _textToEmoji[":flag_af:"] = "🇦🇫"; + _emojiToText["🇦🇫"] = ":flag_af:"; + _textToEmoji[":flag_ax:"] = "🇦🇽"; + _emojiToText["🇦🇽"] = ":flag_ax:"; + _textToEmoji[":flag_al:"] = "🇦🇱"; + _emojiToText["🇦🇱"] = ":flag_al:"; + _textToEmoji[":flag_dz:"] = "🇩🇿"; + _emojiToText["🇩🇿"] = ":flag_dz:"; + _textToEmoji[":flag_as:"] = "🇦🇸"; + _emojiToText["🇦🇸"] = ":flag_as:"; + _textToEmoji[":flag_ad:"] = "🇦🇩"; + _emojiToText["🇦🇩"] = ":flag_ad:"; + _textToEmoji[":flag_ao:"] = "🇦🇴"; + _emojiToText["🇦🇴"] = ":flag_ao:"; + _textToEmoji[":flag_ai:"] = "🇦🇮"; + _emojiToText["🇦🇮"] = ":flag_ai:"; + _textToEmoji[":flag_aq:"] = "🇦🇶"; + _emojiToText["🇦🇶"] = ":flag_aq:"; + _textToEmoji[":flag_ag:"] = "🇦🇬"; + _emojiToText["🇦🇬"] = ":flag_ag:"; + _textToEmoji[":flag_ar:"] = "🇦🇷"; + _emojiToText["🇦🇷"] = ":flag_ar:"; + _textToEmoji[":flag_am:"] = "🇦🇲"; + _emojiToText["🇦🇲"] = ":flag_am:"; + _textToEmoji[":flag_aw:"] = "🇦🇼"; + _emojiToText["🇦🇼"] = ":flag_aw:"; + _textToEmoji[":flag_au:"] = "🇦🇺"; + _emojiToText["🇦🇺"] = ":flag_au:"; + _textToEmoji[":flag_at:"] = "🇦🇹"; + _emojiToText["🇦🇹"] = ":flag_at:"; + _textToEmoji[":flag_az:"] = "🇦🇿"; + _emojiToText["🇦🇿"] = ":flag_az:"; + _textToEmoji[":flag_bs:"] = "🇧🇸"; + _emojiToText["🇧🇸"] = ":flag_bs:"; + _textToEmoji[":flag_bh:"] = "🇧🇭"; + _emojiToText["🇧🇭"] = ":flag_bh:"; + _textToEmoji[":flag_bd:"] = "🇧🇩"; + _emojiToText["🇧🇩"] = ":flag_bd:"; + _textToEmoji[":flag_bb:"] = "🇧🇧"; + _emojiToText["🇧🇧"] = ":flag_bb:"; + _textToEmoji[":flag_by:"] = "🇧🇾"; + _emojiToText["🇧🇾"] = ":flag_by:"; + _textToEmoji[":flag_be:"] = "🇧🇪"; + _emojiToText["🇧🇪"] = ":flag_be:"; + _textToEmoji[":flag_bz:"] = "🇧🇿"; + _emojiToText["🇧🇿"] = ":flag_bz:"; + _textToEmoji[":flag_bj:"] = "🇧🇯"; + _emojiToText["🇧🇯"] = ":flag_bj:"; + _textToEmoji[":flag_bm:"] = "🇧🇲"; + _emojiToText["🇧🇲"] = ":flag_bm:"; + _textToEmoji[":flag_bt:"] = "🇧🇹"; + _emojiToText["🇧🇹"] = ":flag_bt:"; + _textToEmoji[":flag_bo:"] = "🇧🇴"; + _emojiToText["🇧🇴"] = ":flag_bo:"; + _textToEmoji[":flag_ba:"] = "🇧🇦"; + _emojiToText["🇧🇦"] = ":flag_ba:"; + _textToEmoji[":flag_bw:"] = "🇧🇼"; + _emojiToText["🇧🇼"] = ":flag_bw:"; + _textToEmoji[":flag_br:"] = "🇧🇷"; + _emojiToText["🇧🇷"] = ":flag_br:"; + _textToEmoji[":flag_io:"] = "🇮🇴"; + _emojiToText["🇮🇴"] = ":flag_io:"; + _textToEmoji[":flag_vg:"] = "🇻🇬"; + _emojiToText["🇻🇬"] = ":flag_vg:"; + _textToEmoji[":flag_bn:"] = "🇧🇳"; + _emojiToText["🇧🇳"] = ":flag_bn:"; + _textToEmoji[":flag_bg:"] = "🇧🇬"; + _emojiToText["🇧🇬"] = ":flag_bg:"; + _textToEmoji[":flag_bf:"] = "🇧🇫"; + _emojiToText["🇧🇫"] = ":flag_bf:"; + _textToEmoji[":flag_bi:"] = "🇧🇮"; + _emojiToText["🇧🇮"] = ":flag_bi:"; + _textToEmoji[":flag_kh:"] = "🇰🇭"; + _emojiToText["🇰🇭"] = ":flag_kh:"; + _textToEmoji[":flag_cm:"] = "🇨🇲"; + _emojiToText["🇨🇲"] = ":flag_cm:"; + _textToEmoji[":flag_ca:"] = "🇨🇦"; + _emojiToText["🇨🇦"] = ":flag_ca:"; + _textToEmoji[":flag_ic:"] = "🇮🇨"; + _emojiToText["🇮🇨"] = ":flag_ic:"; + _textToEmoji[":flag_cv:"] = "🇨🇻"; + _emojiToText["🇨🇻"] = ":flag_cv:"; + _textToEmoji[":flag_bq:"] = "🇧🇶"; + _emojiToText["🇧🇶"] = ":flag_bq:"; + _textToEmoji[":flag_ky:"] = "🇰🇾"; + _emojiToText["🇰🇾"] = ":flag_ky:"; + _textToEmoji[":flag_cf:"] = "🇨🇫"; + _emojiToText["🇨🇫"] = ":flag_cf:"; + _textToEmoji[":flag_td:"] = "🇹🇩"; + _emojiToText["🇹🇩"] = ":flag_td:"; + _textToEmoji[":flag_cl:"] = "🇨🇱"; + _emojiToText["🇨🇱"] = ":flag_cl:"; + _textToEmoji[":flag_cn:"] = "🇨🇳"; + _emojiToText["🇨🇳"] = ":flag_cn:"; + _textToEmoji[":flag_cx:"] = "🇨🇽"; + _emojiToText["🇨🇽"] = ":flag_cx:"; + _textToEmoji[":flag_cc:"] = "🇨🇨"; + _emojiToText["🇨🇨"] = ":flag_cc:"; + _textToEmoji[":flag_co:"] = "🇨🇴"; + _emojiToText["🇨🇴"] = ":flag_co:"; + _textToEmoji[":flag_km:"] = "🇰🇲"; + _emojiToText["🇰🇲"] = ":flag_km:"; + _textToEmoji[":flag_cg:"] = "🇨🇬"; + _emojiToText["🇨🇬"] = ":flag_cg:"; + _textToEmoji[":flag_cd:"] = "🇨🇩"; + _emojiToText["🇨🇩"] = ":flag_cd:"; + _textToEmoji[":flag_ck:"] = "🇨🇰"; + _emojiToText["🇨🇰"] = ":flag_ck:"; + _textToEmoji[":flag_cr:"] = "🇨🇷"; + _emojiToText["🇨🇷"] = ":flag_cr:"; + _textToEmoji[":flag_ci:"] = "🇨🇮"; + _emojiToText["🇨🇮"] = ":flag_ci:"; + _textToEmoji[":flag_hr:"] = "🇭🇷"; + _emojiToText["🇭🇷"] = ":flag_hr:"; + _textToEmoji[":flag_cu:"] = "🇨🇺"; + _emojiToText["🇨🇺"] = ":flag_cu:"; + _textToEmoji[":flag_cw:"] = "🇨🇼"; + _emojiToText["🇨🇼"] = ":flag_cw:"; + _textToEmoji[":flag_cy:"] = "🇨🇾"; + _emojiToText["🇨🇾"] = ":flag_cy:"; + _textToEmoji[":flag_cz:"] = "🇨🇿"; + _emojiToText["🇨🇿"] = ":flag_cz:"; + _textToEmoji[":flag_dk:"] = "🇩🇰"; + _emojiToText["🇩🇰"] = ":flag_dk:"; + _textToEmoji[":flag_dj:"] = "🇩🇯"; + _emojiToText["🇩🇯"] = ":flag_dj:"; + _textToEmoji[":flag_dm:"] = "🇩🇲"; + _emojiToText["🇩🇲"] = ":flag_dm:"; + _textToEmoji[":flag_do:"] = "🇩🇴"; + _emojiToText["🇩🇴"] = ":flag_do:"; + _textToEmoji[":flag_ec:"] = "🇪🇨"; + _emojiToText["🇪🇨"] = ":flag_ec:"; + _textToEmoji[":flag_eg:"] = "🇪🇬"; + _emojiToText["🇪🇬"] = ":flag_eg:"; + _textToEmoji[":flag_sv:"] = "🇸🇻"; + _emojiToText["🇸🇻"] = ":flag_sv:"; + _textToEmoji[":flag_gq:"] = "🇬🇶"; + _emojiToText["🇬🇶"] = ":flag_gq:"; + _textToEmoji[":flag_er:"] = "🇪🇷"; + _emojiToText["🇪🇷"] = ":flag_er:"; + _textToEmoji[":flag_ee:"] = "🇪🇪"; + _emojiToText["🇪🇪"] = ":flag_ee:"; + _textToEmoji[":flag_et:"] = "🇪🇹"; + _emojiToText["🇪🇹"] = ":flag_et:"; + _textToEmoji[":flag_eu:"] = "🇪🇺"; + _emojiToText["🇪🇺"] = ":flag_eu:"; + _textToEmoji[":flag_fk:"] = "🇫🇰"; + _emojiToText["🇫🇰"] = ":flag_fk:"; + _textToEmoji[":flag_fo:"] = "🇫🇴"; + _emojiToText["🇫🇴"] = ":flag_fo:"; + _textToEmoji[":flag_fj:"] = "🇫🇯"; + _emojiToText["🇫🇯"] = ":flag_fj:"; + _textToEmoji[":flag_fi:"] = "🇫🇮"; + _emojiToText["🇫🇮"] = ":flag_fi:"; + _textToEmoji[":flag_fr:"] = "🇫🇷"; + _emojiToText["🇫🇷"] = ":flag_fr:"; + _textToEmoji[":flag_gf:"] = "🇬🇫"; + _emojiToText["🇬🇫"] = ":flag_gf:"; + _textToEmoji[":flag_pf:"] = "🇵🇫"; + _emojiToText["🇵🇫"] = ":flag_pf:"; + _textToEmoji[":flag_tf:"] = "🇹🇫"; + _emojiToText["🇹🇫"] = ":flag_tf:"; + _textToEmoji[":flag_ga:"] = "🇬🇦"; + _emojiToText["🇬🇦"] = ":flag_ga:"; + _textToEmoji[":flag_gm:"] = "🇬🇲"; + _emojiToText["🇬🇲"] = ":flag_gm:"; + _textToEmoji[":flag_ge:"] = "🇬🇪"; + _emojiToText["🇬🇪"] = ":flag_ge:"; + _textToEmoji[":flag_de:"] = "🇩🇪"; + _emojiToText["🇩🇪"] = ":flag_de:"; + _textToEmoji[":flag_gh:"] = "🇬🇭"; + _emojiToText["🇬🇭"] = ":flag_gh:"; + _textToEmoji[":flag_gi:"] = "🇬🇮"; + _emojiToText["🇬🇮"] = ":flag_gi:"; + _textToEmoji[":flag_gr:"] = "🇬🇷"; + _emojiToText["🇬🇷"] = ":flag_gr:"; + _textToEmoji[":flag_gl:"] = "🇬🇱"; + _emojiToText["🇬🇱"] = ":flag_gl:"; + _textToEmoji[":flag_gd:"] = "🇬🇩"; + _emojiToText["🇬🇩"] = ":flag_gd:"; + _textToEmoji[":flag_gp:"] = "🇬🇵"; + _emojiToText["🇬🇵"] = ":flag_gp:"; + _textToEmoji[":flag_gu:"] = "🇬🇺"; + _emojiToText["🇬🇺"] = ":flag_gu:"; + _textToEmoji[":flag_gt:"] = "🇬🇹"; + _emojiToText["🇬🇹"] = ":flag_gt:"; + _textToEmoji[":flag_gg:"] = "🇬🇬"; + _emojiToText["🇬🇬"] = ":flag_gg:"; + _textToEmoji[":flag_gn:"] = "🇬🇳"; + _emojiToText["🇬🇳"] = ":flag_gn:"; + _textToEmoji[":flag_gw:"] = "🇬🇼"; + _emojiToText["🇬🇼"] = ":flag_gw:"; + _textToEmoji[":flag_gy:"] = "🇬🇾"; + _emojiToText["🇬🇾"] = ":flag_gy:"; + _textToEmoji[":flag_ht:"] = "🇭🇹"; + _emojiToText["🇭🇹"] = ":flag_ht:"; + _textToEmoji[":flag_hn:"] = "🇭🇳"; + _emojiToText["🇭🇳"] = ":flag_hn:"; + _textToEmoji[":flag_hk:"] = "🇭🇰"; + _emojiToText["🇭🇰"] = ":flag_hk:"; + _textToEmoji[":flag_hu:"] = "🇭🇺"; + _emojiToText["🇭🇺"] = ":flag_hu:"; + _textToEmoji[":flag_is:"] = "🇮🇸"; + _emojiToText["🇮🇸"] = ":flag_is:"; + _textToEmoji[":flag_in:"] = "🇮🇳"; + _emojiToText["🇮🇳"] = ":flag_in:"; + _textToEmoji[":flag_id:"] = "🇮🇩"; + _emojiToText["🇮🇩"] = ":flag_id:"; + _textToEmoji[":flag_ir:"] = "🇮🇷"; + _emojiToText["🇮🇷"] = ":flag_ir:"; + _textToEmoji[":flag_iq:"] = "🇮🇶"; + _emojiToText["🇮🇶"] = ":flag_iq:"; + _textToEmoji[":flag_ie:"] = "🇮🇪"; + _emojiToText["🇮🇪"] = ":flag_ie:"; + _textToEmoji[":flag_im:"] = "🇮🇲"; + _emojiToText["🇮🇲"] = ":flag_im:"; + _textToEmoji[":flag_il:"] = "🇮🇱"; + _emojiToText["🇮🇱"] = ":flag_il:"; + _textToEmoji[":flag_it:"] = "🇮🇹"; + _emojiToText["🇮🇹"] = ":flag_it:"; + _textToEmoji[":flag_jm:"] = "🇯🇲"; + _emojiToText["🇯🇲"] = ":flag_jm:"; + _textToEmoji[":flag_jp:"] = "🇯🇵"; + _emojiToText["🇯🇵"] = ":flag_jp:"; + _textToEmoji[":crossed_flags:"] = "🎌"; + _emojiToText["🎌"] = ":crossed_flags:"; + _textToEmoji[":flag_je:"] = "🇯🇪"; + _emojiToText["🇯🇪"] = ":flag_je:"; + _textToEmoji[":flag_jo:"] = "🇯🇴"; + _emojiToText["🇯🇴"] = ":flag_jo:"; + _textToEmoji[":flag_kz:"] = "🇰🇿"; + _emojiToText["🇰🇿"] = ":flag_kz:"; + _textToEmoji[":flag_ke:"] = "🇰🇪"; + _emojiToText["🇰🇪"] = ":flag_ke:"; + _textToEmoji[":flag_ki:"] = "🇰🇮"; + _emojiToText["🇰🇮"] = ":flag_ki:"; + _textToEmoji[":flag_xk:"] = "🇽🇰"; + _emojiToText["🇽🇰"] = ":flag_xk:"; + _textToEmoji[":flag_kw:"] = "🇰🇼"; + _emojiToText["🇰🇼"] = ":flag_kw:"; + _textToEmoji[":flag_kg:"] = "🇰🇬"; + _emojiToText["🇰🇬"] = ":flag_kg:"; + _textToEmoji[":flag_la:"] = "🇱🇦"; + _emojiToText["🇱🇦"] = ":flag_la:"; + _textToEmoji[":flag_lv:"] = "🇱🇻"; + _emojiToText["🇱🇻"] = ":flag_lv:"; + _textToEmoji[":flag_lb:"] = "🇱🇧"; + _emojiToText["🇱🇧"] = ":flag_lb:"; + _textToEmoji[":flag_ls:"] = "🇱🇸"; + _emojiToText["🇱🇸"] = ":flag_ls:"; + _textToEmoji[":flag_lr:"] = "🇱🇷"; + _emojiToText["🇱🇷"] = ":flag_lr:"; + _textToEmoji[":flag_ly:"] = "🇱🇾"; + _emojiToText["🇱🇾"] = ":flag_ly:"; + _textToEmoji[":flag_li:"] = "🇱🇮"; + _emojiToText["🇱🇮"] = ":flag_li:"; + _textToEmoji[":flag_lt:"] = "🇱🇹"; + _emojiToText["🇱🇹"] = ":flag_lt:"; + _textToEmoji[":flag_lu:"] = "🇱🇺"; + _emojiToText["🇱🇺"] = ":flag_lu:"; + _textToEmoji[":flag_mo:"] = "🇲🇴"; + _emojiToText["🇲🇴"] = ":flag_mo:"; + _textToEmoji[":flag_mk:"] = "🇲🇰"; + _emojiToText["🇲🇰"] = ":flag_mk:"; + _textToEmoji[":flag_mg:"] = "🇲🇬"; + _emojiToText["🇲🇬"] = ":flag_mg:"; + _textToEmoji[":flag_mw:"] = "🇲🇼"; + _emojiToText["🇲🇼"] = ":flag_mw:"; + _textToEmoji[":flag_my:"] = "🇲🇾"; + _emojiToText["🇲🇾"] = ":flag_my:"; + _textToEmoji[":flag_mv:"] = "🇲🇻"; + _emojiToText["🇲🇻"] = ":flag_mv:"; + _textToEmoji[":flag_ml:"] = "🇲🇱"; + _emojiToText["🇲🇱"] = ":flag_ml:"; + _textToEmoji[":flag_mt:"] = "🇲🇹"; + _emojiToText["🇲🇹"] = ":flag_mt:"; + _textToEmoji[":flag_mh:"] = "🇲🇭"; + _emojiToText["🇲🇭"] = ":flag_mh:"; + _textToEmoji[":flag_mq:"] = "🇲🇶"; + _emojiToText["🇲🇶"] = ":flag_mq:"; + _textToEmoji[":flag_mr:"] = "🇲🇷"; + _emojiToText["🇲🇷"] = ":flag_mr:"; + _textToEmoji[":flag_mu:"] = "🇲🇺"; + _emojiToText["🇲🇺"] = ":flag_mu:"; + _textToEmoji[":flag_yt:"] = "🇾🇹"; + _emojiToText["🇾🇹"] = ":flag_yt:"; + _textToEmoji[":flag_mx:"] = "🇲🇽"; + _emojiToText["🇲🇽"] = ":flag_mx:"; + _textToEmoji[":flag_fm:"] = "🇫🇲"; + _emojiToText["🇫🇲"] = ":flag_fm:"; + _textToEmoji[":flag_md:"] = "🇲🇩"; + _emojiToText["🇲🇩"] = ":flag_md:"; + _textToEmoji[":flag_mc:"] = "🇲🇨"; + _emojiToText["🇲🇨"] = ":flag_mc:"; + _textToEmoji[":flag_mn:"] = "🇲🇳"; + _emojiToText["🇲🇳"] = ":flag_mn:"; + _textToEmoji[":flag_me:"] = "🇲🇪"; + _emojiToText["🇲🇪"] = ":flag_me:"; + _textToEmoji[":flag_ms:"] = "🇲🇸"; + _emojiToText["🇲🇸"] = ":flag_ms:"; + _textToEmoji[":flag_ma:"] = "🇲🇦"; + _emojiToText["🇲🇦"] = ":flag_ma:"; + _textToEmoji[":flag_mz:"] = "🇲🇿"; + _emojiToText["🇲🇿"] = ":flag_mz:"; + _textToEmoji[":flag_mm:"] = "🇲🇲"; + _emojiToText["🇲🇲"] = ":flag_mm:"; + _textToEmoji[":flag_na:"] = "🇳🇦"; + _emojiToText["🇳🇦"] = ":flag_na:"; + _textToEmoji[":flag_nr:"] = "🇳🇷"; + _emojiToText["🇳🇷"] = ":flag_nr:"; + _textToEmoji[":flag_np:"] = "🇳🇵"; + _emojiToText["🇳🇵"] = ":flag_np:"; + _textToEmoji[":flag_nl:"] = "🇳🇱"; + _emojiToText["🇳🇱"] = ":flag_nl:"; + _textToEmoji[":flag_nc:"] = "🇳🇨"; + _emojiToText["🇳🇨"] = ":flag_nc:"; + _textToEmoji[":flag_nz:"] = "🇳🇿"; + _emojiToText["🇳🇿"] = ":flag_nz:"; + _textToEmoji[":flag_ni:"] = "🇳🇮"; + _emojiToText["🇳🇮"] = ":flag_ni:"; + _textToEmoji[":flag_ne:"] = "🇳🇪"; + _emojiToText["🇳🇪"] = ":flag_ne:"; + _textToEmoji[":flag_ng:"] = "🇳🇬"; + _emojiToText["🇳🇬"] = ":flag_ng:"; + _textToEmoji[":flag_nu:"] = "🇳🇺"; + _emojiToText["🇳🇺"] = ":flag_nu:"; + _textToEmoji[":flag_nf:"] = "🇳🇫"; + _emojiToText["🇳🇫"] = ":flag_nf:"; + _textToEmoji[":flag_kp:"] = "🇰🇵"; + _emojiToText["🇰🇵"] = ":flag_kp:"; + _textToEmoji[":flag_mp:"] = "🇲🇵"; + _emojiToText["🇲🇵"] = ":flag_mp:"; + _textToEmoji[":flag_no:"] = "🇳🇴"; + _emojiToText["🇳🇴"] = ":flag_no:"; + _textToEmoji[":flag_om:"] = "🇴🇲"; + _emojiToText["🇴🇲"] = ":flag_om:"; + _textToEmoji[":flag_pk:"] = "🇵🇰"; + _emojiToText["🇵🇰"] = ":flag_pk:"; + _textToEmoji[":flag_pw:"] = "🇵🇼"; + _emojiToText["🇵🇼"] = ":flag_pw:"; + _textToEmoji[":flag_ps:"] = "🇵🇸"; + _emojiToText["🇵🇸"] = ":flag_ps:"; + _textToEmoji[":flag_pa:"] = "🇵🇦"; + _emojiToText["🇵🇦"] = ":flag_pa:"; + _textToEmoji[":flag_pg:"] = "🇵🇬"; + _emojiToText["🇵🇬"] = ":flag_pg:"; + _textToEmoji[":flag_py:"] = "🇵🇾"; + _emojiToText["🇵🇾"] = ":flag_py:"; + _textToEmoji[":flag_pe:"] = "🇵🇪"; + _emojiToText["🇵🇪"] = ":flag_pe:"; + _textToEmoji[":flag_ph:"] = "🇵🇭"; + _emojiToText["🇵🇭"] = ":flag_ph:"; + _textToEmoji[":flag_pn:"] = "🇵🇳"; + _emojiToText["🇵🇳"] = ":flag_pn:"; + _textToEmoji[":flag_pl:"] = "🇵🇱"; + _emojiToText["🇵🇱"] = ":flag_pl:"; + _textToEmoji[":flag_pt:"] = "🇵🇹"; + _emojiToText["🇵🇹"] = ":flag_pt:"; + _textToEmoji[":flag_pr:"] = "🇵🇷"; + _emojiToText["🇵🇷"] = ":flag_pr:"; + _textToEmoji[":flag_qa:"] = "🇶🇦"; + _emojiToText["🇶🇦"] = ":flag_qa:"; + _textToEmoji[":flag_re:"] = "🇷🇪"; + _emojiToText["🇷🇪"] = ":flag_re:"; + _textToEmoji[":flag_ro:"] = "🇷🇴"; + _emojiToText["🇷🇴"] = ":flag_ro:"; + _textToEmoji[":flag_ru:"] = "🇷🇺"; + _emojiToText["🇷🇺"] = ":flag_ru:"; + _textToEmoji[":flag_rw:"] = "🇷🇼"; + _emojiToText["🇷🇼"] = ":flag_rw:"; + _textToEmoji[":flag_ws:"] = "🇼🇸"; + _emojiToText["🇼🇸"] = ":flag_ws:"; + _textToEmoji[":flag_sm:"] = "🇸🇲"; + _emojiToText["🇸🇲"] = ":flag_sm:"; + _textToEmoji[":flag_st:"] = "🇸🇹"; + _emojiToText["🇸🇹"] = ":flag_st:"; + _textToEmoji[":flag_sa:"] = "🇸🇦"; + _emojiToText["🇸🇦"] = ":flag_sa:"; + _textToEmoji[":flag_sn:"] = "🇸🇳"; + _emojiToText["🇸🇳"] = ":flag_sn:"; + _textToEmoji[":flag_rs:"] = "🇷🇸"; + _emojiToText["🇷🇸"] = ":flag_rs:"; + _textToEmoji[":flag_sc:"] = "🇸🇨"; + _emojiToText["🇸🇨"] = ":flag_sc:"; + _textToEmoji[":flag_sl:"] = "🇸🇱"; + _emojiToText["🇸🇱"] = ":flag_sl:"; + _textToEmoji[":flag_sg:"] = "🇸🇬"; + _emojiToText["🇸🇬"] = ":flag_sg:"; + _textToEmoji[":flag_sx:"] = "🇸🇽"; + _emojiToText["🇸🇽"] = ":flag_sx:"; + _textToEmoji[":flag_sk:"] = "🇸🇰"; + _emojiToText["🇸🇰"] = ":flag_sk:"; + _textToEmoji[":flag_si:"] = "🇸🇮"; + _emojiToText["🇸🇮"] = ":flag_si:"; + _textToEmoji[":flag_gs:"] = "🇬🇸"; + _emojiToText["🇬🇸"] = ":flag_gs:"; + _textToEmoji[":flag_sb:"] = "🇸🇧"; + _emojiToText["🇸🇧"] = ":flag_sb:"; + _textToEmoji[":flag_so:"] = "🇸🇴"; + _emojiToText["🇸🇴"] = ":flag_so:"; + _textToEmoji[":flag_za:"] = "🇿🇦"; + _emojiToText["🇿🇦"] = ":flag_za:"; + _textToEmoji[":flag_kr:"] = "🇰🇷"; + _emojiToText["🇰🇷"] = ":flag_kr:"; + _textToEmoji[":flag_ss:"] = "🇸🇸"; + _emojiToText["🇸🇸"] = ":flag_ss:"; + _textToEmoji[":flag_es:"] = "🇪🇸"; + _emojiToText["🇪🇸"] = ":flag_es:"; + _textToEmoji[":flag_lk:"] = "🇱🇰"; + _emojiToText["🇱🇰"] = ":flag_lk:"; + _textToEmoji[":flag_bl:"] = "🇧🇱"; + _emojiToText["🇧🇱"] = ":flag_bl:"; + _textToEmoji[":flag_sh:"] = "🇸🇭"; + _emojiToText["🇸🇭"] = ":flag_sh:"; + _textToEmoji[":flag_kn:"] = "🇰🇳"; + _emojiToText["🇰🇳"] = ":flag_kn:"; + _textToEmoji[":flag_lc:"] = "🇱🇨"; + _emojiToText["🇱🇨"] = ":flag_lc:"; + _textToEmoji[":flag_pm:"] = "🇵🇲"; + _emojiToText["🇵🇲"] = ":flag_pm:"; + _textToEmoji[":flag_vc:"] = "🇻🇨"; + _emojiToText["🇻🇨"] = ":flag_vc:"; + _textToEmoji[":flag_sd:"] = "🇸🇩"; + _emojiToText["🇸🇩"] = ":flag_sd:"; + _textToEmoji[":flag_sr:"] = "🇸🇷"; + _emojiToText["🇸🇷"] = ":flag_sr:"; + _textToEmoji[":flag_sz:"] = "🇸🇿"; + _emojiToText["🇸🇿"] = ":flag_sz:"; + _textToEmoji[":flag_se:"] = "🇸🇪"; + _emojiToText["🇸🇪"] = ":flag_se:"; + _textToEmoji[":flag_ch:"] = "🇨🇭"; + _emojiToText["🇨🇭"] = ":flag_ch:"; + _textToEmoji[":flag_sy:"] = "🇸🇾"; + _emojiToText["🇸🇾"] = ":flag_sy:"; + _textToEmoji[":flag_tw:"] = "🇹🇼"; + _emojiToText["🇹🇼"] = ":flag_tw:"; + _textToEmoji[":flag_tj:"] = "🇹🇯"; + _emojiToText["🇹🇯"] = ":flag_tj:"; + _textToEmoji[":flag_tz:"] = "🇹🇿"; + _emojiToText["🇹🇿"] = ":flag_tz:"; + _textToEmoji[":flag_th:"] = "🇹🇭"; + _emojiToText["🇹🇭"] = ":flag_th:"; + _textToEmoji[":flag_tl:"] = "🇹🇱"; + _emojiToText["🇹🇱"] = ":flag_tl:"; + _textToEmoji[":flag_tg:"] = "🇹🇬"; + _emojiToText["🇹🇬"] = ":flag_tg:"; + _textToEmoji[":flag_tk:"] = "🇹🇰"; + _emojiToText["🇹🇰"] = ":flag_tk:"; + _textToEmoji[":flag_to:"] = "🇹🇴"; + _emojiToText["🇹🇴"] = ":flag_to:"; + _textToEmoji[":flag_tt:"] = "🇹🇹"; + _emojiToText["🇹🇹"] = ":flag_tt:"; + _textToEmoji[":flag_tn:"] = "🇹🇳"; + _emojiToText["🇹🇳"] = ":flag_tn:"; + _textToEmoji[":flag_tr:"] = "🇹🇷"; + _emojiToText["🇹🇷"] = ":flag_tr:"; + _textToEmoji[":flag_tm:"] = "🇹🇲"; + _emojiToText["🇹🇲"] = ":flag_tm:"; + _textToEmoji[":flag_tc:"] = "🇹🇨"; + _emojiToText["🇹🇨"] = ":flag_tc:"; + _textToEmoji[":flag_vi:"] = "🇻🇮"; + _emojiToText["🇻🇮"] = ":flag_vi:"; + _textToEmoji[":flag_tv:"] = "🇹🇻"; + _emojiToText["🇹🇻"] = ":flag_tv:"; + _textToEmoji[":flag_ug:"] = "🇺🇬"; + _emojiToText["🇺🇬"] = ":flag_ug:"; + _textToEmoji[":flag_ua:"] = "🇺🇦"; + _emojiToText["🇺🇦"] = ":flag_ua:"; + _textToEmoji[":flag_ae:"] = "🇦🇪"; + _emojiToText["🇦🇪"] = ":flag_ae:"; + _textToEmoji[":flag_gb:"] = "🇬🇧"; + _emojiToText["🇬🇧"] = ":flag_gb:"; + _textToEmoji[":england:"] = "🏴󠁧󠁢󠁥󠁮󠁧󠁿"; + _emojiToText["🏴󠁧󠁢󠁥󠁮󠁧󠁿"] = ":england:"; + _textToEmoji[":scotland:"] = "🏴󠁧󠁢󠁳󠁣󠁴󠁿"; + _emojiToText["🏴󠁧󠁢󠁳󠁣󠁴󠁿"] = ":scotland:"; + _textToEmoji[":wales:"] = "🏴󠁧󠁢󠁷󠁬󠁳󠁿"; + _emojiToText["🏴󠁧󠁢󠁷󠁬󠁳󠁿"] = ":wales:"; + _textToEmoji[":flag_us:"] = "🇺🇸"; + _emojiToText["🇺🇸"] = ":flag_us:"; + _textToEmoji[":flag_uy:"] = "🇺🇾"; + _emojiToText["🇺🇾"] = ":flag_uy:"; + _textToEmoji[":flag_uz:"] = "🇺🇿"; + _emojiToText["🇺🇿"] = ":flag_uz:"; + _textToEmoji[":flag_vu:"] = "🇻🇺"; + _emojiToText["🇻🇺"] = ":flag_vu:"; + _textToEmoji[":flag_va:"] = "🇻🇦"; + _emojiToText["🇻🇦"] = ":flag_va:"; + _textToEmoji[":flag_ve:"] = "🇻🇪"; + _emojiToText["🇻🇪"] = ":flag_ve:"; + _textToEmoji[":flag_vn:"] = "🇻🇳"; + _emojiToText["🇻🇳"] = ":flag_vn:"; + _textToEmoji[":flag_wf:"] = "🇼🇫"; + _emojiToText["🇼🇫"] = ":flag_wf:"; + _textToEmoji[":flag_eh:"] = "🇪🇭"; + _emojiToText["🇪🇭"] = ":flag_eh:"; + _textToEmoji[":flag_ye:"] = "🇾🇪"; + _emojiToText["🇾🇪"] = ":flag_ye:"; + _textToEmoji[":flag_zm:"] = "🇿🇲"; + _emojiToText["🇿🇲"] = ":flag_zm:"; + _textToEmoji[":flag_zw:"] = "🇿🇼"; + _emojiToText["🇿🇼"] = ":flag_zw:"; + _textToEmoji[":flag_ac:"] = "🇦🇨"; + _emojiToText["🇦🇨"] = ":flag_ac:"; + _textToEmoji[":flag_bv:"] = "🇧🇻"; + _emojiToText["🇧🇻"] = ":flag_bv:"; + _textToEmoji[":flag_cp:"] = "🇨🇵"; + _emojiToText["🇨🇵"] = ":flag_cp:"; + _textToEmoji[":flag_ea:"] = "🇪🇦"; + _emojiToText["🇪🇦"] = ":flag_ea:"; + _textToEmoji[":flag_dg:"] = "🇩🇬"; + _emojiToText["🇩🇬"] = ":flag_dg:"; + _textToEmoji[":flag_hm:"] = "🇭🇲"; + _emojiToText["🇭🇲"] = ":flag_hm:"; + _textToEmoji[":flag_mf:"] = "🇲🇫"; + _emojiToText["🇲🇫"] = ":flag_mf:"; + _textToEmoji[":flag_sj:"] = "🇸🇯"; + _emojiToText["🇸🇯"] = ":flag_sj:"; + _textToEmoji[":flag_ta:"] = "🇹🇦"; + _emojiToText["🇹🇦"] = ":flag_ta:"; + _textToEmoji[":flag_um:"] = "🇺🇲"; + _emojiToText["🇺🇲"] = ":flag_um:"; + _textToEmoji[":green_apple:"] = "🍏"; + _emojiToText["🍏"] = ":green_apple:"; + _textToEmoji[":apple:"] = "🍎"; + _emojiToText["🍎"] = ":apple:"; + _textToEmoji[":red_apple:"] = "🍎"; + _emojiToText["🍎"] = ":red_apple:"; + _textToEmoji[":pear:"] = "🍐"; + _emojiToText["🍐"] = ":pear:"; + _textToEmoji[":tangerine:"] = "🍊"; + _emojiToText["🍊"] = ":tangerine:"; + _textToEmoji[":lemon:"] = "🍋"; + _emojiToText["🍋"] = ":lemon:"; + _textToEmoji[":banana:"] = "🍌"; + _emojiToText["🍌"] = ":banana:"; + _textToEmoji[":watermelon:"] = "🍉"; + _emojiToText["🍉"] = ":watermelon:"; + _textToEmoji[":grapes:"] = "🍇"; + _emojiToText["🍇"] = ":grapes:"; + _textToEmoji[":strawberry:"] = "🍓"; + _emojiToText["🍓"] = ":strawberry:"; + _textToEmoji[":blueberries:"] = "🫐"; + _emojiToText["🫐"] = ":blueberries:"; + _textToEmoji[":melon:"] = "🍈"; + _emojiToText["🍈"] = ":melon:"; + _textToEmoji[":cherries:"] = "🍒"; + _emojiToText["🍒"] = ":cherries:"; + _textToEmoji[":peach:"] = "🍑"; + _emojiToText["🍑"] = ":peach:"; + _textToEmoji[":mango:"] = "🥭"; + _emojiToText["🥭"] = ":mango:"; + _textToEmoji[":pineapple:"] = "🍍"; + _emojiToText["🍍"] = ":pineapple:"; + _textToEmoji[":coconut:"] = "🥥"; + _emojiToText["🥥"] = ":coconut:"; + _textToEmoji[":kiwi:"] = "🥝"; + _emojiToText["🥝"] = ":kiwi:"; + _textToEmoji[":kiwifruit:"] = "🥝"; + _emojiToText["🥝"] = ":kiwifruit:"; + _textToEmoji[":kiwi_fruit:"] = "🥝"; + _emojiToText["🥝"] = ":kiwi_fruit:"; + _textToEmoji[":tomato:"] = "🍅"; + _emojiToText["🍅"] = ":tomato:"; + _textToEmoji[":eggplant:"] = "🍆"; + _emojiToText["🍆"] = ":eggplant:"; + _textToEmoji[":avocado:"] = "🥑"; + _emojiToText["🥑"] = ":avocado:"; + _textToEmoji[":pea_pod:"] = "🫛"; + _emojiToText["🫛"] = ":pea_pod:"; + _textToEmoji[":broccoli:"] = "🥦"; + _emojiToText["🥦"] = ":broccoli:"; + _textToEmoji[":leafy_green:"] = "🥬"; + _emojiToText["🥬"] = ":leafy_green:"; + _textToEmoji[":cucumber:"] = "🥒"; + _emojiToText["🥒"] = ":cucumber:"; + _textToEmoji[":hot_pepper:"] = "🌶️"; + _emojiToText["🌶️"] = ":hot_pepper:"; + _textToEmoji[":bell_pepper:"] = "🫑"; + _emojiToText["🫑"] = ":bell_pepper:"; + _textToEmoji[":corn:"] = "🌽"; + _emojiToText["🌽"] = ":corn:"; + _textToEmoji[":ear_of_corn:"] = "🌽"; + _emojiToText["🌽"] = ":ear_of_corn:"; + _textToEmoji[":carrot:"] = "🥕"; + _emojiToText["🥕"] = ":carrot:"; + _textToEmoji[":olive:"] = "🫒"; + _emojiToText["🫒"] = ":olive:"; + _textToEmoji[":garlic:"] = "🧄"; + _emojiToText["🧄"] = ":garlic:"; + _textToEmoji[":onion:"] = "🧅"; + _emojiToText["🧅"] = ":onion:"; + _textToEmoji[":potato:"] = "🥔"; + _emojiToText["🥔"] = ":potato:"; + _textToEmoji[":sweet_potato:"] = "🍠"; + _emojiToText["🍠"] = ":sweet_potato:"; + _textToEmoji[":ginger_root:"] = "🫚"; + _emojiToText["🫚"] = ":ginger_root:"; + _textToEmoji[":croissant:"] = "🥐"; + _emojiToText["🥐"] = ":croissant:"; + _textToEmoji[":bagel:"] = "🥯"; + _emojiToText["🥯"] = ":bagel:"; + _textToEmoji[":bread:"] = "🍞"; + _emojiToText["🍞"] = ":bread:"; + _textToEmoji[":french_bread:"] = "🥖"; + _emojiToText["🥖"] = ":french_bread:"; + _textToEmoji[":baguette_bread:"] = "🥖"; + _emojiToText["🥖"] = ":baguette_bread:"; + _textToEmoji[":pretzel:"] = "🥨"; + _emojiToText["🥨"] = ":pretzel:"; + _textToEmoji[":cheese:"] = "🧀"; + _emojiToText["🧀"] = ":cheese:"; + _textToEmoji[":cheese_wedge:"] = "🧀"; + _emojiToText["🧀"] = ":cheese_wedge:"; + _textToEmoji[":egg:"] = "🥚"; + _emojiToText["🥚"] = ":egg:"; + _textToEmoji[":cooking:"] = "🍳"; + _emojiToText["🍳"] = ":cooking:"; + _textToEmoji[":butter:"] = "🧈"; + _emojiToText["🧈"] = ":butter:"; + _textToEmoji[":pancakes:"] = "🥞"; + _emojiToText["🥞"] = ":pancakes:"; + _textToEmoji[":waffle:"] = "🧇"; + _emojiToText["🧇"] = ":waffle:"; + _textToEmoji[":bacon:"] = "🥓"; + _emojiToText["🥓"] = ":bacon:"; + _textToEmoji[":cut_of_meat:"] = "🥩"; + _emojiToText["🥩"] = ":cut_of_meat:"; + _textToEmoji[":poultry_leg:"] = "🍗"; + _emojiToText["🍗"] = ":poultry_leg:"; + _textToEmoji[":meat_on_bone:"] = "🍖"; + _emojiToText["🍖"] = ":meat_on_bone:"; + _textToEmoji[":bone:"] = "🦴"; + _emojiToText["🦴"] = ":bone:"; + _textToEmoji[":hotdog:"] = "🌭"; + _emojiToText["🌭"] = ":hotdog:"; + _textToEmoji[":hot_dog:"] = "🌭"; + _emojiToText["🌭"] = ":hot_dog:"; + _textToEmoji[":hamburger:"] = "🍔"; + _emojiToText["🍔"] = ":hamburger:"; + _textToEmoji[":fries:"] = "🍟"; + _emojiToText["🍟"] = ":fries:"; + _textToEmoji[":french_fries:"] = "🍟"; + _emojiToText["🍟"] = ":french_fries:"; + _textToEmoji[":pizza:"] = "🍕"; + _emojiToText["🍕"] = ":pizza:"; + _textToEmoji[":flatbread:"] = "🫓"; + _emojiToText["🫓"] = ":flatbread:"; + _textToEmoji[":sandwich:"] = "🥪"; + _emojiToText["🥪"] = ":sandwich:"; + _textToEmoji[":stuffed_flatbread:"] = "🥙"; + _emojiToText["🥙"] = ":stuffed_flatbread:"; + _textToEmoji[":stuffed_pita:"] = "🥙"; + _emojiToText["🥙"] = ":stuffed_pita:"; + _textToEmoji[":falafel:"] = "🧆"; + _emojiToText["🧆"] = ":falafel:"; + _textToEmoji[":taco:"] = "🌮"; + _emojiToText["🌮"] = ":taco:"; + _textToEmoji[":burrito:"] = "🌯"; + _emojiToText["🌯"] = ":burrito:"; + _textToEmoji[":tamale:"] = "🫔"; + _emojiToText["🫔"] = ":tamale:"; + _textToEmoji[":salad:"] = "🥗"; + _emojiToText["🥗"] = ":salad:"; + _textToEmoji[":green_salad:"] = "🥗"; + _emojiToText["🥗"] = ":green_salad:"; + _textToEmoji[":shallow_pan_of_food:"] = "🥘"; + _emojiToText["🥘"] = ":shallow_pan_of_food:"; + _textToEmoji[":paella:"] = "🥘"; + _emojiToText["🥘"] = ":paella:"; + _textToEmoji[":fondue:"] = "🫕"; + _emojiToText["🫕"] = ":fondue:"; + _textToEmoji[":canned_food:"] = "🥫"; + _emojiToText["🥫"] = ":canned_food:"; + _textToEmoji[":jar:"] = "🫙"; + _emojiToText["🫙"] = ":jar:"; + _textToEmoji[":spaghetti:"] = "🍝"; + _emojiToText["🍝"] = ":spaghetti:"; + _textToEmoji[":ramen:"] = "🍜"; + _emojiToText["🍜"] = ":ramen:"; + _textToEmoji[":steaming_bowl:"] = "🍜"; + _emojiToText["🍜"] = ":steaming_bowl:"; + _textToEmoji[":stew:"] = "🍲"; + _emojiToText["🍲"] = ":stew:"; + _textToEmoji[":pot_of_food:"] = "🍲"; + _emojiToText["🍲"] = ":pot_of_food:"; + _textToEmoji[":curry:"] = "🍛"; + _emojiToText["🍛"] = ":curry:"; + _textToEmoji[":curry_rice:"] = "🍛"; + _emojiToText["🍛"] = ":curry_rice:"; + _textToEmoji[":sushi:"] = "🍣"; + _emojiToText["🍣"] = ":sushi:"; + _textToEmoji[":bento:"] = "🍱"; + _emojiToText["🍱"] = ":bento:"; + _textToEmoji[":bento_box:"] = "🍱"; + _emojiToText["🍱"] = ":bento_box:"; + _textToEmoji[":dumpling:"] = "🥟"; + _emojiToText["🥟"] = ":dumpling:"; + _textToEmoji[":oyster:"] = "🦪"; + _emojiToText["🦪"] = ":oyster:"; + _textToEmoji[":fried_shrimp:"] = "🍤"; + _emojiToText["🍤"] = ":fried_shrimp:"; + _textToEmoji[":rice_ball:"] = "🍙"; + _emojiToText["🍙"] = ":rice_ball:"; + _textToEmoji[":rice:"] = "🍚"; + _emojiToText["🍚"] = ":rice:"; + _textToEmoji[":cooked_rice:"] = "🍚"; + _emojiToText["🍚"] = ":cooked_rice:"; + _textToEmoji[":rice_cracker:"] = "🍘"; + _emojiToText["🍘"] = ":rice_cracker:"; + _textToEmoji[":fish_cake:"] = "🍥"; + _emojiToText["🍥"] = ":fish_cake:"; + _textToEmoji[":fortune_cookie:"] = "🥠"; + _emojiToText["🥠"] = ":fortune_cookie:"; + _textToEmoji[":moon_cake:"] = "🥮"; + _emojiToText["🥮"] = ":moon_cake:"; + _textToEmoji[":oden:"] = "🍢"; + _emojiToText["🍢"] = ":oden:"; + _textToEmoji[":dango:"] = "🍡"; + _emojiToText["🍡"] = ":dango:"; + _textToEmoji[":shaved_ice:"] = "🍧"; + _emojiToText["🍧"] = ":shaved_ice:"; + _textToEmoji[":ice_cream:"] = "🍨"; + _emojiToText["🍨"] = ":ice_cream:"; + _textToEmoji[":icecream:"] = "🍦"; + _emojiToText["🍦"] = ":icecream:"; + _textToEmoji[":pie:"] = "🥧"; + _emojiToText["🥧"] = ":pie:"; + _textToEmoji[":cupcake:"] = "🧁"; + _emojiToText["🧁"] = ":cupcake:"; + _textToEmoji[":cake:"] = "🍰"; + _emojiToText["🍰"] = ":cake:"; + _textToEmoji[":shortcake:"] = "🍰"; + _emojiToText["🍰"] = ":shortcake:"; + _textToEmoji[":birthday:"] = "🎂"; + _emojiToText["🎂"] = ":birthday:"; + _textToEmoji[":birthday_cake:"] = "🎂"; + _emojiToText["🎂"] = ":birthday_cake:"; + _textToEmoji[":custard:"] = "🍮"; + _emojiToText["🍮"] = ":custard:"; + _textToEmoji[":pudding:"] = "🍮"; + _emojiToText["🍮"] = ":pudding:"; + _textToEmoji[":flan:"] = "🍮"; + _emojiToText["🍮"] = ":flan:"; + _textToEmoji[":lollipop:"] = "🍭"; + _emojiToText["🍭"] = ":lollipop:"; + _textToEmoji[":candy:"] = "🍬"; + _emojiToText["🍬"] = ":candy:"; + _textToEmoji[":chocolate_bar:"] = "🍫"; + _emojiToText["🍫"] = ":chocolate_bar:"; + _textToEmoji[":popcorn:"] = "🍿"; + _emojiToText["🍿"] = ":popcorn:"; + _textToEmoji[":doughnut:"] = "🍩"; + _emojiToText["🍩"] = ":doughnut:"; + _textToEmoji[":cookie:"] = "🍪"; + _emojiToText["🍪"] = ":cookie:"; + _textToEmoji[":chestnut:"] = "🌰"; + _emojiToText["🌰"] = ":chestnut:"; + _textToEmoji[":peanuts:"] = "🥜"; + _emojiToText["🥜"] = ":peanuts:"; + _textToEmoji[":shelled_peanut:"] = "🥜"; + _emojiToText["🥜"] = ":shelled_peanut:"; + _textToEmoji[":beans:"] = "🫘"; + _emojiToText["🫘"] = ":beans:"; + _textToEmoji[":honey_pot:"] = "🍯"; + _emojiToText["🍯"] = ":honey_pot:"; + _textToEmoji[":milk:"] = "🥛"; + _emojiToText["🥛"] = ":milk:"; + _textToEmoji[":glass_of_milk:"] = "🥛"; + _emojiToText["🥛"] = ":glass_of_milk:"; + _textToEmoji[":pouring_liquid:"] = "🫗"; + _emojiToText["🫗"] = ":pouring_liquid:"; + _textToEmoji[":baby_bottle:"] = "🍼"; + _emojiToText["🍼"] = ":baby_bottle:"; + _textToEmoji[":teapot:"] = "🫖"; + _emojiToText["🫖"] = ":teapot:"; + _textToEmoji[":coffee:"] = "☕"; + _emojiToText["☕"] = ":coffee:"; + _textToEmoji[":hot_beverage:"] = "☕"; + _emojiToText["☕"] = ":hot_beverage:"; + _textToEmoji[":tea:"] = "🍵"; + _emojiToText["🍵"] = ":tea:"; + _textToEmoji[":mate:"] = "🧉"; + _emojiToText["🧉"] = ":mate:"; + _textToEmoji[":beverage_box:"] = "🧃"; + _emojiToText["🧃"] = ":beverage_box:"; + _textToEmoji[":cup_with_straw:"] = "🥤"; + _emojiToText["🥤"] = ":cup_with_straw:"; + _textToEmoji[":bubble_tea:"] = "🧋"; + _emojiToText["🧋"] = ":bubble_tea:"; + _textToEmoji[":sake:"] = "🍶"; + _emojiToText["🍶"] = ":sake:"; + _textToEmoji[":beer:"] = "🍺"; + _emojiToText["🍺"] = ":beer:"; + _textToEmoji[":beer_mug:"] = "🍺"; + _emojiToText["🍺"] = ":beer_mug:"; + _textToEmoji[":beers:"] = "🍻"; + _emojiToText["🍻"] = ":beers:"; + _textToEmoji[":champagne_glass:"] = "🥂"; + _emojiToText["🥂"] = ":champagne_glass:"; + _textToEmoji[":clinking_glass:"] = "🥂"; + _emojiToText["🥂"] = ":clinking_glass:"; + _textToEmoji[":wine_glass:"] = "🍷"; + _emojiToText["🍷"] = ":wine_glass:"; + _textToEmoji[":tumbler_glass:"] = "🥃"; + _emojiToText["🥃"] = ":tumbler_glass:"; + _textToEmoji[":whisky:"] = "🥃"; + _emojiToText["🥃"] = ":whisky:"; + _textToEmoji[":cocktail:"] = "🍸"; + _emojiToText["🍸"] = ":cocktail:"; + _textToEmoji[":tropical_drink:"] = "🍹"; + _emojiToText["🍹"] = ":tropical_drink:"; + _textToEmoji[":champagne:"] = "🍾"; + _emojiToText["🍾"] = ":champagne:"; + _textToEmoji[":bottle_with_popping_cork:"] = "🍾"; + _emojiToText["🍾"] = ":bottle_with_popping_cork:"; + _textToEmoji[":ice_cube:"] = "🧊"; + _emojiToText["🧊"] = ":ice_cube:"; + _textToEmoji[":spoon:"] = "🥄"; + _emojiToText["🥄"] = ":spoon:"; + _textToEmoji[":fork_and_knife:"] = "🍴"; + _emojiToText["🍴"] = ":fork_and_knife:"; + _textToEmoji[":fork_knife_plate:"] = "🍽️"; + _emojiToText["🍽️"] = ":fork_knife_plate:"; + _textToEmoji[":fork_and_knife_with_plate:"] = "🍽️"; + _emojiToText["🍽️"] = ":fork_and_knife_with_plate:"; + _textToEmoji[":bowl_with_spoon:"] = "🥣"; + _emojiToText["🥣"] = ":bowl_with_spoon:"; + _textToEmoji[":takeout_box:"] = "🥡"; + _emojiToText["🥡"] = ":takeout_box:"; + _textToEmoji[":chopsticks:"] = "🥢"; + _emojiToText["🥢"] = ":chopsticks:"; + _textToEmoji[":salt:"] = "🧂"; + _emojiToText["🧂"] = ":salt:"; + _textToEmoji[":dog:"] = "🐶"; + _emojiToText["🐶"] = ":dog:"; + _textToEmoji[":dog_face:"] = "🐶"; + _emojiToText["🐶"] = ":dog_face:"; + _textToEmoji[":cat:"] = "🐱"; + _emojiToText["🐱"] = ":cat:"; + _textToEmoji[":cat_face:"] = "🐱"; + _emojiToText["🐱"] = ":cat_face:"; + _textToEmoji[":mouse:"] = "🐭"; + _emojiToText["🐭"] = ":mouse:"; + _textToEmoji[":mouse_face:"] = "🐭"; + _emojiToText["🐭"] = ":mouse_face:"; + _textToEmoji[":hamster:"] = "🐹"; + _emojiToText["🐹"] = ":hamster:"; + _textToEmoji[":rabbit:"] = "🐰"; + _emojiToText["🐰"] = ":rabbit:"; + _textToEmoji[":rabbit_face:"] = "🐰"; + _emojiToText["🐰"] = ":rabbit_face:"; + _textToEmoji[":fox:"] = "🦊"; + _emojiToText["🦊"] = ":fox:"; + _textToEmoji[":fox_face:"] = "🦊"; + _emojiToText["🦊"] = ":fox_face:"; + _textToEmoji[":bear:"] = "🐻"; + _emojiToText["🐻"] = ":bear:"; + _textToEmoji[":panda_face:"] = "🐼"; + _emojiToText["🐼"] = ":panda_face:"; + _textToEmoji[":panda:"] = "🐼"; + _emojiToText["🐼"] = ":panda:"; + _textToEmoji[":polar_bear:"] = "🐻‍❄️"; + _emojiToText["🐻‍❄️"] = ":polar_bear:"; + _textToEmoji[":koala:"] = "🐨"; + _emojiToText["🐨"] = ":koala:"; + _textToEmoji[":tiger:"] = "🐯"; + _emojiToText["🐯"] = ":tiger:"; + _textToEmoji[":tiger_face:"] = "🐯"; + _emojiToText["🐯"] = ":tiger_face:"; + _textToEmoji[":lion_face:"] = "🦁"; + _emojiToText["🦁"] = ":lion_face:"; + _textToEmoji[":lion:"] = "🦁"; + _emojiToText["🦁"] = ":lion:"; + _textToEmoji[":cow:"] = "🐮"; + _emojiToText["🐮"] = ":cow:"; + _textToEmoji[":cow_face:"] = "🐮"; + _emojiToText["🐮"] = ":cow_face:"; + _textToEmoji[":pig:"] = "🐷"; + _emojiToText["🐷"] = ":pig:"; + _textToEmoji[":pig_face:"] = "🐷"; + _emojiToText["🐷"] = ":pig_face:"; + _textToEmoji[":pig_nose:"] = "🐽"; + _emojiToText["🐽"] = ":pig_nose:"; + _textToEmoji[":frog:"] = "🐸"; + _emojiToText["🐸"] = ":frog:"; + _textToEmoji[":monkey_face:"] = "🐵"; + _emojiToText["🐵"] = ":monkey_face:"; + _textToEmoji[":see_no_evil:"] = "🙈"; + _emojiToText["🙈"] = ":see_no_evil:"; + _textToEmoji[":hear_no_evil:"] = "🙉"; + _emojiToText["🙉"] = ":hear_no_evil:"; + _textToEmoji[":speak_no_evil:"] = "🙊"; + _emojiToText["🙊"] = ":speak_no_evil:"; + _textToEmoji[":monkey:"] = "🐒"; + _emojiToText["🐒"] = ":monkey:"; + _textToEmoji[":chicken:"] = "🐔"; + _emojiToText["🐔"] = ":chicken:"; + _textToEmoji[":penguin:"] = "🐧"; + _emojiToText["🐧"] = ":penguin:"; + _textToEmoji[":bird:"] = "🐦"; + _emojiToText["🐦"] = ":bird:"; + _textToEmoji[":baby_chick:"] = "🐤"; + _emojiToText["🐤"] = ":baby_chick:"; + _textToEmoji[":hatching_chick:"] = "🐣"; + _emojiToText["🐣"] = ":hatching_chick:"; + _textToEmoji[":hatched_chick:"] = "🐥"; + _emojiToText["🐥"] = ":hatched_chick:"; + _textToEmoji[":goose:"] = "🪿"; + _emojiToText["🪿"] = ":goose:"; + _textToEmoji[":duck:"] = "🦆"; + _emojiToText["🦆"] = ":duck:"; + _textToEmoji[":black_bird:"] = "🐦‍⬛"; + _emojiToText["🐦‍⬛"] = ":black_bird:"; + _textToEmoji[":eagle:"] = "🦅"; + _emojiToText["🦅"] = ":eagle:"; + _textToEmoji[":owl:"] = "🦉"; + _emojiToText["🦉"] = ":owl:"; + _textToEmoji[":bat:"] = "🦇"; + _emojiToText["🦇"] = ":bat:"; + _textToEmoji[":wolf:"] = "🐺"; + _emojiToText["🐺"] = ":wolf:"; + _textToEmoji[":boar:"] = "🐗"; + _emojiToText["🐗"] = ":boar:"; + _textToEmoji[":horse:"] = "🐴"; + _emojiToText["🐴"] = ":horse:"; + _textToEmoji[":horse_face:"] = "🐴"; + _emojiToText["🐴"] = ":horse_face:"; + _textToEmoji[":unicorn:"] = "🦄"; + _emojiToText["🦄"] = ":unicorn:"; + _textToEmoji[":unicorn_face:"] = "🦄"; + _emojiToText["🦄"] = ":unicorn_face:"; + _textToEmoji[":moose:"] = "🫎"; + _emojiToText["🫎"] = ":moose:"; + _textToEmoji[":bee:"] = "🐝"; + _emojiToText["🐝"] = ":bee:"; + _textToEmoji[":honeybee:"] = "🐝"; + _emojiToText["🐝"] = ":honeybee:"; + _textToEmoji[":worm:"] = "🪱"; + _emojiToText["🪱"] = ":worm:"; + _textToEmoji[":bug:"] = "🐛"; + _emojiToText["🐛"] = ":bug:"; + _textToEmoji[":butterfly:"] = "🦋"; + _emojiToText["🦋"] = ":butterfly:"; + _textToEmoji[":snail:"] = "🐌"; + _emojiToText["🐌"] = ":snail:"; + _textToEmoji[":lady_beetle:"] = "🐞"; + _emojiToText["🐞"] = ":lady_beetle:"; + _textToEmoji[":ant:"] = "🐜"; + _emojiToText["🐜"] = ":ant:"; + _textToEmoji[":fly:"] = "🪰"; + _emojiToText["🪰"] = ":fly:"; + _textToEmoji[":beetle:"] = "🪲"; + _emojiToText["🪲"] = ":beetle:"; + _textToEmoji[":cockroach:"] = "🪳"; + _emojiToText["🪳"] = ":cockroach:"; + _textToEmoji[":mosquito:"] = "🦟"; + _emojiToText["🦟"] = ":mosquito:"; + _textToEmoji[":cricket:"] = "🦗"; + _emojiToText["🦗"] = ":cricket:"; + _textToEmoji[":spider:"] = "🕷️"; + _emojiToText["🕷️"] = ":spider:"; + _textToEmoji[":spider_web:"] = "🕸️"; + _emojiToText["🕸️"] = ":spider_web:"; + _textToEmoji[":scorpion:"] = "🦂"; + _emojiToText["🦂"] = ":scorpion:"; + _textToEmoji[":turtle:"] = "🐢"; + _emojiToText["🐢"] = ":turtle:"; + _textToEmoji[":snake:"] = "🐍"; + _emojiToText["🐍"] = ":snake:"; + _textToEmoji[":lizard:"] = "🦎"; + _emojiToText["🦎"] = ":lizard:"; + _textToEmoji[":t_rex:"] = "🦖"; + _emojiToText["🦖"] = ":t_rex:"; + _textToEmoji[":sauropod:"] = "🦕"; + _emojiToText["🦕"] = ":sauropod:"; + _textToEmoji[":octopus:"] = "🐙"; + _emojiToText["🐙"] = ":octopus:"; + _textToEmoji[":squid:"] = "🦑"; + _emojiToText["🦑"] = ":squid:"; + _textToEmoji[":jellyfish:"] = "🪼"; + _emojiToText["🪼"] = ":jellyfish:"; + _textToEmoji[":shrimp:"] = "🦐"; + _emojiToText["🦐"] = ":shrimp:"; + _textToEmoji[":lobster:"] = "🦞"; + _emojiToText["🦞"] = ":lobster:"; + _textToEmoji[":crab:"] = "🦀"; + _emojiToText["🦀"] = ":crab:"; + _textToEmoji[":blowfish:"] = "🐡"; + _emojiToText["🐡"] = ":blowfish:"; + _textToEmoji[":tropical_fish:"] = "🐠"; + _emojiToText["🐠"] = ":tropical_fish:"; + _textToEmoji[":fish:"] = "🐟"; + _emojiToText["🐟"] = ":fish:"; + _textToEmoji[":dolphin:"] = "🐬"; + _emojiToText["🐬"] = ":dolphin:"; + _textToEmoji[":whale:"] = "🐳"; + _emojiToText["🐳"] = ":whale:"; + _textToEmoji[":whale2:"] = "🐋"; + _emojiToText["🐋"] = ":whale2:"; + _textToEmoji[":shark:"] = "🦈"; + _emojiToText["🦈"] = ":shark:"; + _textToEmoji[":seal:"] = "🦭"; + _emojiToText["🦭"] = ":seal:"; + _textToEmoji[":crocodile:"] = "🐊"; + _emojiToText["🐊"] = ":crocodile:"; + _textToEmoji[":tiger2:"] = "🐅"; + _emojiToText["🐅"] = ":tiger2:"; + _textToEmoji[":leopard:"] = "🐆"; + _emojiToText["🐆"] = ":leopard:"; + _textToEmoji[":zebra:"] = "🦓"; + _emojiToText["🦓"] = ":zebra:"; + _textToEmoji[":gorilla:"] = "🦍"; + _emojiToText["🦍"] = ":gorilla:"; + _textToEmoji[":orangutan:"] = "🦧"; + _emojiToText["🦧"] = ":orangutan:"; + _textToEmoji[":mammoth:"] = "🦣"; + _emojiToText["🦣"] = ":mammoth:"; + _textToEmoji[":elephant:"] = "🐘"; + _emojiToText["🐘"] = ":elephant:"; + _textToEmoji[":hippopotamus:"] = "🦛"; + _emojiToText["🦛"] = ":hippopotamus:"; + _textToEmoji[":rhino:"] = "🦏"; + _emojiToText["🦏"] = ":rhino:"; + _textToEmoji[":rhinoceros:"] = "🦏"; + _emojiToText["🦏"] = ":rhinoceros:"; + _textToEmoji[":dromedary_camel:"] = "🐪"; + _emojiToText["🐪"] = ":dromedary_camel:"; + _textToEmoji[":camel:"] = "🐫"; + _emojiToText["🐫"] = ":camel:"; + _textToEmoji[":giraffe:"] = "🦒"; + _emojiToText["🦒"] = ":giraffe:"; + _textToEmoji[":kangaroo:"] = "🦘"; + _emojiToText["🦘"] = ":kangaroo:"; + _textToEmoji[":bison:"] = "🦬"; + _emojiToText["🦬"] = ":bison:"; + _textToEmoji[":water_buffalo:"] = "🐃"; + _emojiToText["🐃"] = ":water_buffalo:"; + _textToEmoji[":ox:"] = "🐂"; + _emojiToText["🐂"] = ":ox:"; + _textToEmoji[":cow2:"] = "🐄"; + _emojiToText["🐄"] = ":cow2:"; + _textToEmoji[":donkey:"] = "🫏"; + _emojiToText["🫏"] = ":donkey:"; + _textToEmoji[":racehorse:"] = "🐎"; + _emojiToText["🐎"] = ":racehorse:"; + _textToEmoji[":pig2:"] = "🐖"; + _emojiToText["🐖"] = ":pig2:"; + _textToEmoji[":ram:"] = "🐏"; + _emojiToText["🐏"] = ":ram:"; + _textToEmoji[":sheep:"] = "🐑"; + _emojiToText["🐑"] = ":sheep:"; + _textToEmoji[":ewe:"] = "🐑"; + _emojiToText["🐑"] = ":ewe:"; + _textToEmoji[":llama:"] = "🦙"; + _emojiToText["🦙"] = ":llama:"; + _textToEmoji[":goat:"] = "🐐"; + _emojiToText["🐐"] = ":goat:"; + _textToEmoji[":deer:"] = "🦌"; + _emojiToText["🦌"] = ":deer:"; + _textToEmoji[":dog2:"] = "🐕"; + _emojiToText["🐕"] = ":dog2:"; + _textToEmoji[":poodle:"] = "🐩"; + _emojiToText["🐩"] = ":poodle:"; + _textToEmoji[":guide_dog:"] = "🦮"; + _emojiToText["🦮"] = ":guide_dog:"; + _textToEmoji[":service_dog:"] = "🐕‍🦺"; + _emojiToText["🐕‍🦺"] = ":service_dog:"; + _textToEmoji[":cat2:"] = "🐈"; + _emojiToText["🐈"] = ":cat2:"; + _textToEmoji[":black_cat:"] = "🐈‍⬛"; + _emojiToText["🐈‍⬛"] = ":black_cat:"; + _textToEmoji[":feather:"] = "🪶"; + _emojiToText["🪶"] = ":feather:"; + _textToEmoji[":wing:"] = "🪽"; + _emojiToText["🪽"] = ":wing:"; + _textToEmoji[":rooster:"] = "🐓"; + _emojiToText["🐓"] = ":rooster:"; + _textToEmoji[":turkey:"] = "🦃"; + _emojiToText["🦃"] = ":turkey:"; + _textToEmoji[":dodo:"] = "🦤"; + _emojiToText["🦤"] = ":dodo:"; + _textToEmoji[":peacock:"] = "🦚"; + _emojiToText["🦚"] = ":peacock:"; + _textToEmoji[":parrot:"] = "🦜"; + _emojiToText["🦜"] = ":parrot:"; + _textToEmoji[":swan:"] = "🦢"; + _emojiToText["🦢"] = ":swan:"; + _textToEmoji[":flamingo:"] = "🦩"; + _emojiToText["🦩"] = ":flamingo:"; + _textToEmoji[":dove:"] = "🕊️"; + _emojiToText["🕊️"] = ":dove:"; + _textToEmoji[":dove_of_peace:"] = "🕊️"; + _emojiToText["🕊️"] = ":dove_of_peace:"; + _textToEmoji[":rabbit2:"] = "🐇"; + _emojiToText["🐇"] = ":rabbit2:"; + _textToEmoji[":raccoon:"] = "🦝"; + _emojiToText["🦝"] = ":raccoon:"; + _textToEmoji[":skunk:"] = "🦨"; + _emojiToText["🦨"] = ":skunk:"; + _textToEmoji[":badger:"] = "🦡"; + _emojiToText["🦡"] = ":badger:"; + _textToEmoji[":beaver:"] = "🦫"; + _emojiToText["🦫"] = ":beaver:"; + _textToEmoji[":otter:"] = "🦦"; + _emojiToText["🦦"] = ":otter:"; + _textToEmoji[":sloth:"] = "🦥"; + _emojiToText["🦥"] = ":sloth:"; + _textToEmoji[":mouse2:"] = "🐁"; + _emojiToText["🐁"] = ":mouse2:"; + _textToEmoji[":rat:"] = "🐀"; + _emojiToText["🐀"] = ":rat:"; + _textToEmoji[":chipmunk:"] = "🐿️"; + _emojiToText["🐿️"] = ":chipmunk:"; + _textToEmoji[":hedgehog:"] = "🦔"; + _emojiToText["🦔"] = ":hedgehog:"; + _textToEmoji[":feet:"] = "🐾"; + _emojiToText["🐾"] = ":feet:"; + _textToEmoji[":paw_prints:"] = "🐾"; + _emojiToText["🐾"] = ":paw_prints:"; + _textToEmoji[":dragon:"] = "🐉"; + _emojiToText["🐉"] = ":dragon:"; + _textToEmoji[":dragon_face:"] = "🐲"; + _emojiToText["🐲"] = ":dragon_face:"; + _textToEmoji[":cactus:"] = "🌵"; + _emojiToText["🌵"] = ":cactus:"; + _textToEmoji[":christmas_tree:"] = "🎄"; + _emojiToText["🎄"] = ":christmas_tree:"; + _textToEmoji[":evergreen_tree:"] = "🌲"; + _emojiToText["🌲"] = ":evergreen_tree:"; + _textToEmoji[":deciduous_tree:"] = "🌳"; + _emojiToText["🌳"] = ":deciduous_tree:"; + _textToEmoji[":palm_tree:"] = "🌴"; + _emojiToText["🌴"] = ":palm_tree:"; + _textToEmoji[":wood:"] = "🪵"; + _emojiToText["🪵"] = ":wood:"; + _textToEmoji[":seedling:"] = "🌱"; + _emojiToText["🌱"] = ":seedling:"; + _textToEmoji[":herb:"] = "🌿"; + _emojiToText["🌿"] = ":herb:"; + _textToEmoji[":shamrock:"] = "☘️"; + _emojiToText["☘️"] = ":shamrock:"; + _textToEmoji[":four_leaf_clover:"] = "🍀"; + _emojiToText["🍀"] = ":four_leaf_clover:"; + _textToEmoji[":bamboo:"] = "🎍"; + _emojiToText["🎍"] = ":bamboo:"; + _textToEmoji[":potted_plant:"] = "🪴"; + _emojiToText["🪴"] = ":potted_plant:"; + _textToEmoji[":tanabata_tree:"] = "🎋"; + _emojiToText["🎋"] = ":tanabata_tree:"; + _textToEmoji[":leaves:"] = "🍃"; + _emojiToText["🍃"] = ":leaves:"; + _textToEmoji[":fallen_leaf:"] = "🍂"; + _emojiToText["🍂"] = ":fallen_leaf:"; + _textToEmoji[":maple_leaf:"] = "🍁"; + _emojiToText["🍁"] = ":maple_leaf:"; + _textToEmoji[":nest_with_eggs:"] = "🪺"; + _emojiToText["🪺"] = ":nest_with_eggs:"; + _textToEmoji[":empty_nest:"] = "🪹"; + _emojiToText["🪹"] = ":empty_nest:"; + _textToEmoji[":mushroom:"] = "🍄"; + _emojiToText["🍄"] = ":mushroom:"; + _textToEmoji[":shell:"] = "🐚"; + _emojiToText["🐚"] = ":shell:"; + _textToEmoji[":spiral_shell:"] = "🐚"; + _emojiToText["🐚"] = ":spiral_shell:"; + _textToEmoji[":coral:"] = "🪸"; + _emojiToText["🪸"] = ":coral:"; + _textToEmoji[":rock:"] = "🪨"; + _emojiToText["🪨"] = ":rock:"; + _textToEmoji[":ear_of_rice:"] = "🌾"; + _emojiToText["🌾"] = ":ear_of_rice:"; + _textToEmoji[":sheaf_of_rice:"] = "🌾"; + _emojiToText["🌾"] = ":sheaf_of_rice:"; + _textToEmoji[":bouquet:"] = "💐"; + _emojiToText["💐"] = ":bouquet:"; + _textToEmoji[":tulip:"] = "🌷"; + _emojiToText["🌷"] = ":tulip:"; + _textToEmoji[":rose:"] = "🌹"; + _emojiToText["🌹"] = ":rose:"; + _textToEmoji[":wilted_rose:"] = "🥀"; + _emojiToText["🥀"] = ":wilted_rose:"; + _textToEmoji[":wilted_flower:"] = "🥀"; + _emojiToText["🥀"] = ":wilted_flower:"; + _textToEmoji[":hyacinth:"] = "🪻"; + _emojiToText["🪻"] = ":hyacinth:"; + _textToEmoji[":lotus:"] = "🪷"; + _emojiToText["🪷"] = ":lotus:"; + _textToEmoji[":hibiscus:"] = "🌺"; + _emojiToText["🌺"] = ":hibiscus:"; + _textToEmoji[":cherry_blossom:"] = "🌸"; + _emojiToText["🌸"] = ":cherry_blossom:"; + _textToEmoji[":blossom:"] = "🌼"; + _emojiToText["🌼"] = ":blossom:"; + _textToEmoji[":sunflower:"] = "🌻"; + _emojiToText["🌻"] = ":sunflower:"; + _textToEmoji[":sun_with_face:"] = "🌞"; + _emojiToText["🌞"] = ":sun_with_face:"; + _textToEmoji[":full_moon_with_face:"] = "🌝"; + _emojiToText["🌝"] = ":full_moon_with_face:"; + _textToEmoji[":first_quarter_moon_with_face:"] = "🌛"; + _emojiToText["🌛"] = ":first_quarter_moon_with_face:"; + _textToEmoji[":last_quarter_moon_with_face:"] = "🌜"; + _emojiToText["🌜"] = ":last_quarter_moon_with_face:"; + _textToEmoji[":new_moon_with_face:"] = "🌚"; + _emojiToText["🌚"] = ":new_moon_with_face:"; + _textToEmoji[":new_moon_face:"] = "🌚"; + _emojiToText["🌚"] = ":new_moon_face:"; + _textToEmoji[":full_moon:"] = "🌕"; + _emojiToText["🌕"] = ":full_moon:"; + _textToEmoji[":waning_gibbous_moon:"] = "🌖"; + _emojiToText["🌖"] = ":waning_gibbous_moon:"; + _textToEmoji[":last_quarter_moon:"] = "🌗"; + _emojiToText["🌗"] = ":last_quarter_moon:"; + _textToEmoji[":waning_crescent_moon:"] = "🌘"; + _emojiToText["🌘"] = ":waning_crescent_moon:"; + _textToEmoji[":new_moon:"] = "🌑"; + _emojiToText["🌑"] = ":new_moon:"; + _textToEmoji[":waxing_crescent_moon:"] = "🌒"; + _emojiToText["🌒"] = ":waxing_crescent_moon:"; + _textToEmoji[":first_quarter_moon:"] = "🌓"; + _emojiToText["🌓"] = ":first_quarter_moon:"; + _textToEmoji[":waxing_gibbous_moon:"] = "🌔"; + _emojiToText["🌔"] = ":waxing_gibbous_moon:"; + _textToEmoji[":crescent_moon:"] = "🌙"; + _emojiToText["🌙"] = ":crescent_moon:"; + _textToEmoji[":earth_americas:"] = "🌎"; + _emojiToText["🌎"] = ":earth_americas:"; + _textToEmoji[":earth_africa:"] = "🌍"; + _emojiToText["🌍"] = ":earth_africa:"; + _textToEmoji[":earth_asia:"] = "🌏"; + _emojiToText["🌏"] = ":earth_asia:"; + _textToEmoji[":ringed_planet:"] = "🪐"; + _emojiToText["🪐"] = ":ringed_planet:"; + _textToEmoji[":dizzy:"] = "💫"; + _emojiToText["💫"] = ":dizzy:"; + _textToEmoji[":star:"] = "⭐"; + _emojiToText["⭐"] = ":star:"; + _textToEmoji[":star2:"] = "🌟"; + _emojiToText["🌟"] = ":star2:"; + _textToEmoji[":glowing_star:"] = "🌟"; + _emojiToText["🌟"] = ":glowing_star:"; + _textToEmoji[":sparkles:"] = "✨"; + _emojiToText["✨"] = ":sparkles:"; + _textToEmoji[":zap:"] = "⚡"; + _emojiToText["⚡"] = ":zap:"; + _textToEmoji[":high_voltage:"] = "⚡"; + _emojiToText["⚡"] = ":high_voltage:"; + _textToEmoji[":comet:"] = "☄️"; + _emojiToText["☄️"] = ":comet:"; + _textToEmoji[":boom:"] = "💥"; + _emojiToText["💥"] = ":boom:"; + _textToEmoji[":collision:"] = "💥"; + _emojiToText["💥"] = ":collision:"; + _textToEmoji[":fire:"] = "🔥"; + _emojiToText["🔥"] = ":fire:"; + _textToEmoji[":flame:"] = "🔥"; + _emojiToText["🔥"] = ":flame:"; + _textToEmoji[":cloud_tornado:"] = "🌪️"; + _emojiToText["🌪️"] = ":cloud_tornado:"; + _textToEmoji[":cloud_with_tornado:"] = "🌪️"; + _emojiToText["🌪️"] = ":cloud_with_tornado:"; + _textToEmoji[":tornado:"] = "🌪️"; + _emojiToText["🌪️"] = ":tornado:"; + _textToEmoji[":rainbow:"] = "🌈"; + _emojiToText["🌈"] = ":rainbow:"; + _textToEmoji[":sunny:"] = "☀️"; + _emojiToText["☀️"] = ":sunny:"; + _textToEmoji[":sun:"] = "☀️"; + _emojiToText["☀️"] = ":sun:"; + _textToEmoji[":white_sun_small_cloud:"] = "🌤️"; + _emojiToText["🌤️"] = ":white_sun_small_cloud:"; + _textToEmoji[":white_sun_with_small_cloud:"] = "🌤️"; + _emojiToText["🌤️"] = ":white_sun_with_small_cloud:"; + _textToEmoji[":partly_sunny:"] = "⛅"; + _emojiToText["⛅"] = ":partly_sunny:"; + _textToEmoji[":white_sun_cloud:"] = "🌥️"; + _emojiToText["🌥️"] = ":white_sun_cloud:"; + _textToEmoji[":white_sun_behind_cloud:"] = "🌥️"; + _emojiToText["🌥️"] = ":white_sun_behind_cloud:"; + _textToEmoji[":cloud:"] = "☁️"; + _emojiToText["☁️"] = ":cloud:"; + _textToEmoji[":white_sun_rain_cloud:"] = "🌦️"; + _emojiToText["🌦️"] = ":white_sun_rain_cloud:"; + _textToEmoji[":white_sun_behind_cloud_with_rain:"] = "🌦️"; + _emojiToText["🌦️"] = ":white_sun_behind_cloud_with_rain:"; + _textToEmoji[":cloud_rain:"] = "🌧️"; + _emojiToText["🌧️"] = ":cloud_rain:"; + _textToEmoji[":cloud_with_rain:"] = "🌧️"; + _emojiToText["🌧️"] = ":cloud_with_rain:"; + _textToEmoji[":thunder_cloud_rain:"] = "⛈️"; + _emojiToText["⛈️"] = ":thunder_cloud_rain:"; + _textToEmoji[":thunder_cloud_and_rain:"] = "⛈️"; + _emojiToText["⛈️"] = ":thunder_cloud_and_rain:"; + _textToEmoji[":cloud_lightning:"] = "🌩️"; + _emojiToText["🌩️"] = ":cloud_lightning:"; + _textToEmoji[":cloud_with_lightning:"] = "🌩️"; + _emojiToText["🌩️"] = ":cloud_with_lightning:"; + _textToEmoji[":cloud_snow:"] = "🌨️"; + _emojiToText["🌨️"] = ":cloud_snow:"; + _textToEmoji[":cloud_with_snow:"] = "🌨️"; + _emojiToText["🌨️"] = ":cloud_with_snow:"; + _textToEmoji[":snowflake:"] = "❄️"; + _emojiToText["❄️"] = ":snowflake:"; + _textToEmoji[":snowman2:"] = "☃️"; + _emojiToText["☃️"] = ":snowman2:"; + _textToEmoji[":snowman:"] = "⛄"; + _emojiToText["⛄"] = ":snowman:"; + _textToEmoji[":wind_blowing_face:"] = "🌬️"; + _emojiToText["🌬️"] = ":wind_blowing_face:"; + _textToEmoji[":wind_face:"] = "🌬️"; + _emojiToText["🌬️"] = ":wind_face:"; + _textToEmoji[":dash:"] = "💨"; + _emojiToText["💨"] = ":dash:"; + _textToEmoji[":dashing_away:"] = "💨"; + _emojiToText["💨"] = ":dashing_away:"; + _textToEmoji[":droplet:"] = "💧"; + _emojiToText["💧"] = ":droplet:"; + _textToEmoji[":sweat_drops:"] = "💦"; + _emojiToText["💦"] = ":sweat_drops:"; + _textToEmoji[":bubbles:"] = "🫧"; + _emojiToText["🫧"] = ":bubbles:"; + _textToEmoji[":umbrella:"] = "☔"; + _emojiToText["☔"] = ":umbrella:"; + _textToEmoji[":umbrella2:"] = "☂️"; + _emojiToText["☂️"] = ":umbrella2:"; + _textToEmoji[":ocean:"] = "🌊"; + _emojiToText["🌊"] = ":ocean:"; + _textToEmoji[":water_wave:"] = "🌊"; + _emojiToText["🌊"] = ":water_wave:"; + _textToEmoji[":fog:"] = "🌫️"; + _emojiToText["🌫️"] = ":fog:"; + _textToEmoji[":watch:"] = "⌚"; + _emojiToText["⌚"] = ":watch:"; + _textToEmoji[":mobile_phone:"] = "📱"; + _emojiToText["📱"] = ":mobile_phone:"; + _textToEmoji[":iphone:"] = "📱"; + _emojiToText["📱"] = ":iphone:"; + _textToEmoji[":calling:"] = "📲"; + _emojiToText["📲"] = ":calling:"; + _textToEmoji[":computer:"] = "💻"; + _emojiToText["💻"] = ":computer:"; + _textToEmoji[":keyboard:"] = "⌨️"; + _emojiToText["⌨️"] = ":keyboard:"; + _textToEmoji[":desktop:"] = "🖥️"; + _emojiToText["🖥️"] = ":desktop:"; + _textToEmoji[":desktop_computer:"] = "🖥️"; + _emojiToText["🖥️"] = ":desktop_computer:"; + _textToEmoji[":printer:"] = "🖨️"; + _emojiToText["🖨️"] = ":printer:"; + _textToEmoji[":mouse_three_button:"] = "🖱️"; + _emojiToText["🖱️"] = ":mouse_three_button:"; + _textToEmoji[":three_button_mouse:"] = "🖱️"; + _emojiToText["🖱️"] = ":three_button_mouse:"; + _textToEmoji[":trackball:"] = "🖲️"; + _emojiToText["🖲️"] = ":trackball:"; + _textToEmoji[":joystick:"] = "🕹️"; + _emojiToText["🕹️"] = ":joystick:"; + _textToEmoji[":compression:"] = "🗜️"; + _emojiToText["🗜️"] = ":compression:"; + _textToEmoji[":clamp:"] = "🗜️"; + _emojiToText["🗜️"] = ":clamp:"; + _textToEmoji[":minidisc:"] = "💽"; + _emojiToText["💽"] = ":minidisc:"; + _textToEmoji[":computer_disk:"] = "💽"; + _emojiToText["💽"] = ":computer_disk:"; + _textToEmoji[":floppy_disk:"] = "💾"; + _emojiToText["💾"] = ":floppy_disk:"; + _textToEmoji[":cd:"] = "💿"; + _emojiToText["💿"] = ":cd:"; + _textToEmoji[":optical_disk:"] = "💿"; + _emojiToText["💿"] = ":optical_disk:"; + _textToEmoji[":dvd:"] = "📀"; + _emojiToText["📀"] = ":dvd:"; + _textToEmoji[":vhs:"] = "📼"; + _emojiToText["📼"] = ":vhs:"; + _textToEmoji[":videocassette:"] = "📼"; + _emojiToText["📼"] = ":videocassette:"; + _textToEmoji[":camera:"] = "📷"; + _emojiToText["📷"] = ":camera:"; + _textToEmoji[":camera_with_flash:"] = "📸"; + _emojiToText["📸"] = ":camera_with_flash:"; + _textToEmoji[":video_camera:"] = "📹"; + _emojiToText["📹"] = ":video_camera:"; + _textToEmoji[":movie_camera:"] = "🎥"; + _emojiToText["🎥"] = ":movie_camera:"; + _textToEmoji[":projector:"] = "📽️"; + _emojiToText["📽️"] = ":projector:"; + _textToEmoji[":film_projector:"] = "📽️"; + _emojiToText["📽️"] = ":film_projector:"; + _textToEmoji[":film_frames:"] = "🎞️"; + _emojiToText["🎞️"] = ":film_frames:"; + _textToEmoji[":telephone_receiver:"] = "📞"; + _emojiToText["📞"] = ":telephone_receiver:"; + _textToEmoji[":telephone:"] = "☎️"; + _emojiToText["☎️"] = ":telephone:"; + _textToEmoji[":pager:"] = "📟"; + _emojiToText["📟"] = ":pager:"; + _textToEmoji[":fax:"] = "📠"; + _emojiToText["📠"] = ":fax:"; + _textToEmoji[":fax_machine:"] = "📠"; + _emojiToText["📠"] = ":fax_machine:"; + _textToEmoji[":tv:"] = "📺"; + _emojiToText["📺"] = ":tv:"; + _textToEmoji[":television:"] = "📺"; + _emojiToText["📺"] = ":television:"; + _textToEmoji[":radio:"] = "📻"; + _emojiToText["📻"] = ":radio:"; + _textToEmoji[":microphone2:"] = "🎙️"; + _emojiToText["🎙️"] = ":microphone2:"; + _textToEmoji[":studio_microphone:"] = "🎙️"; + _emojiToText["🎙️"] = ":studio_microphone:"; + _textToEmoji[":level_slider:"] = "🎚️"; + _emojiToText["🎚️"] = ":level_slider:"; + _textToEmoji[":control_knobs:"] = "🎛️"; + _emojiToText["🎛️"] = ":control_knobs:"; + _textToEmoji[":compass:"] = "🧭"; + _emojiToText["🧭"] = ":compass:"; + _textToEmoji[":stopwatch:"] = "⏱️"; + _emojiToText["⏱️"] = ":stopwatch:"; + _textToEmoji[":timer:"] = "⏲️"; + _emojiToText["⏲️"] = ":timer:"; + _textToEmoji[":timer_clock:"] = "⏲️"; + _emojiToText["⏲️"] = ":timer_clock:"; + _textToEmoji[":alarm_clock:"] = "⏰"; + _emojiToText["⏰"] = ":alarm_clock:"; + _textToEmoji[":clock:"] = "🕰️"; + _emojiToText["🕰️"] = ":clock:"; + _textToEmoji[":mantlepiece_clock:"] = "🕰️"; + _emojiToText["🕰️"] = ":mantlepiece_clock:"; + _textToEmoji[":hourglass:"] = "⌛"; + _emojiToText["⌛"] = ":hourglass:"; + _textToEmoji[":hourglass_flowing_sand:"] = "⏳"; + _emojiToText["⏳"] = ":hourglass_flowing_sand:"; + _textToEmoji[":satellite:"] = "📡"; + _emojiToText["📡"] = ":satellite:"; + _textToEmoji[":battery:"] = "🔋"; + _emojiToText["🔋"] = ":battery:"; + _textToEmoji[":low_battery:"] = "🪫"; + _emojiToText["🪫"] = ":low_battery:"; + _textToEmoji[":electric_plug:"] = "🔌"; + _emojiToText["🔌"] = ":electric_plug:"; + _textToEmoji[":bulb:"] = "💡"; + _emojiToText["💡"] = ":bulb:"; + _textToEmoji[":light_bulb:"] = "💡"; + _emojiToText["💡"] = ":light_bulb:"; + _textToEmoji[":flashlight:"] = "🔦"; + _emojiToText["🔦"] = ":flashlight:"; + _textToEmoji[":candle:"] = "🕯️"; + _emojiToText["🕯️"] = ":candle:"; + _textToEmoji[":diya_lamp:"] = "🪔"; + _emojiToText["🪔"] = ":diya_lamp:"; + _textToEmoji[":fire_extinguisher:"] = "🧯"; + _emojiToText["🧯"] = ":fire_extinguisher:"; + _textToEmoji[":oil:"] = "🛢️"; + _emojiToText["🛢️"] = ":oil:"; + _textToEmoji[":oil_drum:"] = "🛢️"; + _emojiToText["🛢️"] = ":oil_drum:"; + _textToEmoji[":money_with_wings:"] = "💸"; + _emojiToText["💸"] = ":money_with_wings:"; + _textToEmoji[":dollar:"] = "💵"; + _emojiToText["💵"] = ":dollar:"; + _textToEmoji[":yen:"] = "💴"; + _emojiToText["💴"] = ":yen:"; + _textToEmoji[":yen_banknote:"] = "💴"; + _emojiToText["💴"] = ":yen_banknote:"; + _textToEmoji[":euro:"] = "💶"; + _emojiToText["💶"] = ":euro:"; + _textToEmoji[":euro_banknote:"] = "💶"; + _emojiToText["💶"] = ":euro_banknote:"; + _textToEmoji[":pound:"] = "💷"; + _emojiToText["💷"] = ":pound:"; + _textToEmoji[":coin:"] = "🪙"; + _emojiToText["🪙"] = ":coin:"; + _textToEmoji[":moneybag:"] = "💰"; + _emojiToText["💰"] = ":moneybag:"; + _textToEmoji[":money_bag:"] = "💰"; + _emojiToText["💰"] = ":money_bag:"; + _textToEmoji[":credit_card:"] = "💳"; + _emojiToText["💳"] = ":credit_card:"; + _textToEmoji[":identification_card:"] = "🪪"; + _emojiToText["🪪"] = ":identification_card:"; + _textToEmoji[":gem:"] = "💎"; + _emojiToText["💎"] = ":gem:"; + _textToEmoji[":gem_stone:"] = "💎"; + _emojiToText["💎"] = ":gem_stone:"; + _textToEmoji[":scales:"] = "⚖️"; + _emojiToText["⚖️"] = ":scales:"; + _textToEmoji[":balance_scale:"] = "⚖️"; + _emojiToText["⚖️"] = ":balance_scale:"; + _textToEmoji[":ladder:"] = "🪜"; + _emojiToText["🪜"] = ":ladder:"; + _textToEmoji[":toolbox:"] = "🧰"; + _emojiToText["🧰"] = ":toolbox:"; + _textToEmoji[":screwdriver:"] = "🪛"; + _emojiToText["🪛"] = ":screwdriver:"; + _textToEmoji[":wrench:"] = "🔧"; + _emojiToText["🔧"] = ":wrench:"; + _textToEmoji[":hammer:"] = "🔨"; + _emojiToText["🔨"] = ":hammer:"; + _textToEmoji[":hammer_pick:"] = "⚒️"; + _emojiToText["⚒️"] = ":hammer_pick:"; + _textToEmoji[":hammer_and_pick:"] = "⚒️"; + _emojiToText["⚒️"] = ":hammer_and_pick:"; + _textToEmoji[":tools:"] = "🛠️"; + _emojiToText["🛠️"] = ":tools:"; + _textToEmoji[":hammer_and_wrench:"] = "🛠️"; + _emojiToText["🛠️"] = ":hammer_and_wrench:"; + _textToEmoji[":pick:"] = "⛏️"; + _emojiToText["⛏️"] = ":pick:"; + _textToEmoji[":carpentry_saw:"] = "🪚"; + _emojiToText["🪚"] = ":carpentry_saw:"; + _textToEmoji[":nut_and_bolt:"] = "🔩"; + _emojiToText["🔩"] = ":nut_and_bolt:"; + _textToEmoji[":gear:"] = "⚙️"; + _emojiToText["⚙️"] = ":gear:"; + _textToEmoji[":mouse_trap:"] = "🪤"; + _emojiToText["🪤"] = ":mouse_trap:"; + _textToEmoji[":bricks:"] = "🧱"; + _emojiToText["🧱"] = ":bricks:"; + _textToEmoji[":brick:"] = "🧱"; + _emojiToText["🧱"] = ":brick:"; + _textToEmoji[":chains:"] = "⛓️"; + _emojiToText["⛓️"] = ":chains:"; + _textToEmoji[":magnet:"] = "🧲"; + _emojiToText["🧲"] = ":magnet:"; + _textToEmoji[":gun:"] = "🔫"; + _emojiToText["🔫"] = ":gun:"; + _textToEmoji[":pistol:"] = "🔫"; + _emojiToText["🔫"] = ":pistol:"; + _textToEmoji[":bomb:"] = "💣"; + _emojiToText["💣"] = ":bomb:"; + _textToEmoji[":firecracker:"] = "🧨"; + _emojiToText["🧨"] = ":firecracker:"; + _textToEmoji[":axe:"] = "🪓"; + _emojiToText["🪓"] = ":axe:"; + _textToEmoji[":knife:"] = "🔪"; + _emojiToText["🔪"] = ":knife:"; + _textToEmoji[":kitchen_knife:"] = "🔪"; + _emojiToText["🔪"] = ":kitchen_knife:"; + _textToEmoji[":dagger:"] = "🗡️"; + _emojiToText["🗡️"] = ":dagger:"; + _textToEmoji[":dagger_knife:"] = "🗡️"; + _emojiToText["🗡️"] = ":dagger_knife:"; + _textToEmoji[":crossed_swords:"] = "⚔️"; + _emojiToText["⚔️"] = ":crossed_swords:"; + _textToEmoji[":shield:"] = "🛡️"; + _emojiToText["🛡️"] = ":shield:"; + _textToEmoji[":smoking:"] = "🚬"; + _emojiToText["🚬"] = ":smoking:"; + _textToEmoji[":cigarette:"] = "🚬"; + _emojiToText["🚬"] = ":cigarette:"; + _textToEmoji[":coffin:"] = "⚰️"; + _emojiToText["⚰️"] = ":coffin:"; + _textToEmoji[":headstone:"] = "🪦"; + _emojiToText["🪦"] = ":headstone:"; + _textToEmoji[":urn:"] = "⚱️"; + _emojiToText["⚱️"] = ":urn:"; + _textToEmoji[":funeral_urn:"] = "⚱️"; + _emojiToText["⚱️"] = ":funeral_urn:"; + _textToEmoji[":amphora:"] = "🏺"; + _emojiToText["🏺"] = ":amphora:"; + _textToEmoji[":crystal_ball:"] = "🔮"; + _emojiToText["🔮"] = ":crystal_ball:"; + _textToEmoji[":prayer_beads:"] = "📿"; + _emojiToText["📿"] = ":prayer_beads:"; + _textToEmoji[":nazar_amulet:"] = "🧿"; + _emojiToText["🧿"] = ":nazar_amulet:"; + _textToEmoji[":hamsa:"] = "🪬"; + _emojiToText["🪬"] = ":hamsa:"; + _textToEmoji[":barber:"] = "💈"; + _emojiToText["💈"] = ":barber:"; + _textToEmoji[":barber_pole:"] = "💈"; + _emojiToText["💈"] = ":barber_pole:"; + _textToEmoji[":alembic:"] = "⚗️"; + _emojiToText["⚗️"] = ":alembic:"; + _textToEmoji[":telescope:"] = "🔭"; + _emojiToText["🔭"] = ":telescope:"; + _textToEmoji[":microscope:"] = "🔬"; + _emojiToText["🔬"] = ":microscope:"; + _textToEmoji[":hole:"] = "🕳️"; + _emojiToText["🕳️"] = ":hole:"; + _textToEmoji[":x_ray:"] = "🩻"; + _emojiToText["🩻"] = ":x_ray:"; + _textToEmoji[":adhesive_bandage:"] = "🩹"; + _emojiToText["🩹"] = ":adhesive_bandage:"; + _textToEmoji[":stethoscope:"] = "🩺"; + _emojiToText["🩺"] = ":stethoscope:"; + _textToEmoji[":pill:"] = "💊"; + _emojiToText["💊"] = ":pill:"; + _textToEmoji[":syringe:"] = "💉"; + _emojiToText["💉"] = ":syringe:"; + _textToEmoji[":drop_of_blood:"] = "🩸"; + _emojiToText["🩸"] = ":drop_of_blood:"; + _textToEmoji[":dna:"] = "🧬"; + _emojiToText["🧬"] = ":dna:"; + _textToEmoji[":microbe:"] = "🦠"; + _emojiToText["🦠"] = ":microbe:"; + _textToEmoji[":petri_dish:"] = "🧫"; + _emojiToText["🧫"] = ":petri_dish:"; + _textToEmoji[":test_tube:"] = "🧪"; + _emojiToText["🧪"] = ":test_tube:"; + _textToEmoji[":thermometer:"] = "🌡️"; + _emojiToText["🌡️"] = ":thermometer:"; + _textToEmoji[":broom:"] = "🧹"; + _emojiToText["🧹"] = ":broom:"; + _textToEmoji[":plunger:"] = "🪠"; + _emojiToText["🪠"] = ":plunger:"; + _textToEmoji[":basket:"] = "🧺"; + _emojiToText["🧺"] = ":basket:"; + _textToEmoji[":roll_of_paper:"] = "🧻"; + _emojiToText["🧻"] = ":roll_of_paper:"; + _textToEmoji[":toilet:"] = "🚽"; + _emojiToText["🚽"] = ":toilet:"; + _textToEmoji[":potable_water:"] = "🚰"; + _emojiToText["🚰"] = ":potable_water:"; + _textToEmoji[":shower:"] = "🚿"; + _emojiToText["🚿"] = ":shower:"; + _textToEmoji[":bathtub:"] = "🛁"; + _emojiToText["🛁"] = ":bathtub:"; + _textToEmoji[":bath:"] = "🛀"; + _emojiToText["🛀"] = ":bath:"; + _textToEmoji[":soap:"] = "🧼"; + _emojiToText["🧼"] = ":soap:"; + _textToEmoji[":toothbrush:"] = "🪥"; + _emojiToText["🪥"] = ":toothbrush:"; + _textToEmoji[":razor:"] = "🪒"; + _emojiToText["🪒"] = ":razor:"; + _textToEmoji[":hair_pick:"] = "🪮"; + _emojiToText["🪮"] = ":hair_pick:"; + _textToEmoji[":sponge:"] = "🧽"; + _emojiToText["🧽"] = ":sponge:"; + _textToEmoji[":bucket:"] = "🪣"; + _emojiToText["🪣"] = ":bucket:"; + _textToEmoji[":squeeze_bottle:"] = "🧴"; + _emojiToText["🧴"] = ":squeeze_bottle:"; + _textToEmoji[":lotion_bottle:"] = "🧴"; + _emojiToText["🧴"] = ":lotion_bottle:"; + _textToEmoji[":bellhop:"] = "🛎️"; + _emojiToText["🛎️"] = ":bellhop:"; + _textToEmoji[":bellhop_bell:"] = "🛎️"; + _emojiToText["🛎️"] = ":bellhop_bell:"; + _textToEmoji[":key:"] = "🔑"; + _emojiToText["🔑"] = ":key:"; + _textToEmoji[":key2:"] = "🗝️"; + _emojiToText["🗝️"] = ":key2:"; + _textToEmoji[":old_key:"] = "🗝️"; + _emojiToText["🗝️"] = ":old_key:"; + _textToEmoji[":door:"] = "🚪"; + _emojiToText["🚪"] = ":door:"; + _textToEmoji[":chair:"] = "🪑"; + _emojiToText["🪑"] = ":chair:"; + _textToEmoji[":couch:"] = "🛋️"; + _emojiToText["🛋️"] = ":couch:"; + _textToEmoji[":couch_and_lamp:"] = "🛋️"; + _emojiToText["🛋️"] = ":couch_and_lamp:"; + _textToEmoji[":bed:"] = "🛏️"; + _emojiToText["🛏️"] = ":bed:"; + _textToEmoji[":sleeping_accommodation:"] = "🛌"; + _emojiToText["🛌"] = ":sleeping_accommodation:"; + _textToEmoji[":person_in_bed:"] = "🛌"; + _emojiToText["🛌"] = ":person_in_bed:"; + _textToEmoji[":teddy_bear:"] = "🧸"; + _emojiToText["🧸"] = ":teddy_bear:"; + _textToEmoji[":nesting_dolls:"] = "🪆"; + _emojiToText["🪆"] = ":nesting_dolls:"; + _textToEmoji[":frame_photo:"] = "🖼️"; + _emojiToText["🖼️"] = ":frame_photo:"; + _textToEmoji[":frame_with_picture:"] = "🖼️"; + _emojiToText["🖼️"] = ":frame_with_picture:"; + _textToEmoji[":mirror:"] = "🪞"; + _emojiToText["🪞"] = ":mirror:"; + _textToEmoji[":window:"] = "🪟"; + _emojiToText["🪟"] = ":window:"; + _textToEmoji[":shopping_bags:"] = "🛍️"; + _emojiToText["🛍️"] = ":shopping_bags:"; + _textToEmoji[":shopping_cart:"] = "🛒"; + _emojiToText["🛒"] = ":shopping_cart:"; + _textToEmoji[":shopping_trolley:"] = "🛒"; + _emojiToText["🛒"] = ":shopping_trolley:"; + _textToEmoji[":gift:"] = "🎁"; + _emojiToText["🎁"] = ":gift:"; + _textToEmoji[":wrapped_gift:"] = "🎁"; + _emojiToText["🎁"] = ":wrapped_gift:"; + _textToEmoji[":balloon:"] = "🎈"; + _emojiToText["🎈"] = ":balloon:"; + _textToEmoji[":flags:"] = "🎏"; + _emojiToText["🎏"] = ":flags:"; + _textToEmoji[":carp_streamer:"] = "🎏"; + _emojiToText["🎏"] = ":carp_streamer:"; + _textToEmoji[":ribbon:"] = "🎀"; + _emojiToText["🎀"] = ":ribbon:"; + _textToEmoji[":magic_wand:"] = "🪄"; + _emojiToText["🪄"] = ":magic_wand:"; + _textToEmoji[":piñata:"] = "🪅"; + _emojiToText["🪅"] = ":piñata:"; + _textToEmoji[":confetti_ball:"] = "🎊"; + _emojiToText["🎊"] = ":confetti_ball:"; + _textToEmoji[":tada:"] = "🎉"; + _emojiToText["🎉"] = ":tada:"; + _textToEmoji[":party_popper:"] = "🎉"; + _emojiToText["🎉"] = ":party_popper:"; + _textToEmoji[":dolls:"] = "🎎"; + _emojiToText["🎎"] = ":dolls:"; + _textToEmoji[":folding_hand_fan:"] = "🪭"; + _emojiToText["🪭"] = ":folding_hand_fan:"; + _textToEmoji[":izakaya_lantern:"] = "🏮"; + _emojiToText["🏮"] = ":izakaya_lantern:"; + _textToEmoji[":wind_chime:"] = "🎐"; + _emojiToText["🎐"] = ":wind_chime:"; + _textToEmoji[":mirror_ball:"] = "🪩"; + _emojiToText["🪩"] = ":mirror_ball:"; + _textToEmoji[":red_envelope:"] = "🧧"; + _emojiToText["🧧"] = ":red_envelope:"; + _textToEmoji[":envelope:"] = "✉️"; + _emojiToText["✉️"] = ":envelope:"; + _textToEmoji[":envelope_with_arrow:"] = "📩"; + _emojiToText["📩"] = ":envelope_with_arrow:"; + _textToEmoji[":incoming_envelope:"] = "📨"; + _emojiToText["📨"] = ":incoming_envelope:"; + _textToEmoji[":e_mail:"] = "📧"; + _emojiToText["📧"] = ":e_mail:"; + _textToEmoji[":email:"] = "📧"; + _emojiToText["📧"] = ":email:"; + _textToEmoji[":love_letter:"] = "💌"; + _emojiToText["💌"] = ":love_letter:"; + _textToEmoji[":inbox_tray:"] = "📥"; + _emojiToText["📥"] = ":inbox_tray:"; + _textToEmoji[":outbox_tray:"] = "📤"; + _emojiToText["📤"] = ":outbox_tray:"; + _textToEmoji[":package:"] = "📦"; + _emojiToText["📦"] = ":package:"; + _textToEmoji[":label:"] = "🏷️"; + _emojiToText["🏷️"] = ":label:"; + _textToEmoji[":placard:"] = "🪧"; + _emojiToText["🪧"] = ":placard:"; + _textToEmoji[":mailbox_closed:"] = "📪"; + _emojiToText["📪"] = ":mailbox_closed:"; + _textToEmoji[":mailbox:"] = "📫"; + _emojiToText["📫"] = ":mailbox:"; + _textToEmoji[":mailbox_with_mail:"] = "📬"; + _emojiToText["📬"] = ":mailbox_with_mail:"; + _textToEmoji[":mailbox_with_no_mail:"] = "📭"; + _emojiToText["📭"] = ":mailbox_with_no_mail:"; + _textToEmoji[":postbox:"] = "📮"; + _emojiToText["📮"] = ":postbox:"; + _textToEmoji[":postal_horn:"] = "📯"; + _emojiToText["📯"] = ":postal_horn:"; + _textToEmoji[":scroll:"] = "📜"; + _emojiToText["📜"] = ":scroll:"; + _textToEmoji[":page_with_curl:"] = "📃"; + _emojiToText["📃"] = ":page_with_curl:"; + _textToEmoji[":page_facing_up:"] = "📄"; + _emojiToText["📄"] = ":page_facing_up:"; + _textToEmoji[":bookmark_tabs:"] = "📑"; + _emojiToText["📑"] = ":bookmark_tabs:"; + _textToEmoji[":receipt:"] = "🧾"; + _emojiToText["🧾"] = ":receipt:"; + _textToEmoji[":bar_chart:"] = "📊"; + _emojiToText["📊"] = ":bar_chart:"; + _textToEmoji[":chart_with_upwards_trend:"] = "📈"; + _emojiToText["📈"] = ":chart_with_upwards_trend:"; + _textToEmoji[":chart_with_downwards_trend:"] = "📉"; + _emojiToText["📉"] = ":chart_with_downwards_trend:"; + _textToEmoji[":notepad_spiral:"] = "🗒️"; + _emojiToText["🗒️"] = ":notepad_spiral:"; + _textToEmoji[":spiral_note_pad:"] = "🗒️"; + _emojiToText["🗒️"] = ":spiral_note_pad:"; + _textToEmoji[":calendar_spiral:"] = "🗓️"; + _emojiToText["🗓️"] = ":calendar_spiral:"; + _textToEmoji[":spiral_calendar_pad:"] = "🗓️"; + _emojiToText["🗓️"] = ":spiral_calendar_pad:"; + _textToEmoji[":calendar:"] = "📆"; + _emojiToText["📆"] = ":calendar:"; + _textToEmoji[":date:"] = "📅"; + _emojiToText["📅"] = ":date:"; + _textToEmoji[":wastebasket:"] = "🗑️"; + _emojiToText["🗑️"] = ":wastebasket:"; + _textToEmoji[":card_index:"] = "📇"; + _emojiToText["📇"] = ":card_index:"; + _textToEmoji[":card_box:"] = "🗃️"; + _emojiToText["🗃️"] = ":card_box:"; + _textToEmoji[":card_file_box:"] = "🗃️"; + _emojiToText["🗃️"] = ":card_file_box:"; + _textToEmoji[":ballot_box:"] = "🗳️"; + _emojiToText["🗳️"] = ":ballot_box:"; + _textToEmoji[":ballot_box_with_ballot:"] = "🗳️"; + _emojiToText["🗳️"] = ":ballot_box_with_ballot:"; + _textToEmoji[":file_cabinet:"] = "🗄️"; + _emojiToText["🗄️"] = ":file_cabinet:"; + _textToEmoji[":clipboard:"] = "📋"; + _emojiToText["📋"] = ":clipboard:"; + _textToEmoji[":file_folder:"] = "📁"; + _emojiToText["📁"] = ":file_folder:"; + _textToEmoji[":open_file_folder:"] = "📂"; + _emojiToText["📂"] = ":open_file_folder:"; + _textToEmoji[":dividers:"] = "🗂️"; + _emojiToText["🗂️"] = ":dividers:"; + _textToEmoji[":card_index_dividers:"] = "🗂️"; + _emojiToText["🗂️"] = ":card_index_dividers:"; + _textToEmoji[":newspaper2:"] = "🗞️"; + _emojiToText["🗞️"] = ":newspaper2:"; + _textToEmoji[":rolled_up_newspaper:"] = "🗞️"; + _emojiToText["🗞️"] = ":rolled_up_newspaper:"; + _textToEmoji[":newspaper:"] = "📰"; + _emojiToText["📰"] = ":newspaper:"; + _textToEmoji[":notebook:"] = "📓"; + _emojiToText["📓"] = ":notebook:"; + _textToEmoji[":notebook_with_decorative_cover:"] = "📔"; + _emojiToText["📔"] = ":notebook_with_decorative_cover:"; + _textToEmoji[":ledger:"] = "📒"; + _emojiToText["📒"] = ":ledger:"; + _textToEmoji[":closed_book:"] = "📕"; + _emojiToText["📕"] = ":closed_book:"; + _textToEmoji[":green_book:"] = "📗"; + _emojiToText["📗"] = ":green_book:"; + _textToEmoji[":blue_book:"] = "📘"; + _emojiToText["📘"] = ":blue_book:"; + _textToEmoji[":orange_book:"] = "📙"; + _emojiToText["📙"] = ":orange_book:"; + _textToEmoji[":books:"] = "📚"; + _emojiToText["📚"] = ":books:"; + _textToEmoji[":book:"] = "📖"; + _emojiToText["📖"] = ":book:"; + _textToEmoji[":open_book:"] = "📖"; + _emojiToText["📖"] = ":open_book:"; + _textToEmoji[":bookmark:"] = "🔖"; + _emojiToText["🔖"] = ":bookmark:"; + _textToEmoji[":safety_pin:"] = "🧷"; + _emojiToText["🧷"] = ":safety_pin:"; + _textToEmoji[":link:"] = "🔗"; + _emojiToText["🔗"] = ":link:"; + _textToEmoji[":paperclip:"] = "📎"; + _emojiToText["📎"] = ":paperclip:"; + _textToEmoji[":paperclips:"] = "🖇️"; + _emojiToText["🖇️"] = ":paperclips:"; + _textToEmoji[":linked_paperclips:"] = "🖇️"; + _emojiToText["🖇️"] = ":linked_paperclips:"; + _textToEmoji[":triangular_ruler:"] = "📐"; + _emojiToText["📐"] = ":triangular_ruler:"; + _textToEmoji[":straight_ruler:"] = "📏"; + _emojiToText["📏"] = ":straight_ruler:"; + _textToEmoji[":abacus:"] = "🧮"; + _emojiToText["🧮"] = ":abacus:"; + _textToEmoji[":pushpin:"] = "📌"; + _emojiToText["📌"] = ":pushpin:"; + _textToEmoji[":round_pushpin:"] = "📍"; + _emojiToText["📍"] = ":round_pushpin:"; + _textToEmoji[":scissors:"] = "✂️"; + _emojiToText["✂️"] = ":scissors:"; + _textToEmoji[":pen_ballpoint:"] = "🖊️"; + _emojiToText["🖊️"] = ":pen_ballpoint:"; + _textToEmoji[":lower_left_ballpoint_pen:"] = "🖊️"; + _emojiToText["🖊️"] = ":lower_left_ballpoint_pen:"; + _textToEmoji[":pen:"] = "🖊️"; + _emojiToText["🖊️"] = ":pen:"; + _textToEmoji[":pen_fountain:"] = "🖋️"; + _emojiToText["🖋️"] = ":pen_fountain:"; + _textToEmoji[":lower_left_fountain_pen:"] = "🖋️"; + _emojiToText["🖋️"] = ":lower_left_fountain_pen:"; + _textToEmoji[":fountain_pen:"] = "🖋️"; + _emojiToText["🖋️"] = ":fountain_pen:"; + _textToEmoji[":black_nib:"] = "✒️"; + _emojiToText["✒️"] = ":black_nib:"; + _textToEmoji[":paintbrush:"] = "🖌️"; + _emojiToText["🖌️"] = ":paintbrush:"; + _textToEmoji[":lower_left_paintbrush:"] = "🖌️"; + _emojiToText["🖌️"] = ":lower_left_paintbrush:"; + _textToEmoji[":crayon:"] = "🖍️"; + _emojiToText["🖍️"] = ":crayon:"; + _textToEmoji[":lower_left_crayon:"] = "🖍️"; + _emojiToText["🖍️"] = ":lower_left_crayon:"; + _textToEmoji[":pencil:"] = "📝"; + _emojiToText["📝"] = ":pencil:"; + _textToEmoji[":memo:"] = "📝"; + _emojiToText["📝"] = ":memo:"; + _textToEmoji[":pencil2:"] = "✏️"; + _emojiToText["✏️"] = ":pencil2:"; + _textToEmoji[":mag:"] = "🔍"; + _emojiToText["🔍"] = ":mag:"; + _textToEmoji[":mag_right:"] = "🔎"; + _emojiToText["🔎"] = ":mag_right:"; + _textToEmoji[":lock_with_ink_pen:"] = "🔏"; + _emojiToText["🔏"] = ":lock_with_ink_pen:"; + _textToEmoji[":closed_lock_with_key:"] = "🔐"; + _emojiToText["🔐"] = ":closed_lock_with_key:"; + _textToEmoji[":lock:"] = "🔒"; + _emojiToText["🔒"] = ":lock:"; + _textToEmoji[":locked:"] = "🔒"; + _emojiToText["🔒"] = ":locked:"; + _textToEmoji[":unlock:"] = "🔓"; + _emojiToText["🔓"] = ":unlock:"; + _textToEmoji[":unlocked:"] = "🔓"; + _emojiToText["🔓"] = ":unlocked:"; + _textToEmoji[":grinning:"] = "😀"; + _emojiToText["😀"] = ":grinning:"; + _textToEmoji[":grinning_face:"] = "😀"; + _emojiToText["😀"] = ":grinning_face:"; + _textToEmoji[":smiley:"] = "😃"; + _emojiToText["😃"] = ":smiley:"; + _textToEmoji[":smile:"] = "😄"; + _emojiToText["😄"] = ":smile:"; + _textToEmoji[":grin:"] = "😁"; + _emojiToText["😁"] = ":grin:"; + _textToEmoji[":laughing:"] = "😆"; + _emojiToText["😆"] = ":laughing:"; + _textToEmoji[":satisfied:"] = "😆"; + _emojiToText["😆"] = ":satisfied:"; + _textToEmoji[":face_holding_back_tears:"] = "🥹"; + _emojiToText["🥹"] = ":face_holding_back_tears:"; + _textToEmoji[":sweat_smile:"] = "😅"; + _emojiToText["😅"] = ":sweat_smile:"; + _textToEmoji[":joy:"] = "😂"; + _emojiToText["😂"] = ":joy:"; + _textToEmoji[":rofl:"] = "🤣"; + _emojiToText["🤣"] = ":rofl:"; + _textToEmoji[":rolling_on_the_floor_laughing:"] = "🤣"; + _emojiToText["🤣"] = ":rolling_on_the_floor_laughing:"; + _textToEmoji[":smiling_face_with_tear:"] = "🥲"; + _emojiToText["🥲"] = ":smiling_face_with_tear:"; + _textToEmoji[":relaxed:"] = "☺️"; + _emojiToText["☺️"] = ":relaxed:"; + _textToEmoji[":smiling_face:"] = "☺️"; + _emojiToText["☺️"] = ":smiling_face:"; + _textToEmoji[":blush:"] = "😊"; + _emojiToText["😊"] = ":blush:"; + _textToEmoji[":innocent:"] = "😇"; + _emojiToText["😇"] = ":innocent:"; + _textToEmoji[":slight_smile:"] = "🙂"; + _emojiToText["🙂"] = ":slight_smile:"; + _textToEmoji[":slightly_smiling_face:"] = "🙂"; + _emojiToText["🙂"] = ":slightly_smiling_face:"; + _textToEmoji[":upside_down:"] = "🙃"; + _emojiToText["🙃"] = ":upside_down:"; + _textToEmoji[":upside_down_face:"] = "🙃"; + _emojiToText["🙃"] = ":upside_down_face:"; + _textToEmoji[":wink:"] = "😉"; + _emojiToText["😉"] = ":wink:"; + _textToEmoji[":winking_face:"] = "😉"; + _emojiToText["😉"] = ":winking_face:"; + _textToEmoji[":relieved:"] = "😌"; + _emojiToText["😌"] = ":relieved:"; + _textToEmoji[":relieved_face:"] = "😌"; + _emojiToText["😌"] = ":relieved_face:"; + _textToEmoji[":heart_eyes:"] = "😍"; + _emojiToText["😍"] = ":heart_eyes:"; + _textToEmoji[":smiling_face_with_3_hearts:"] = "🥰"; + _emojiToText["🥰"] = ":smiling_face_with_3_hearts:"; + _textToEmoji[":kissing_heart:"] = "😘"; + _emojiToText["😘"] = ":kissing_heart:"; + _textToEmoji[":kissing:"] = "😗"; + _emojiToText["😗"] = ":kissing:"; + _textToEmoji[":kissing_face:"] = "😗"; + _emojiToText["😗"] = ":kissing_face:"; + _textToEmoji[":kissing_smiling_eyes:"] = "😙"; + _emojiToText["😙"] = ":kissing_smiling_eyes:"; + _textToEmoji[":kissing_closed_eyes:"] = "😚"; + _emojiToText["😚"] = ":kissing_closed_eyes:"; + _textToEmoji[":yum:"] = "😋"; + _emojiToText["😋"] = ":yum:"; + _textToEmoji[":stuck_out_tongue:"] = "😛"; + _emojiToText["😛"] = ":stuck_out_tongue:"; + _textToEmoji[":stuck_out_tongue_closed_eyes:"] = "😝"; + _emojiToText["😝"] = ":stuck_out_tongue_closed_eyes:"; + _textToEmoji[":stuck_out_tongue_winking_eye:"] = "😜"; + _emojiToText["😜"] = ":stuck_out_tongue_winking_eye:"; + _textToEmoji[":zany_face:"] = "🤪"; + _emojiToText["🤪"] = ":zany_face:"; + _textToEmoji[":face_with_raised_eyebrow:"] = "🤨"; + _emojiToText["🤨"] = ":face_with_raised_eyebrow:"; + _textToEmoji[":face_with_monocle:"] = "🧐"; + _emojiToText["🧐"] = ":face_with_monocle:"; + _textToEmoji[":nerd:"] = "🤓"; + _emojiToText["🤓"] = ":nerd:"; + _textToEmoji[":nerd_face:"] = "🤓"; + _emojiToText["🤓"] = ":nerd_face:"; + _textToEmoji[":sunglasses:"] = "😎"; + _emojiToText["😎"] = ":sunglasses:"; + _textToEmoji[":disguised_face:"] = "🥸"; + _emojiToText["🥸"] = ":disguised_face:"; + _textToEmoji[":star_struck:"] = "🤩"; + _emojiToText["🤩"] = ":star_struck:"; + _textToEmoji[":partying_face:"] = "🥳"; + _emojiToText["🥳"] = ":partying_face:"; + _textToEmoji[":smirk:"] = "😏"; + _emojiToText["😏"] = ":smirk:"; + _textToEmoji[":smirking_face:"] = "😏"; + _emojiToText["😏"] = ":smirking_face:"; + _textToEmoji[":unamused:"] = "😒"; + _emojiToText["😒"] = ":unamused:"; + _textToEmoji[":unamused_face:"] = "😒"; + _emojiToText["😒"] = ":unamused_face:"; + _textToEmoji[":disappointed:"] = "😞"; + _emojiToText["😞"] = ":disappointed:"; + _textToEmoji[":pensive:"] = "😔"; + _emojiToText["😔"] = ":pensive:"; + _textToEmoji[":pensive_face:"] = "😔"; + _emojiToText["😔"] = ":pensive_face:"; + _textToEmoji[":worried:"] = "😟"; + _emojiToText["😟"] = ":worried:"; + _textToEmoji[":worried_face:"] = "😟"; + _emojiToText["😟"] = ":worried_face:"; + _textToEmoji[":confused:"] = "😕"; + _emojiToText["😕"] = ":confused:"; + _textToEmoji[":confused_face:"] = "😕"; + _emojiToText["😕"] = ":confused_face:"; + _textToEmoji[":slight_frown:"] = "🙁"; + _emojiToText["🙁"] = ":slight_frown:"; + _textToEmoji[":slightly_frowning_face:"] = "🙁"; + _emojiToText["🙁"] = ":slightly_frowning_face:"; + _textToEmoji[":frowning2:"] = "☹️"; + _emojiToText["☹️"] = ":frowning2:"; + _textToEmoji[":white_frowning_face:"] = "☹️"; + _emojiToText["☹️"] = ":white_frowning_face:"; + _textToEmoji[":frowning_face:"] = "☹️"; + _emojiToText["☹️"] = ":frowning_face:"; + _textToEmoji[":persevere:"] = "😣"; + _emojiToText["😣"] = ":persevere:"; + _textToEmoji[":confounded:"] = "😖"; + _emojiToText["😖"] = ":confounded:"; + _textToEmoji[":tired_face:"] = "😫"; + _emojiToText["😫"] = ":tired_face:"; + _textToEmoji[":weary:"] = "😩"; + _emojiToText["😩"] = ":weary:"; + _textToEmoji[":weary_face:"] = "😩"; + _emojiToText["😩"] = ":weary_face:"; + _textToEmoji[":pleading_face:"] = "🥺"; + _emojiToText["🥺"] = ":pleading_face:"; + _textToEmoji[":cry:"] = "😢"; + _emojiToText["😢"] = ":cry:"; + _textToEmoji[":crying_face:"] = "😢"; + _emojiToText["😢"] = ":crying_face:"; + _textToEmoji[":sob:"] = "😭"; + _emojiToText["😭"] = ":sob:"; + _textToEmoji[":triumph:"] = "😤"; + _emojiToText["😤"] = ":triumph:"; + _textToEmoji[":angry:"] = "😠"; + _emojiToText["😠"] = ":angry:"; + _textToEmoji[":angry_face:"] = "😠"; + _emojiToText["😠"] = ":angry_face:"; + _textToEmoji[":rage:"] = "😡"; + _emojiToText["😡"] = ":rage:"; + _textToEmoji[":pouting_face:"] = "😡"; + _emojiToText["😡"] = ":pouting_face:"; + _textToEmoji[":face_with_symbols_over_mouth:"] = "🤬"; + _emojiToText["🤬"] = ":face_with_symbols_over_mouth:"; + _textToEmoji[":exploding_head:"] = "🤯"; + _emojiToText["🤯"] = ":exploding_head:"; + _textToEmoji[":flushed:"] = "😳"; + _emojiToText["😳"] = ":flushed:"; + _textToEmoji[":flushed_face:"] = "😳"; + _emojiToText["😳"] = ":flushed_face:"; + _textToEmoji[":hot_face:"] = "🥵"; + _emojiToText["🥵"] = ":hot_face:"; + _textToEmoji[":cold_face:"] = "🥶"; + _emojiToText["🥶"] = ":cold_face:"; + _textToEmoji[":face_in_clouds:"] = "😶‍🌫️"; + _emojiToText["😶‍🌫️"] = ":face_in_clouds:"; + _textToEmoji[":scream:"] = "😱"; + _emojiToText["😱"] = ":scream:"; + _textToEmoji[":fearful:"] = "😨"; + _emojiToText["😨"] = ":fearful:"; + _textToEmoji[":fearful_face:"] = "😨"; + _emojiToText["😨"] = ":fearful_face:"; + _textToEmoji[":cold_sweat:"] = "😰"; + _emojiToText["😰"] = ":cold_sweat:"; + _textToEmoji[":disappointed_relieved:"] = "😥"; + _emojiToText["😥"] = ":disappointed_relieved:"; + _textToEmoji[":sweat:"] = "😓"; + _emojiToText["😓"] = ":sweat:"; + _textToEmoji[":hugging:"] = "🤗"; + _emojiToText["🤗"] = ":hugging:"; + _textToEmoji[":hugging_face:"] = "🤗"; + _emojiToText["🤗"] = ":hugging_face:"; + _textToEmoji[":thinking:"] = "🤔"; + _emojiToText["🤔"] = ":thinking:"; + _textToEmoji[":thinking_face:"] = "🤔"; + _emojiToText["🤔"] = ":thinking_face:"; + _textToEmoji[":face_with_peeking_eye:"] = "🫣"; + _emojiToText["🫣"] = ":face_with_peeking_eye:"; + _textToEmoji[":face_with_hand_over_mouth:"] = "🤭"; + _emojiToText["🤭"] = ":face_with_hand_over_mouth:"; + _textToEmoji[":face_with_open_eyes_and_hand_over_mouth:"] = "🫢"; + _emojiToText["🫢"] = ":face_with_open_eyes_and_hand_over_mouth:"; + _textToEmoji[":saluting_face:"] = "🫡"; + _emojiToText["🫡"] = ":saluting_face:"; + _textToEmoji[":shushing_face:"] = "🤫"; + _emojiToText["🤫"] = ":shushing_face:"; + _textToEmoji[":melting_face:"] = "🫠"; + _emojiToText["🫠"] = ":melting_face:"; + _textToEmoji[":lying_face:"] = "🤥"; + _emojiToText["🤥"] = ":lying_face:"; + _textToEmoji[":liar:"] = "🤥"; + _emojiToText["🤥"] = ":liar:"; + _textToEmoji[":no_mouth:"] = "😶"; + _emojiToText["😶"] = ":no_mouth:"; + _textToEmoji[":dotted_line_face:"] = "🫥"; + _emojiToText["🫥"] = ":dotted_line_face:"; + _textToEmoji[":neutral_face:"] = "😐"; + _emojiToText["😐"] = ":neutral_face:"; + _textToEmoji[":face_with_diagonal_mouth:"] = "🫤"; + _emojiToText["🫤"] = ":face_with_diagonal_mouth:"; + _textToEmoji[":expressionless:"] = "😑"; + _emojiToText["😑"] = ":expressionless:"; + _textToEmoji[":shaking_face:"] = "🫨"; + _emojiToText["🫨"] = ":shaking_face:"; + _textToEmoji[":grimacing:"] = "😬"; + _emojiToText["😬"] = ":grimacing:"; + _textToEmoji[":rolling_eyes:"] = "🙄"; + _emojiToText["🙄"] = ":rolling_eyes:"; + _textToEmoji[":face_with_rolling_eyes:"] = "🙄"; + _emojiToText["🙄"] = ":face_with_rolling_eyes:"; + _textToEmoji[":hushed:"] = "😯"; + _emojiToText["😯"] = ":hushed:"; + _textToEmoji[":hushed_face:"] = "😯"; + _emojiToText["😯"] = ":hushed_face:"; + _textToEmoji[":frowning:"] = "😦"; + _emojiToText["😦"] = ":frowning:"; + _textToEmoji[":anguished:"] = "😧"; + _emojiToText["😧"] = ":anguished:"; + _textToEmoji[":open_mouth:"] = "😮"; + _emojiToText["😮"] = ":open_mouth:"; + _textToEmoji[":astonished:"] = "😲"; + _emojiToText["😲"] = ":astonished:"; + _textToEmoji[":yawning_face:"] = "🥱"; + _emojiToText["🥱"] = ":yawning_face:"; + _textToEmoji[":sleeping:"] = "😴"; + _emojiToText["😴"] = ":sleeping:"; + _textToEmoji[":sleeping_face:"] = "😴"; + _emojiToText["😴"] = ":sleeping_face:"; + _textToEmoji[":drooling_face:"] = "🤤"; + _emojiToText["🤤"] = ":drooling_face:"; + _textToEmoji[":drool:"] = "🤤"; + _emojiToText["🤤"] = ":drool:"; + _textToEmoji[":sleepy:"] = "😪"; + _emojiToText["😪"] = ":sleepy:"; + _textToEmoji[":sleepy_face:"] = "😪"; + _emojiToText["😪"] = ":sleepy_face:"; + _textToEmoji[":face_exhaling:"] = "😮‍💨"; + _emojiToText["😮‍💨"] = ":face_exhaling:"; + _textToEmoji[":dizzy_face:"] = "😵"; + _emojiToText["😵"] = ":dizzy_face:"; + _textToEmoji[":face_with_spiral_eyes:"] = "😵‍💫"; + _emojiToText["😵‍💫"] = ":face_with_spiral_eyes:"; + _textToEmoji[":zipper_mouth:"] = "🤐"; + _emojiToText["🤐"] = ":zipper_mouth:"; + _textToEmoji[":zipper_mouth_face:"] = "🤐"; + _emojiToText["🤐"] = ":zipper_mouth_face:"; + _textToEmoji[":woozy_face:"] = "🥴"; + _emojiToText["🥴"] = ":woozy_face:"; + _textToEmoji[":nauseated_face:"] = "🤢"; + _emojiToText["🤢"] = ":nauseated_face:"; + _textToEmoji[":sick:"] = "🤢"; + _emojiToText["🤢"] = ":sick:"; + _textToEmoji[":face_vomiting:"] = "🤮"; + _emojiToText["🤮"] = ":face_vomiting:"; + _textToEmoji[":sneezing_face:"] = "🤧"; + _emojiToText["🤧"] = ":sneezing_face:"; + _textToEmoji[":sneeze:"] = "🤧"; + _emojiToText["🤧"] = ":sneeze:"; + _textToEmoji[":mask:"] = "😷"; + _emojiToText["😷"] = ":mask:"; + _textToEmoji[":thermometer_face:"] = "🤒"; + _emojiToText["🤒"] = ":thermometer_face:"; + _textToEmoji[":face_with_thermometer:"] = "🤒"; + _emojiToText["🤒"] = ":face_with_thermometer:"; + _textToEmoji[":head_bandage:"] = "🤕"; + _emojiToText["🤕"] = ":head_bandage:"; + _textToEmoji[":face_with_head_bandage:"] = "🤕"; + _emojiToText["🤕"] = ":face_with_head_bandage:"; + _textToEmoji[":money_mouth:"] = "🤑"; + _emojiToText["🤑"] = ":money_mouth:"; + _textToEmoji[":money_mouth_face:"] = "🤑"; + _emojiToText["🤑"] = ":money_mouth_face:"; + _textToEmoji[":cowboy:"] = "🤠"; + _emojiToText["🤠"] = ":cowboy:"; + _textToEmoji[":face_with_cowboy_hat:"] = "🤠"; + _emojiToText["🤠"] = ":face_with_cowboy_hat:"; + _textToEmoji[":smiling_imp:"] = "😈"; + _emojiToText["😈"] = ":smiling_imp:"; + _textToEmoji[":imp:"] = "👿"; + _emojiToText["👿"] = ":imp:"; + _textToEmoji[":japanese_ogre:"] = "👹"; + _emojiToText["👹"] = ":japanese_ogre:"; + _textToEmoji[":ogre:"] = "👹"; + _emojiToText["👹"] = ":ogre:"; + _textToEmoji[":japanese_goblin:"] = "👺"; + _emojiToText["👺"] = ":japanese_goblin:"; + _textToEmoji[":goblin:"] = "👺"; + _emojiToText["👺"] = ":goblin:"; + _textToEmoji[":clown:"] = "🤡"; + _emojiToText["🤡"] = ":clown:"; + _textToEmoji[":clown_face:"] = "🤡"; + _emojiToText["🤡"] = ":clown_face:"; + _textToEmoji[":poop:"] = "💩"; + _emojiToText["💩"] = ":poop:"; + _textToEmoji[":shit:"] = "💩"; + _emojiToText["💩"] = ":shit:"; + _textToEmoji[":hankey:"] = "💩"; + _emojiToText["💩"] = ":hankey:"; + _textToEmoji[":poo:"] = "💩"; + _emojiToText["💩"] = ":poo:"; + _textToEmoji[":pile_of_poo:"] = "💩"; + _emojiToText["💩"] = ":pile_of_poo:"; + _textToEmoji[":ghost:"] = "👻"; + _emojiToText["👻"] = ":ghost:"; + _textToEmoji[":skull:"] = "💀"; + _emojiToText["💀"] = ":skull:"; + _textToEmoji[":skeleton:"] = "💀"; + _emojiToText["💀"] = ":skeleton:"; + _textToEmoji[":skull_crossbones:"] = "☠️"; + _emojiToText["☠️"] = ":skull_crossbones:"; + _textToEmoji[":skull_and_crossbones:"] = "☠️"; + _emojiToText["☠️"] = ":skull_and_crossbones:"; + _textToEmoji[":alien:"] = "👽"; + _emojiToText["👽"] = ":alien:"; + _textToEmoji[":space_invader:"] = "👾"; + _emojiToText["👾"] = ":space_invader:"; + _textToEmoji[":alien_monster:"] = "👾"; + _emojiToText["👾"] = ":alien_monster:"; + _textToEmoji[":robot:"] = "🤖"; + _emojiToText["🤖"] = ":robot:"; + _textToEmoji[":robot_face:"] = "🤖"; + _emojiToText["🤖"] = ":robot_face:"; + _textToEmoji[":jack_o_lantern:"] = "🎃"; + _emojiToText["🎃"] = ":jack_o_lantern:"; + _textToEmoji[":smiley_cat:"] = "😺"; + _emojiToText["😺"] = ":smiley_cat:"; + _textToEmoji[":grinning_cat:"] = "😺"; + _emojiToText["😺"] = ":grinning_cat:"; + _textToEmoji[":smile_cat:"] = "😸"; + _emojiToText["😸"] = ":smile_cat:"; + _textToEmoji[":joy_cat:"] = "😹"; + _emojiToText["😹"] = ":joy_cat:"; + _textToEmoji[":heart_eyes_cat:"] = "😻"; + _emojiToText["😻"] = ":heart_eyes_cat:"; + _textToEmoji[":smirk_cat:"] = "😼"; + _emojiToText["😼"] = ":smirk_cat:"; + _textToEmoji[":kissing_cat:"] = "😽"; + _emojiToText["😽"] = ":kissing_cat:"; + _textToEmoji[":scream_cat:"] = "🙀"; + _emojiToText["🙀"] = ":scream_cat:"; + _textToEmoji[":weary_cat:"] = "🙀"; + _emojiToText["🙀"] = ":weary_cat:"; + _textToEmoji[":crying_cat_face:"] = "😿"; + _emojiToText["😿"] = ":crying_cat_face:"; + _textToEmoji[":crying_cat:"] = "😿"; + _emojiToText["😿"] = ":crying_cat:"; + _textToEmoji[":pouting_cat:"] = "😾"; + _emojiToText["😾"] = ":pouting_cat:"; + _textToEmoji[":heart_hands:"] = "🫶"; + _emojiToText["🫶"] = ":heart_hands:"; + _textToEmoji[":palms_up_together:"] = "🤲"; + _emojiToText["🤲"] = ":palms_up_together:"; + _textToEmoji[":open_hands:"] = "👐"; + _emojiToText["👐"] = ":open_hands:"; + _textToEmoji[":raised_hands:"] = "🙌"; + _emojiToText["🙌"] = ":raised_hands:"; + _textToEmoji[":raising_hands:"] = "🙌"; + _emojiToText["🙌"] = ":raising_hands:"; + _textToEmoji[":clap:"] = "👏"; + _emojiToText["👏"] = ":clap:"; + _textToEmoji[":handshake:"] = "🤝"; + _emojiToText["🤝"] = ":handshake:"; + _textToEmoji[":shaking_hands:"] = "🤝"; + _emojiToText["🤝"] = ":shaking_hands:"; + _textToEmoji[":thumbsup:"] = "👍"; + _emojiToText["👍"] = ":thumbsup:"; + _textToEmoji[":+1:"] = "👍"; + _emojiToText["👍"] = ":+1:"; + _textToEmoji[":thumbup:"] = "👍"; + _emojiToText["👍"] = ":thumbup:"; + _textToEmoji[":thumbs_up:"] = "👍"; + _emojiToText["👍"] = ":thumbs_up:"; + _textToEmoji[":thumbsdown:"] = "👎"; + _emojiToText["👎"] = ":thumbsdown:"; + _textToEmoji[":-1:"] = "👎"; + _emojiToText["👎"] = ":-1:"; + _textToEmoji[":thumbdown:"] = "👎"; + _emojiToText["👎"] = ":thumbdown:"; + _textToEmoji[":thumbs_down:"] = "👎"; + _emojiToText["👎"] = ":thumbs_down:"; + _textToEmoji[":punch:"] = "👊"; + _emojiToText["👊"] = ":punch:"; + _textToEmoji[":oncoming_fist:"] = "👊"; + _emojiToText["👊"] = ":oncoming_fist:"; + _textToEmoji[":fist:"] = "✊"; + _emojiToText["✊"] = ":fist:"; + _textToEmoji[":raised_fist:"] = "✊"; + _emojiToText["✊"] = ":raised_fist:"; + _textToEmoji[":left_facing_fist:"] = "🤛"; + _emojiToText["🤛"] = ":left_facing_fist:"; + _textToEmoji[":left_fist:"] = "🤛"; + _emojiToText["🤛"] = ":left_fist:"; + _textToEmoji[":right_facing_fist:"] = "🤜"; + _emojiToText["🤜"] = ":right_facing_fist:"; + _textToEmoji[":right_fist:"] = "🤜"; + _emojiToText["🤜"] = ":right_fist:"; + _textToEmoji[":leftwards_pushing_hand:"] = "🫷"; + _emojiToText["🫷"] = ":leftwards_pushing_hand:"; + _textToEmoji[":rightwards_pushing_hand:"] = "🫸"; + _emojiToText["🫸"] = ":rightwards_pushing_hand:"; + _textToEmoji[":fingers_crossed:"] = "🤞"; + _emojiToText["🤞"] = ":fingers_crossed:"; + _textToEmoji[":hand_with_index_and_middle_finger_crossed:"] = "🤞"; + _emojiToText["🤞"] = ":hand_with_index_and_middle_finger_crossed:"; + _textToEmoji[":v:"] = "✌️"; + _emojiToText["✌️"] = ":v:"; + _textToEmoji[":victory_hand:"] = "✌️"; + _emojiToText["✌️"] = ":victory_hand:"; + _textToEmoji[":hand_with_index_finger_and_thumb_crossed:"] = "🫰"; + _emojiToText["🫰"] = ":hand_with_index_finger_and_thumb_crossed:"; + _textToEmoji[":love_you_gesture:"] = "🤟"; + _emojiToText["🤟"] = ":love_you_gesture:"; + _textToEmoji[":metal:"] = "🤘"; + _emojiToText["🤘"] = ":metal:"; + _textToEmoji[":sign_of_the_horns:"] = "🤘"; + _emojiToText["🤘"] = ":sign_of_the_horns:"; + _textToEmoji[":ok_hand:"] = "👌"; + _emojiToText["👌"] = ":ok_hand:"; + _textToEmoji[":pinched_fingers:"] = "🤌"; + _emojiToText["🤌"] = ":pinched_fingers:"; + _textToEmoji[":pinching_hand:"] = "🤏"; + _emojiToText["🤏"] = ":pinching_hand:"; + _textToEmoji[":palm_down_hand:"] = "🫳"; + _emojiToText["🫳"] = ":palm_down_hand:"; + _textToEmoji[":palm_up_hand:"] = "🫴"; + _emojiToText["🫴"] = ":palm_up_hand:"; + _textToEmoji[":point_left:"] = "👈"; + _emojiToText["👈"] = ":point_left:"; + _textToEmoji[":point_right:"] = "👉"; + _emojiToText["👉"] = ":point_right:"; + _textToEmoji[":point_up_2:"] = "👆"; + _emojiToText["👆"] = ":point_up_2:"; + _textToEmoji[":point_down:"] = "👇"; + _emojiToText["👇"] = ":point_down:"; + _textToEmoji[":point_up:"] = "☝️"; + _emojiToText["☝️"] = ":point_up:"; + _textToEmoji[":raised_hand:"] = "✋"; + _emojiToText["✋"] = ":raised_hand:"; + _textToEmoji[":raised_back_of_hand:"] = "🤚"; + _emojiToText["🤚"] = ":raised_back_of_hand:"; + _textToEmoji[":back_of_hand:"] = "🤚"; + _emojiToText["🤚"] = ":back_of_hand:"; + _textToEmoji[":hand_splayed:"] = "🖐️"; + _emojiToText["🖐️"] = ":hand_splayed:"; + _textToEmoji[":raised_hand_with_fingers_splayed:"] = "🖐️"; + _emojiToText["🖐️"] = ":raised_hand_with_fingers_splayed:"; + _textToEmoji[":vulcan:"] = "🖖"; + _emojiToText["🖖"] = ":vulcan:"; + _textToEmoji[":raised_hand_with_part_between_middle_and_ring_fingers:"] = "🖖"; + _emojiToText["🖖"] = ":raised_hand_with_part_between_middle_and_ring_fingers:"; + _textToEmoji[":vulcan_salute:"] = "🖖"; + _emojiToText["🖖"] = ":vulcan_salute:"; + _textToEmoji[":wave:"] = "👋"; + _emojiToText["👋"] = ":wave:"; + _textToEmoji[":waving_hand:"] = "👋"; + _emojiToText["👋"] = ":waving_hand:"; + _textToEmoji[":call_me:"] = "🤙"; + _emojiToText["🤙"] = ":call_me:"; + _textToEmoji[":call_me_hand:"] = "🤙"; + _emojiToText["🤙"] = ":call_me_hand:"; + _textToEmoji[":leftwards_hand:"] = "🫲"; + _emojiToText["🫲"] = ":leftwards_hand:"; + _textToEmoji[":rightwards_hand:"] = "🫱"; + _emojiToText["🫱"] = ":rightwards_hand:"; + _textToEmoji[":muscle:"] = "💪"; + _emojiToText["💪"] = ":muscle:"; + _textToEmoji[":flexed_biceps:"] = "💪"; + _emojiToText["💪"] = ":flexed_biceps:"; + _textToEmoji[":mechanical_arm:"] = "🦾"; + _emojiToText["🦾"] = ":mechanical_arm:"; + _textToEmoji[":middle_finger:"] = "🖕"; + _emojiToText["🖕"] = ":middle_finger:"; + _textToEmoji[":reversed_hand_with_middle_finger_extended:"] = "🖕"; + _emojiToText["🖕"] = ":reversed_hand_with_middle_finger_extended:"; + _textToEmoji[":writing_hand:"] = "✍️"; + _emojiToText["✍️"] = ":writing_hand:"; + _textToEmoji[":pray:"] = "🙏"; + _emojiToText["🙏"] = ":pray:"; + _textToEmoji[":folded_hands:"] = "🙏"; + _emojiToText["🙏"] = ":folded_hands:"; + _textToEmoji[":index_pointing_at_the_viewer:"] = "🫵"; + _emojiToText["🫵"] = ":index_pointing_at_the_viewer:"; + _textToEmoji[":foot:"] = "🦶"; + _emojiToText["🦶"] = ":foot:"; + _textToEmoji[":leg:"] = "🦵"; + _emojiToText["🦵"] = ":leg:"; + _textToEmoji[":mechanical_leg:"] = "🦿"; + _emojiToText["🦿"] = ":mechanical_leg:"; + _textToEmoji[":lipstick:"] = "💄"; + _emojiToText["💄"] = ":lipstick:"; + _textToEmoji[":kiss:"] = "💋"; + _emojiToText["💋"] = ":kiss:"; + _textToEmoji[":kiss_mark:"] = "💋"; + _emojiToText["💋"] = ":kiss_mark:"; + _textToEmoji[":lips:"] = "👄"; + _emojiToText["👄"] = ":lips:"; + _textToEmoji[":mouth:"] = "👄"; + _emojiToText["👄"] = ":mouth:"; + _textToEmoji[":biting_lip:"] = "🫦"; + _emojiToText["🫦"] = ":biting_lip:"; + _textToEmoji[":tooth:"] = "🦷"; + _emojiToText["🦷"] = ":tooth:"; + _textToEmoji[":tongue:"] = "👅"; + _emojiToText["👅"] = ":tongue:"; + _textToEmoji[":ear:"] = "👂"; + _emojiToText["👂"] = ":ear:"; + _textToEmoji[":ear_with_hearing_aid:"] = "🦻"; + _emojiToText["🦻"] = ":ear_with_hearing_aid:"; + _textToEmoji[":nose:"] = "👃"; + _emojiToText["👃"] = ":nose:"; + _textToEmoji[":footprints:"] = "👣"; + _emojiToText["👣"] = ":footprints:"; + _textToEmoji[":eye:"] = "👁️"; + _emojiToText["👁️"] = ":eye:"; + _textToEmoji[":eyes:"] = "👀"; + _emojiToText["👀"] = ":eyes:"; + _textToEmoji[":anatomical_heart:"] = "🫀"; + _emojiToText["🫀"] = ":anatomical_heart:"; + _textToEmoji[":lungs:"] = "🫁"; + _emojiToText["🫁"] = ":lungs:"; + _textToEmoji[":brain:"] = "🧠"; + _emojiToText["🧠"] = ":brain:"; + _textToEmoji[":speaking_head:"] = "🗣️"; + _emojiToText["🗣️"] = ":speaking_head:"; + _textToEmoji[":speaking_head_in_silhouette:"] = "🗣️"; + _emojiToText["🗣️"] = ":speaking_head_in_silhouette:"; + _textToEmoji[":bust_in_silhouette:"] = "👤"; + _emojiToText["👤"] = ":bust_in_silhouette:"; + _textToEmoji[":busts_in_silhouette:"] = "👥"; + _emojiToText["👥"] = ":busts_in_silhouette:"; + _textToEmoji[":people_hugging:"] = "🫂"; + _emojiToText["🫂"] = ":people_hugging:"; + _textToEmoji[":baby:"] = "👶"; + _emojiToText["👶"] = ":baby:"; + _textToEmoji[":child:"] = "🧒"; + _emojiToText["🧒"] = ":child:"; + _textToEmoji[":girl:"] = "👧"; + _emojiToText["👧"] = ":girl:"; + _textToEmoji[":boy:"] = "👦"; + _emojiToText["👦"] = ":boy:"; + _textToEmoji[":adult:"] = "🧑"; + _emojiToText["🧑"] = ":adult:"; + _textToEmoji[":person:"] = "🧑"; + _emojiToText["🧑"] = ":person:"; + _textToEmoji[":woman:"] = "👩"; + _emojiToText["👩"] = ":woman:"; + _textToEmoji[":man:"] = "👨"; + _emojiToText["👨"] = ":man:"; + _textToEmoji[":person_curly_hair:"] = "🧑‍🦱"; + _emojiToText["🧑‍🦱"] = ":person_curly_hair:"; + _textToEmoji[":woman_curly_haired:"] = "👩‍🦱"; + _emojiToText["👩‍🦱"] = ":woman_curly_haired:"; + _textToEmoji[":man_curly_haired:"] = "👨‍🦱"; + _emojiToText["👨‍🦱"] = ":man_curly_haired:"; + _textToEmoji[":person_red_hair:"] = "🧑‍🦰"; + _emojiToText["🧑‍🦰"] = ":person_red_hair:"; + _textToEmoji[":woman_red_haired:"] = "👩‍🦰"; + _emojiToText["👩‍🦰"] = ":woman_red_haired:"; + _textToEmoji[":man_red_haired:"] = "👨‍🦰"; + _emojiToText["👨‍🦰"] = ":man_red_haired:"; + _textToEmoji[":man_red_hair:"] = "👨‍🦰"; + _emojiToText["👨‍🦰"] = ":man_red_hair:"; + _textToEmoji[":blond_haired_person:"] = "👱"; + _emojiToText["👱"] = ":blond_haired_person:"; + _textToEmoji[":person_with_blond_hair:"] = "👱"; + _emojiToText["👱"] = ":person_with_blond_hair:"; + _textToEmoji[":blond_haired_woman:"] = "👱‍♀️"; + _emojiToText["👱‍♀️"] = ":blond_haired_woman:"; + _textToEmoji[":blond_haired_man:"] = "👱‍♂️"; + _emojiToText["👱‍♂️"] = ":blond_haired_man:"; + _textToEmoji[":person_white_hair:"] = "🧑‍🦳"; + _emojiToText["🧑‍🦳"] = ":person_white_hair:"; + _textToEmoji[":woman_white_haired:"] = "👩‍🦳"; + _emojiToText["👩‍🦳"] = ":woman_white_haired:"; + _textToEmoji[":man_white_haired:"] = "👨‍🦳"; + _emojiToText["👨‍🦳"] = ":man_white_haired:"; + _textToEmoji[":person_bald:"] = "🧑‍🦲"; + _emojiToText["🧑‍🦲"] = ":person_bald:"; + _textToEmoji[":woman_bald:"] = "👩‍🦲"; + _emojiToText["👩‍🦲"] = ":woman_bald:"; + _textToEmoji[":man_bald:"] = "👨‍🦲"; + _emojiToText["👨‍🦲"] = ":man_bald:"; + _textToEmoji[":bearded_person:"] = "🧔"; + _emojiToText["🧔"] = ":bearded_person:"; + _textToEmoji[":person_beard:"] = "🧔"; + _emojiToText["🧔"] = ":person_beard:"; + _textToEmoji[":woman_beard:"] = "🧔‍♀️"; + _emojiToText["🧔‍♀️"] = ":woman_beard:"; + _textToEmoji[":man_beard:"] = "🧔‍♂️"; + _emojiToText["🧔‍♂️"] = ":man_beard:"; + _textToEmoji[":older_adult:"] = "🧓"; + _emojiToText["🧓"] = ":older_adult:"; + _textToEmoji[":older_person:"] = "🧓"; + _emojiToText["🧓"] = ":older_person:"; + _textToEmoji[":older_woman:"] = "👵"; + _emojiToText["👵"] = ":older_woman:"; + _textToEmoji[":grandma:"] = "👵"; + _emojiToText["👵"] = ":grandma:"; + _textToEmoji[":old_woman:"] = "👵"; + _emojiToText["👵"] = ":old_woman:"; + _textToEmoji[":older_man:"] = "👴"; + _emojiToText["👴"] = ":older_man:"; + _textToEmoji[":old_man:"] = "👴"; + _emojiToText["👴"] = ":old_man:"; + _textToEmoji[":man_with_chinese_cap:"] = "👲"; + _emojiToText["👲"] = ":man_with_chinese_cap:"; + _textToEmoji[":man_with_gua_pi_mao:"] = "👲"; + _emojiToText["👲"] = ":man_with_gua_pi_mao:"; + _textToEmoji[":person_wearing_turban:"] = "👳"; + _emojiToText["👳"] = ":person_wearing_turban:"; + _textToEmoji[":man_with_turban:"] = "👳"; + _emojiToText["👳"] = ":man_with_turban:"; + _textToEmoji[":woman_wearing_turban:"] = "👳‍♀️"; + _emojiToText["👳‍♀️"] = ":woman_wearing_turban:"; + _textToEmoji[":man_wearing_turban:"] = "👳‍♂️"; + _emojiToText["👳‍♂️"] = ":man_wearing_turban:"; + _textToEmoji[":woman_with_headscarf:"] = "🧕"; + _emojiToText["🧕"] = ":woman_with_headscarf:"; + _textToEmoji[":police_officer:"] = "👮"; + _emojiToText["👮"] = ":police_officer:"; + _textToEmoji[":cop:"] = "👮"; + _emojiToText["👮"] = ":cop:"; + _textToEmoji[":woman_police_officer:"] = "👮‍♀️"; + _emojiToText["👮‍♀️"] = ":woman_police_officer:"; + _textToEmoji[":man_police_officer:"] = "👮‍♂️"; + _emojiToText["👮‍♂️"] = ":man_police_officer:"; + _textToEmoji[":construction_worker:"] = "👷"; + _emojiToText["👷"] = ":construction_worker:"; + _textToEmoji[":woman_construction_worker:"] = "👷‍♀️"; + _emojiToText["👷‍♀️"] = ":woman_construction_worker:"; + _textToEmoji[":man_construction_worker:"] = "👷‍♂️"; + _emojiToText["👷‍♂️"] = ":man_construction_worker:"; + _textToEmoji[":guard:"] = "💂"; + _emojiToText["💂"] = ":guard:"; + _textToEmoji[":guardsman:"] = "💂"; + _emojiToText["💂"] = ":guardsman:"; + _textToEmoji[":woman_guard:"] = "💂‍♀️"; + _emojiToText["💂‍♀️"] = ":woman_guard:"; + _textToEmoji[":man_guard:"] = "💂‍♂️"; + _emojiToText["💂‍♂️"] = ":man_guard:"; + _textToEmoji[":detective:"] = "🕵️"; + _emojiToText["🕵️"] = ":detective:"; + _textToEmoji[":spy:"] = "🕵️"; + _emojiToText["🕵️"] = ":spy:"; + _textToEmoji[":sleuth_or_spy:"] = "🕵️"; + _emojiToText["🕵️"] = ":sleuth_or_spy:"; + _textToEmoji[":woman_detective:"] = "🕵️‍♀️"; + _emojiToText["🕵️‍♀️"] = ":woman_detective:"; + _textToEmoji[":man_detective:"] = "🕵️‍♂️"; + _emojiToText["🕵️‍♂️"] = ":man_detective:"; + _textToEmoji[":health_worker:"] = "🧑‍⚕️"; + _emojiToText["🧑‍⚕️"] = ":health_worker:"; + _textToEmoji[":woman_health_worker:"] = "👩‍⚕️"; + _emojiToText["👩‍⚕️"] = ":woman_health_worker:"; + _textToEmoji[":man_health_worker:"] = "👨‍⚕️"; + _emojiToText["👨‍⚕️"] = ":man_health_worker:"; + _textToEmoji[":farmer:"] = "🧑‍🌾"; + _emojiToText["🧑‍🌾"] = ":farmer:"; + _textToEmoji[":woman_farmer:"] = "👩‍🌾"; + _emojiToText["👩‍🌾"] = ":woman_farmer:"; + _textToEmoji[":man_farmer:"] = "👨‍🌾"; + _emojiToText["👨‍🌾"] = ":man_farmer:"; + _textToEmoji[":cook:"] = "🧑‍🍳"; + _emojiToText["🧑‍🍳"] = ":cook:"; + _textToEmoji[":woman_cook:"] = "👩‍🍳"; + _emojiToText["👩‍🍳"] = ":woman_cook:"; + _textToEmoji[":man_cook:"] = "👨‍🍳"; + _emojiToText["👨‍🍳"] = ":man_cook:"; + _textToEmoji[":student:"] = "🧑‍🎓"; + _emojiToText["🧑‍🎓"] = ":student:"; + _textToEmoji[":woman_student:"] = "👩‍🎓"; + _emojiToText["👩‍🎓"] = ":woman_student:"; + _textToEmoji[":man_student:"] = "👨‍🎓"; + _emojiToText["👨‍🎓"] = ":man_student:"; + _textToEmoji[":singer:"] = "🧑‍🎤"; + _emojiToText["🧑‍🎤"] = ":singer:"; + _textToEmoji[":woman_singer:"] = "👩‍🎤"; + _emojiToText["👩‍🎤"] = ":woman_singer:"; + _textToEmoji[":man_singer:"] = "👨‍🎤"; + _emojiToText["👨‍🎤"] = ":man_singer:"; + _textToEmoji[":teacher:"] = "🧑‍🏫"; + _emojiToText["🧑‍🏫"] = ":teacher:"; + _textToEmoji[":woman_teacher:"] = "👩‍🏫"; + _emojiToText["👩‍🏫"] = ":woman_teacher:"; + _textToEmoji[":man_teacher:"] = "👨‍🏫"; + _emojiToText["👨‍🏫"] = ":man_teacher:"; + _textToEmoji[":factory_worker:"] = "🧑‍🏭"; + _emojiToText["🧑‍🏭"] = ":factory_worker:"; + _textToEmoji[":woman_factory_worker:"] = "👩‍🏭"; + _emojiToText["👩‍🏭"] = ":woman_factory_worker:"; + _textToEmoji[":man_factory_worker:"] = "👨‍🏭"; + _emojiToText["👨‍🏭"] = ":man_factory_worker:"; + _textToEmoji[":technologist:"] = "🧑‍💻"; + _emojiToText["🧑‍💻"] = ":technologist:"; + _textToEmoji[":woman_technologist:"] = "👩‍💻"; + _emojiToText["👩‍💻"] = ":woman_technologist:"; + _textToEmoji[":man_technologist:"] = "👨‍💻"; + _emojiToText["👨‍💻"] = ":man_technologist:"; + _textToEmoji[":office_worker:"] = "🧑‍💼"; + _emojiToText["🧑‍💼"] = ":office_worker:"; + _textToEmoji[":woman_office_worker:"] = "👩‍💼"; + _emojiToText["👩‍💼"] = ":woman_office_worker:"; + _textToEmoji[":man_office_worker:"] = "👨‍💼"; + _emojiToText["👨‍💼"] = ":man_office_worker:"; + _textToEmoji[":mechanic:"] = "🧑‍🔧"; + _emojiToText["🧑‍🔧"] = ":mechanic:"; + _textToEmoji[":woman_mechanic:"] = "👩‍🔧"; + _emojiToText["👩‍🔧"] = ":woman_mechanic:"; + _textToEmoji[":man_mechanic:"] = "👨‍🔧"; + _emojiToText["👨‍🔧"] = ":man_mechanic:"; + _textToEmoji[":scientist:"] = "🧑‍🔬"; + _emojiToText["🧑‍🔬"] = ":scientist:"; + _textToEmoji[":woman_scientist:"] = "👩‍🔬"; + _emojiToText["👩‍🔬"] = ":woman_scientist:"; + _textToEmoji[":man_scientist:"] = "👨‍🔬"; + _emojiToText["👨‍🔬"] = ":man_scientist:"; + _textToEmoji[":artist:"] = "🧑‍🎨"; + _emojiToText["🧑‍🎨"] = ":artist:"; + _textToEmoji[":woman_artist:"] = "👩‍🎨"; + _emojiToText["👩‍🎨"] = ":woman_artist:"; + _textToEmoji[":man_artist:"] = "👨‍🎨"; + _emojiToText["👨‍🎨"] = ":man_artist:"; + _textToEmoji[":firefighter:"] = "🧑‍🚒"; + _emojiToText["🧑‍🚒"] = ":firefighter:"; + _textToEmoji[":woman_firefighter:"] = "👩‍🚒"; + _emojiToText["👩‍🚒"] = ":woman_firefighter:"; + _textToEmoji[":man_firefighter:"] = "👨‍🚒"; + _emojiToText["👨‍🚒"] = ":man_firefighter:"; + _textToEmoji[":pilot:"] = "🧑‍✈️"; + _emojiToText["🧑‍✈️"] = ":pilot:"; + _textToEmoji[":woman_pilot:"] = "👩‍✈️"; + _emojiToText["👩‍✈️"] = ":woman_pilot:"; + _textToEmoji[":man_pilot:"] = "👨‍✈️"; + _emojiToText["👨‍✈️"] = ":man_pilot:"; + _textToEmoji[":astronaut:"] = "🧑‍🚀"; + _emojiToText["🧑‍🚀"] = ":astronaut:"; + _textToEmoji[":woman_astronaut:"] = "👩‍🚀"; + _emojiToText["👩‍🚀"] = ":woman_astronaut:"; + _textToEmoji[":man_astronaut:"] = "👨‍🚀"; + _emojiToText["👨‍🚀"] = ":man_astronaut:"; + _textToEmoji[":judge:"] = "🧑‍⚖️"; + _emojiToText["🧑‍⚖️"] = ":judge:"; + _textToEmoji[":woman_judge:"] = "👩‍⚖️"; + _emojiToText["👩‍⚖️"] = ":woman_judge:"; + _textToEmoji[":man_judge:"] = "👨‍⚖️"; + _emojiToText["👨‍⚖️"] = ":man_judge:"; + _textToEmoji[":person_with_veil:"] = "👰"; + _emojiToText["👰"] = ":person_with_veil:"; + _textToEmoji[":woman_with_veil:"] = "👰‍♀️"; + _emojiToText["👰‍♀️"] = ":woman_with_veil:"; + _textToEmoji[":bride_with_veil:"] = "👰‍♀️"; + _emojiToText["👰‍♀️"] = ":bride_with_veil:"; + _textToEmoji[":man_with_veil:"] = "👰‍♂️"; + _emojiToText["👰‍♂️"] = ":man_with_veil:"; + _textToEmoji[":person_in_tuxedo:"] = "🤵"; + _emojiToText["🤵"] = ":person_in_tuxedo:"; + _textToEmoji[":woman_in_tuxedo:"] = "🤵‍♀️"; + _emojiToText["🤵‍♀️"] = ":woman_in_tuxedo:"; + _textToEmoji[":man_in_tuxedo:"] = "🤵‍♂️"; + _emojiToText["🤵‍♂️"] = ":man_in_tuxedo:"; + _textToEmoji[":person_with_crown:"] = "🫅"; + _emojiToText["🫅"] = ":person_with_crown:"; + _textToEmoji[":princess:"] = "👸"; + _emojiToText["👸"] = ":princess:"; + _textToEmoji[":prince:"] = "🤴"; + _emojiToText["🤴"] = ":prince:"; + _textToEmoji[":superhero:"] = "🦸"; + _emojiToText["🦸"] = ":superhero:"; + _textToEmoji[":woman_superhero:"] = "🦸‍♀️"; + _emojiToText["🦸‍♀️"] = ":woman_superhero:"; + _textToEmoji[":man_superhero:"] = "🦸‍♂️"; + _emojiToText["🦸‍♂️"] = ":man_superhero:"; + _textToEmoji[":supervillain:"] = "🦹"; + _emojiToText["🦹"] = ":supervillain:"; + _textToEmoji[":woman_supervillain:"] = "🦹‍♀️"; + _emojiToText["🦹‍♀️"] = ":woman_supervillain:"; + _textToEmoji[":man_supervillain:"] = "🦹‍♂️"; + _emojiToText["🦹‍♂️"] = ":man_supervillain:"; + _textToEmoji[":ninja:"] = "🥷"; + _emojiToText["🥷"] = ":ninja:"; + _textToEmoji[":mx_claus:"] = "🧑‍🎄"; + _emojiToText["🧑‍🎄"] = ":mx_claus:"; + _textToEmoji[":mrs_claus:"] = "🤶"; + _emojiToText["🤶"] = ":mrs_claus:"; + _textToEmoji[":mother_christmas:"] = "🤶"; + _emojiToText["🤶"] = ":mother_christmas:"; + _textToEmoji[":santa:"] = "🎅"; + _emojiToText["🎅"] = ":santa:"; + _textToEmoji[":santa_claus:"] = "🎅"; + _emojiToText["🎅"] = ":santa_claus:"; + _textToEmoji[":mage:"] = "🧙"; + _emojiToText["🧙"] = ":mage:"; + _textToEmoji[":woman_mage:"] = "🧙‍♀️"; + _emojiToText["🧙‍♀️"] = ":woman_mage:"; + _textToEmoji[":man_mage:"] = "🧙‍♂️"; + _emojiToText["🧙‍♂️"] = ":man_mage:"; + _textToEmoji[":elf:"] = "🧝"; + _emojiToText["🧝"] = ":elf:"; + _textToEmoji[":woman_elf:"] = "🧝‍♀️"; + _emojiToText["🧝‍♀️"] = ":woman_elf:"; + _textToEmoji[":man_elf:"] = "🧝‍♂️"; + _emojiToText["🧝‍♂️"] = ":man_elf:"; + _textToEmoji[":troll:"] = "🧌"; + _emojiToText["🧌"] = ":troll:"; + _textToEmoji[":vampire:"] = "🧛"; + _emojiToText["🧛"] = ":vampire:"; + _textToEmoji[":woman_vampire:"] = "🧛‍♀️"; + _emojiToText["🧛‍♀️"] = ":woman_vampire:"; + _textToEmoji[":man_vampire:"] = "🧛‍♂️"; + _emojiToText["🧛‍♂️"] = ":man_vampire:"; + _textToEmoji[":zombie:"] = "🧟"; + _emojiToText["🧟"] = ":zombie:"; + _textToEmoji[":woman_zombie:"] = "🧟‍♀️"; + _emojiToText["🧟‍♀️"] = ":woman_zombie:"; + _textToEmoji[":man_zombie:"] = "🧟‍♂️"; + _emojiToText["🧟‍♂️"] = ":man_zombie:"; + _textToEmoji[":genie:"] = "🧞"; + _emojiToText["🧞"] = ":genie:"; + _textToEmoji[":woman_genie:"] = "🧞‍♀️"; + _emojiToText["🧞‍♀️"] = ":woman_genie:"; + _textToEmoji[":man_genie:"] = "🧞‍♂️"; + _emojiToText["🧞‍♂️"] = ":man_genie:"; + _textToEmoji[":merperson:"] = "🧜"; + _emojiToText["🧜"] = ":merperson:"; + _textToEmoji[":mermaid:"] = "🧜‍♀️"; + _emojiToText["🧜‍♀️"] = ":mermaid:"; + _textToEmoji[":merman:"] = "🧜‍♂️"; + _emojiToText["🧜‍♂️"] = ":merman:"; + _textToEmoji[":fairy:"] = "🧚"; + _emojiToText["🧚"] = ":fairy:"; + _textToEmoji[":woman_fairy:"] = "🧚‍♀️"; + _emojiToText["🧚‍♀️"] = ":woman_fairy:"; + _textToEmoji[":man_fairy:"] = "🧚‍♂️"; + _emojiToText["🧚‍♂️"] = ":man_fairy:"; + _textToEmoji[":angel:"] = "👼"; + _emojiToText["👼"] = ":angel:"; + _textToEmoji[":baby_angel:"] = "👼"; + _emojiToText["👼"] = ":baby_angel:"; + _textToEmoji[":pregnant_person:"] = "🫄"; + _emojiToText["🫄"] = ":pregnant_person:"; + _textToEmoji[":pregnant_woman:"] = "🤰"; + _emojiToText["🤰"] = ":pregnant_woman:"; + _textToEmoji[":expecting_woman:"] = "🤰"; + _emojiToText["🤰"] = ":expecting_woman:"; + _textToEmoji[":pregnant_man:"] = "🫃"; + _emojiToText["🫃"] = ":pregnant_man:"; + _textToEmoji[":breast_feeding:"] = "🤱"; + _emojiToText["🤱"] = ":breast_feeding:"; + _textToEmoji[":person_feeding_baby:"] = "🧑‍🍼"; + _emojiToText["🧑‍🍼"] = ":person_feeding_baby:"; + _textToEmoji[":woman_feeding_baby:"] = "👩‍🍼"; + _emojiToText["👩‍🍼"] = ":woman_feeding_baby:"; + _textToEmoji[":man_feeding_baby:"] = "👨‍🍼"; + _emojiToText["👨‍🍼"] = ":man_feeding_baby:"; + _textToEmoji[":person_bowing:"] = "🙇"; + _emojiToText["🙇"] = ":person_bowing:"; + _textToEmoji[":bow:"] = "🙇"; + _emojiToText["🙇"] = ":bow:"; + _textToEmoji[":woman_bowing:"] = "🙇‍♀️"; + _emojiToText["🙇‍♀️"] = ":woman_bowing:"; + _textToEmoji[":man_bowing:"] = "🙇‍♂️"; + _emojiToText["🙇‍♂️"] = ":man_bowing:"; + _textToEmoji[":person_tipping_hand:"] = "💁"; + _emojiToText["💁"] = ":person_tipping_hand:"; + _textToEmoji[":information_desk_person:"] = "💁"; + _emojiToText["💁"] = ":information_desk_person:"; + _textToEmoji[":woman_tipping_hand:"] = "💁‍♀️"; + _emojiToText["💁‍♀️"] = ":woman_tipping_hand:"; + _textToEmoji[":man_tipping_hand:"] = "💁‍♂️"; + _emojiToText["💁‍♂️"] = ":man_tipping_hand:"; + _textToEmoji[":person_gesturing_no:"] = "🙅"; + _emojiToText["🙅"] = ":person_gesturing_no:"; + _textToEmoji[":no_good:"] = "🙅"; + _emojiToText["🙅"] = ":no_good:"; + _textToEmoji[":woman_gesturing_no:"] = "🙅‍♀️"; + _emojiToText["🙅‍♀️"] = ":woman_gesturing_no:"; + _textToEmoji[":man_gesturing_no:"] = "🙅‍♂️"; + _emojiToText["🙅‍♂️"] = ":man_gesturing_no:"; + _textToEmoji[":person_gesturing_ok:"] = "🙆"; + _emojiToText["🙆"] = ":person_gesturing_ok:"; + _textToEmoji[":woman_gesturing_ok:"] = "🙆‍♀️"; + _emojiToText["🙆‍♀️"] = ":woman_gesturing_ok:"; + _textToEmoji[":man_gesturing_ok:"] = "🙆‍♂️"; + _emojiToText["🙆‍♂️"] = ":man_gesturing_ok:"; + _textToEmoji[":person_raising_hand:"] = "🙋"; + _emojiToText["🙋"] = ":person_raising_hand:"; + _textToEmoji[":raising_hand:"] = "🙋"; + _emojiToText["🙋"] = ":raising_hand:"; + _textToEmoji[":woman_raising_hand:"] = "🙋‍♀️"; + _emojiToText["🙋‍♀️"] = ":woman_raising_hand:"; + _textToEmoji[":man_raising_hand:"] = "🙋‍♂️"; + _emojiToText["🙋‍♂️"] = ":man_raising_hand:"; + _textToEmoji[":deaf_person:"] = "🧏"; + _emojiToText["🧏"] = ":deaf_person:"; + _textToEmoji[":deaf_woman:"] = "🧏‍♀️"; + _emojiToText["🧏‍♀️"] = ":deaf_woman:"; + _textToEmoji[":deaf_man:"] = "🧏‍♂️"; + _emojiToText["🧏‍♂️"] = ":deaf_man:"; + _textToEmoji[":person_facepalming:"] = "🤦"; + _emojiToText["🤦"] = ":person_facepalming:"; + _textToEmoji[":face_palm:"] = "🤦"; + _emojiToText["🤦"] = ":face_palm:"; + _textToEmoji[":facepalm:"] = "🤦"; + _emojiToText["🤦"] = ":facepalm:"; + _textToEmoji[":woman_facepalming:"] = "🤦‍♀️"; + _emojiToText["🤦‍♀️"] = ":woman_facepalming:"; + _textToEmoji[":man_facepalming:"] = "🤦‍♂️"; + _emojiToText["🤦‍♂️"] = ":man_facepalming:"; + _textToEmoji[":person_shrugging:"] = "🤷"; + _emojiToText["🤷"] = ":person_shrugging:"; + _textToEmoji[":shrug:"] = "🤷"; + _emojiToText["🤷"] = ":shrug:"; + _textToEmoji[":woman_shrugging:"] = "🤷‍♀️"; + _emojiToText["🤷‍♀️"] = ":woman_shrugging:"; + _textToEmoji[":man_shrugging:"] = "🤷‍♂️"; + _emojiToText["🤷‍♂️"] = ":man_shrugging:"; + _textToEmoji[":person_pouting:"] = "🙎"; + _emojiToText["🙎"] = ":person_pouting:"; + _textToEmoji[":person_with_pouting_face:"] = "🙎"; + _emojiToText["🙎"] = ":person_with_pouting_face:"; + _textToEmoji[":woman_pouting:"] = "🙎‍♀️"; + _emojiToText["🙎‍♀️"] = ":woman_pouting:"; + _textToEmoji[":man_pouting:"] = "🙎‍♂️"; + _emojiToText["🙎‍♂️"] = ":man_pouting:"; + _textToEmoji[":person_frowning:"] = "🙍"; + _emojiToText["🙍"] = ":person_frowning:"; + _textToEmoji[":woman_frowning:"] = "🙍‍♀️"; + _emojiToText["🙍‍♀️"] = ":woman_frowning:"; + _textToEmoji[":man_frowning:"] = "🙍‍♂️"; + _emojiToText["🙍‍♂️"] = ":man_frowning:"; + _textToEmoji[":person_getting_haircut:"] = "💇"; + _emojiToText["💇"] = ":person_getting_haircut:"; + _textToEmoji[":haircut:"] = "💇"; + _emojiToText["💇"] = ":haircut:"; + _textToEmoji[":woman_getting_haircut:"] = "💇‍♀️"; + _emojiToText["💇‍♀️"] = ":woman_getting_haircut:"; + _textToEmoji[":man_getting_haircut:"] = "💇‍♂️"; + _emojiToText["💇‍♂️"] = ":man_getting_haircut:"; + _textToEmoji[":person_getting_massage:"] = "💆"; + _emojiToText["💆"] = ":person_getting_massage:"; + _textToEmoji[":massage:"] = "💆"; + _emojiToText["💆"] = ":massage:"; + _textToEmoji[":woman_getting_face_massage:"] = "💆‍♀️"; + _emojiToText["💆‍♀️"] = ":woman_getting_face_massage:"; + _textToEmoji[":man_getting_face_massage:"] = "💆‍♂️"; + _emojiToText["💆‍♂️"] = ":man_getting_face_massage:"; + _textToEmoji[":person_in_steamy_room:"] = "🧖"; + _emojiToText["🧖"] = ":person_in_steamy_room:"; + _textToEmoji[":woman_in_steamy_room:"] = "🧖‍♀️"; + _emojiToText["🧖‍♀️"] = ":woman_in_steamy_room:"; + _textToEmoji[":man_in_steamy_room:"] = "🧖‍♂️"; + _emojiToText["🧖‍♂️"] = ":man_in_steamy_room:"; + _textToEmoji[":nail_care:"] = "💅"; + _emojiToText["💅"] = ":nail_care:"; + _textToEmoji[":nail_polish:"] = "💅"; + _emojiToText["💅"] = ":nail_polish:"; + _textToEmoji[":selfie:"] = "🤳"; + _emojiToText["🤳"] = ":selfie:"; + _textToEmoji[":dancer:"] = "💃"; + _emojiToText["💃"] = ":dancer:"; + _textToEmoji[":woman_dancing:"] = "💃"; + _emojiToText["💃"] = ":woman_dancing:"; + _textToEmoji[":man_dancing:"] = "🕺"; + _emojiToText["🕺"] = ":man_dancing:"; + _textToEmoji[":male_dancer:"] = "🕺"; + _emojiToText["🕺"] = ":male_dancer:"; + _textToEmoji[":people_with_bunny_ears_partying:"] = "👯"; + _emojiToText["👯"] = ":people_with_bunny_ears_partying:"; + _textToEmoji[":dancers:"] = "👯"; + _emojiToText["👯"] = ":dancers:"; + _textToEmoji[":women_with_bunny_ears_partying:"] = "👯‍♀️"; + _emojiToText["👯‍♀️"] = ":women_with_bunny_ears_partying:"; + _textToEmoji[":men_with_bunny_ears_partying:"] = "👯‍♂️"; + _emojiToText["👯‍♂️"] = ":men_with_bunny_ears_partying:"; + _textToEmoji[":levitate:"] = "🕴️"; + _emojiToText["🕴️"] = ":levitate:"; + _textToEmoji[":man_in_business_suit_levitating:"] = "🕴️"; + _emojiToText["🕴️"] = ":man_in_business_suit_levitating:"; + _textToEmoji[":person_in_manual_wheelchair:"] = "🧑‍🦽"; + _emojiToText["🧑‍🦽"] = ":person_in_manual_wheelchair:"; + _textToEmoji[":woman_in_manual_wheelchair:"] = "👩‍🦽"; + _emojiToText["👩‍🦽"] = ":woman_in_manual_wheelchair:"; + _textToEmoji[":man_in_manual_wheelchair:"] = "👨‍🦽"; + _emojiToText["👨‍🦽"] = ":man_in_manual_wheelchair:"; + _textToEmoji[":person_in_motorized_wheelchair:"] = "🧑‍🦼"; + _emojiToText["🧑‍🦼"] = ":person_in_motorized_wheelchair:"; + _textToEmoji[":woman_in_motorized_wheelchair:"] = "👩‍🦼"; + _emojiToText["👩‍🦼"] = ":woman_in_motorized_wheelchair:"; + _textToEmoji[":man_in_motorized_wheelchair:"] = "👨‍🦼"; + _emojiToText["👨‍🦼"] = ":man_in_motorized_wheelchair:"; + _textToEmoji[":person_walking:"] = "🚶"; + _emojiToText["🚶"] = ":person_walking:"; + _textToEmoji[":walking:"] = "🚶"; + _emojiToText["🚶"] = ":walking:"; + _textToEmoji[":woman_walking:"] = "🚶‍♀️"; + _emojiToText["🚶‍♀️"] = ":woman_walking:"; + _textToEmoji[":man_walking:"] = "🚶‍♂️"; + _emojiToText["🚶‍♂️"] = ":man_walking:"; + _textToEmoji[":person_with_probing_cane:"] = "🧑‍🦯"; + _emojiToText["🧑‍🦯"] = ":person_with_probing_cane:"; + _textToEmoji[":woman_with_probing_cane:"] = "👩‍🦯"; + _emojiToText["👩‍🦯"] = ":woman_with_probing_cane:"; + _textToEmoji[":man_with_probing_cane:"] = "👨‍🦯"; + _emojiToText["👨‍🦯"] = ":man_with_probing_cane:"; + _textToEmoji[":person_kneeling:"] = "🧎"; + _emojiToText["🧎"] = ":person_kneeling:"; + _textToEmoji[":woman_kneeling:"] = "🧎‍♀️"; + _emojiToText["🧎‍♀️"] = ":woman_kneeling:"; + _textToEmoji[":man_kneeling:"] = "🧎‍♂️"; + _emojiToText["🧎‍♂️"] = ":man_kneeling:"; + _textToEmoji[":person_running:"] = "🏃"; + _emojiToText["🏃"] = ":person_running:"; + _textToEmoji[":runner:"] = "🏃"; + _emojiToText["🏃"] = ":runner:"; + _textToEmoji[":woman_running:"] = "🏃‍♀️"; + _emojiToText["🏃‍♀️"] = ":woman_running:"; + _textToEmoji[":man_running:"] = "🏃‍♂️"; + _emojiToText["🏃‍♂️"] = ":man_running:"; + _textToEmoji[":person_standing:"] = "🧍"; + _emojiToText["🧍"] = ":person_standing:"; + _textToEmoji[":woman_standing:"] = "🧍‍♀️"; + _emojiToText["🧍‍♀️"] = ":woman_standing:"; + _textToEmoji[":man_standing:"] = "🧍‍♂️"; + _emojiToText["🧍‍♂️"] = ":man_standing:"; + _textToEmoji[":people_holding_hands:"] = "🧑‍🤝‍🧑"; + _emojiToText["🧑‍🤝‍🧑"] = ":people_holding_hands:"; + _textToEmoji[":couple:"] = "👫"; + _emojiToText["👫"] = ":couple:"; + _textToEmoji[":two_women_holding_hands:"] = "👭"; + _emojiToText["👭"] = ":two_women_holding_hands:"; + _textToEmoji[":two_men_holding_hands:"] = "👬"; + _emojiToText["👬"] = ":two_men_holding_hands:"; + _textToEmoji[":couple_with_heart:"] = "💑"; + _emojiToText["💑"] = ":couple_with_heart:"; + _textToEmoji[":couple_with_heart_woman_man:"] = "👩‍❤️‍👨"; + _emojiToText["👩‍❤️‍👨"] = ":couple_with_heart_woman_man:"; + _textToEmoji[":couple_ww:"] = "👩‍❤️‍👩"; + _emojiToText["👩‍❤️‍👩"] = ":couple_ww:"; + _textToEmoji[":couple_with_heart_ww:"] = "👩‍❤️‍👩"; + _emojiToText["👩‍❤️‍👩"] = ":couple_with_heart_ww:"; + _textToEmoji[":couple_mm:"] = "👨‍❤️‍👨"; + _emojiToText["👨‍❤️‍👨"] = ":couple_mm:"; + _textToEmoji[":couple_with_heart_mm:"] = "👨‍❤️‍👨"; + _emojiToText["👨‍❤️‍👨"] = ":couple_with_heart_mm:"; + _textToEmoji[":couplekiss:"] = "💏"; + _emojiToText["💏"] = ":couplekiss:"; + _textToEmoji[":kiss_woman_man:"] = "👩‍❤️‍💋‍👨"; + _emojiToText["👩‍❤️‍💋‍👨"] = ":kiss_woman_man:"; + _textToEmoji[":kiss_ww:"] = "👩‍❤️‍💋‍👩"; + _emojiToText["👩‍❤️‍💋‍👩"] = ":kiss_ww:"; + _textToEmoji[":couplekiss_ww:"] = "👩‍❤️‍💋‍👩"; + _emojiToText["👩‍❤️‍💋‍👩"] = ":couplekiss_ww:"; + _textToEmoji[":kiss_mm:"] = "👨‍❤️‍💋‍👨"; + _emojiToText["👨‍❤️‍💋‍👨"] = ":kiss_mm:"; + _textToEmoji[":couplekiss_mm:"] = "👨‍❤️‍💋‍👨"; + _emojiToText["👨‍❤️‍💋‍👨"] = ":couplekiss_mm:"; + _textToEmoji[":kiss_man_man:"] = "👨‍❤️‍💋‍👨"; + _emojiToText["👨‍❤️‍💋‍👨"] = ":kiss_man_man:"; + _textToEmoji[":family:"] = "👪"; + _emojiToText["👪"] = ":family:"; + _textToEmoji[":family_man_woman_boy:"] = "👨‍👩‍👦"; + _emojiToText["👨‍👩‍👦"] = ":family_man_woman_boy:"; + _textToEmoji[":family_mwg:"] = "👨‍👩‍👧"; + _emojiToText["👨‍👩‍👧"] = ":family_mwg:"; + _textToEmoji[":family_mwgb:"] = "👨‍👩‍👧‍👦"; + _emojiToText["👨‍👩‍👧‍👦"] = ":family_mwgb:"; + _textToEmoji[":family_mwbb:"] = "👨‍👩‍👦‍👦"; + _emojiToText["👨‍👩‍👦‍👦"] = ":family_mwbb:"; + _textToEmoji[":family_mwgg:"] = "👨‍👩‍👧‍👧"; + _emojiToText["👨‍👩‍👧‍👧"] = ":family_mwgg:"; + _textToEmoji[":family_wwb:"] = "👩‍👩‍👦"; + _emojiToText["👩‍👩‍👦"] = ":family_wwb:"; + _textToEmoji[":family_wwg:"] = "👩‍👩‍👧"; + _emojiToText["👩‍👩‍👧"] = ":family_wwg:"; + _textToEmoji[":family_wwgb:"] = "👩‍👩‍👧‍👦"; + _emojiToText["👩‍👩‍👧‍👦"] = ":family_wwgb:"; + _textToEmoji[":family_wwbb:"] = "👩‍👩‍👦‍👦"; + _emojiToText["👩‍👩‍👦‍👦"] = ":family_wwbb:"; + _textToEmoji[":family_wwgg:"] = "👩‍👩‍👧‍👧"; + _emojiToText["👩‍👩‍👧‍👧"] = ":family_wwgg:"; + _textToEmoji[":family_mmb:"] = "👨‍👨‍👦"; + _emojiToText["👨‍👨‍👦"] = ":family_mmb:"; + _textToEmoji[":family_mmg:"] = "👨‍👨‍👧"; + _emojiToText["👨‍👨‍👧"] = ":family_mmg:"; + _textToEmoji[":family_mmgb:"] = "👨‍👨‍👧‍👦"; + _emojiToText["👨‍👨‍👧‍👦"] = ":family_mmgb:"; + _textToEmoji[":family_mmbb:"] = "👨‍👨‍👦‍👦"; + _emojiToText["👨‍👨‍👦‍👦"] = ":family_mmbb:"; + _textToEmoji[":family_mmgg:"] = "👨‍👨‍👧‍👧"; + _emojiToText["👨‍👨‍👧‍👧"] = ":family_mmgg:"; + _textToEmoji[":family_woman_boy:"] = "👩‍👦"; + _emojiToText["👩‍👦"] = ":family_woman_boy:"; + _textToEmoji[":family_woman_girl:"] = "👩‍👧"; + _emojiToText["👩‍👧"] = ":family_woman_girl:"; + _textToEmoji[":family_woman_girl_boy:"] = "👩‍👧‍👦"; + _emojiToText["👩‍👧‍👦"] = ":family_woman_girl_boy:"; + _textToEmoji[":family_woman_boy_boy:"] = "👩‍👦‍👦"; + _emojiToText["👩‍👦‍👦"] = ":family_woman_boy_boy:"; + _textToEmoji[":family_woman_girl_girl:"] = "👩‍👧‍👧"; + _emojiToText["👩‍👧‍👧"] = ":family_woman_girl_girl:"; + _textToEmoji[":family_man_boy:"] = "👨‍👦"; + _emojiToText["👨‍👦"] = ":family_man_boy:"; + _textToEmoji[":family_man_girl:"] = "👨‍👧"; + _emojiToText["👨‍👧"] = ":family_man_girl:"; + _textToEmoji[":family_man_girl_boy:"] = "👨‍👧‍👦"; + _emojiToText["👨‍👧‍👦"] = ":family_man_girl_boy:"; + _textToEmoji[":family_man_boy_boy:"] = "👨‍👦‍👦"; + _emojiToText["👨‍👦‍👦"] = ":family_man_boy_boy:"; + _textToEmoji[":family_man_girl_girl:"] = "👨‍👧‍👧"; + _emojiToText["👨‍👧‍👧"] = ":family_man_girl_girl:"; + _textToEmoji[":knot:"] = "🪢"; + _emojiToText["🪢"] = ":knot:"; + _textToEmoji[":yarn:"] = "🧶"; + _emojiToText["🧶"] = ":yarn:"; + _textToEmoji[":thread:"] = "🧵"; + _emojiToText["🧵"] = ":thread:"; + _textToEmoji[":sewing_needle:"] = "🪡"; + _emojiToText["🪡"] = ":sewing_needle:"; + _textToEmoji[":coat:"] = "🧥"; + _emojiToText["🧥"] = ":coat:"; + _textToEmoji[":lab_coat:"] = "🥼"; + _emojiToText["🥼"] = ":lab_coat:"; + _textToEmoji[":safety_vest:"] = "🦺"; + _emojiToText["🦺"] = ":safety_vest:"; + _textToEmoji[":womans_clothes:"] = "👚"; + _emojiToText["👚"] = ":womans_clothes:"; + _textToEmoji[":shirt:"] = "👕"; + _emojiToText["👕"] = ":shirt:"; + _textToEmoji[":t_shirt:"] = "👕"; + _emojiToText["👕"] = ":t_shirt:"; + _textToEmoji[":jeans:"] = "👖"; + _emojiToText["👖"] = ":jeans:"; + _textToEmoji[":briefs:"] = "🩲"; + _emojiToText["🩲"] = ":briefs:"; + _textToEmoji[":shorts:"] = "🩳"; + _emojiToText["🩳"] = ":shorts:"; + _textToEmoji[":necktie:"] = "👔"; + _emojiToText["👔"] = ":necktie:"; + _textToEmoji[":dress:"] = "👗"; + _emojiToText["👗"] = ":dress:"; + _textToEmoji[":bikini:"] = "👙"; + _emojiToText["👙"] = ":bikini:"; + _textToEmoji[":one_piece_swimsuit:"] = "🩱"; + _emojiToText["🩱"] = ":one_piece_swimsuit:"; + _textToEmoji[":kimono:"] = "👘"; + _emojiToText["👘"] = ":kimono:"; + _textToEmoji[":sari:"] = "🥻"; + _emojiToText["🥻"] = ":sari:"; + _textToEmoji[":thong_sandal:"] = "🩴"; + _emojiToText["🩴"] = ":thong_sandal:"; + _textToEmoji[":womans_flat_shoe:"] = "🥿"; + _emojiToText["🥿"] = ":womans_flat_shoe:"; + _textToEmoji[":flat_shoe:"] = "🥿"; + _emojiToText["🥿"] = ":flat_shoe:"; + _textToEmoji[":high_heel:"] = "👠"; + _emojiToText["👠"] = ":high_heel:"; + _textToEmoji[":sandal:"] = "👡"; + _emojiToText["👡"] = ":sandal:"; + _textToEmoji[":womans_sandal:"] = "👡"; + _emojiToText["👡"] = ":womans_sandal:"; + _textToEmoji[":boot:"] = "👢"; + _emojiToText["👢"] = ":boot:"; + _textToEmoji[":womans_boot:"] = "👢"; + _emojiToText["👢"] = ":womans_boot:"; + _textToEmoji[":mans_shoe:"] = "👞"; + _emojiToText["👞"] = ":mans_shoe:"; + _textToEmoji[":athletic_shoe:"] = "👟"; + _emojiToText["👟"] = ":athletic_shoe:"; + _textToEmoji[":running_shoe:"] = "👟"; + _emojiToText["👟"] = ":running_shoe:"; + _textToEmoji[":hiking_boot:"] = "🥾"; + _emojiToText["🥾"] = ":hiking_boot:"; + _textToEmoji[":socks:"] = "🧦"; + _emojiToText["🧦"] = ":socks:"; + _textToEmoji[":gloves:"] = "🧤"; + _emojiToText["🧤"] = ":gloves:"; + _textToEmoji[":scarf:"] = "🧣"; + _emojiToText["🧣"] = ":scarf:"; + _textToEmoji[":tophat:"] = "🎩"; + _emojiToText["🎩"] = ":tophat:"; + _textToEmoji[":top_hat:"] = "🎩"; + _emojiToText["🎩"] = ":top_hat:"; + _textToEmoji[":billed_cap:"] = "🧢"; + _emojiToText["🧢"] = ":billed_cap:"; + _textToEmoji[":womans_hat:"] = "👒"; + _emojiToText["👒"] = ":womans_hat:"; + _textToEmoji[":mortar_board:"] = "🎓"; + _emojiToText["🎓"] = ":mortar_board:"; + _textToEmoji[":helmet_with_cross:"] = "⛑️"; + _emojiToText["⛑️"] = ":helmet_with_cross:"; + _textToEmoji[":helmet_with_white_cross:"] = "⛑️"; + _emojiToText["⛑️"] = ":helmet_with_white_cross:"; + _textToEmoji[":military_helmet:"] = "🪖"; + _emojiToText["🪖"] = ":military_helmet:"; + _textToEmoji[":crown:"] = "👑"; + _emojiToText["👑"] = ":crown:"; + _textToEmoji[":ring:"] = "💍"; + _emojiToText["💍"] = ":ring:"; + _textToEmoji[":pouch:"] = "👝"; + _emojiToText["👝"] = ":pouch:"; + _textToEmoji[":clutch_bag:"] = "👝"; + _emojiToText["👝"] = ":clutch_bag:"; + _textToEmoji[":purse:"] = "👛"; + _emojiToText["👛"] = ":purse:"; + _textToEmoji[":handbag:"] = "👜"; + _emojiToText["👜"] = ":handbag:"; + _textToEmoji[":briefcase:"] = "💼"; + _emojiToText["💼"] = ":briefcase:"; + _textToEmoji[":school_satchel:"] = "🎒"; + _emojiToText["🎒"] = ":school_satchel:"; + _textToEmoji[":backpack:"] = "🎒"; + _emojiToText["🎒"] = ":backpack:"; + _textToEmoji[":luggage:"] = "🧳"; + _emojiToText["🧳"] = ":luggage:"; + _textToEmoji[":eyeglasses:"] = "👓"; + _emojiToText["👓"] = ":eyeglasses:"; + _textToEmoji[":glasses:"] = "👓"; + _emojiToText["👓"] = ":glasses:"; + _textToEmoji[":dark_sunglasses:"] = "🕶️"; + _emojiToText["🕶️"] = ":dark_sunglasses:"; + _textToEmoji[":goggles:"] = "🥽"; + _emojiToText["🥽"] = ":goggles:"; + _textToEmoji[":closed_umbrella:"] = "🌂"; + _emojiToText["🌂"] = ":closed_umbrella:"; + _textToEmoji[":pink_heart:"] = "🩷"; + _emojiToText["🩷"] = ":pink_heart:"; + _textToEmoji[":heart:"] = "❤️"; + _emojiToText["❤️"] = ":heart:"; + _textToEmoji[":red_heart:"] = "❤️"; + _emojiToText["❤️"] = ":red_heart:"; + _textToEmoji[":orange_heart:"] = "🧡"; + _emojiToText["🧡"] = ":orange_heart:"; + _textToEmoji[":yellow_heart:"] = "💛"; + _emojiToText["💛"] = ":yellow_heart:"; + _textToEmoji[":green_heart:"] = "💚"; + _emojiToText["💚"] = ":green_heart:"; + _textToEmoji[":light_blue_heart:"] = "🩵"; + _emojiToText["🩵"] = ":light_blue_heart:"; + _textToEmoji[":blue_heart:"] = "💙"; + _emojiToText["💙"] = ":blue_heart:"; + _textToEmoji[":purple_heart:"] = "💜"; + _emojiToText["💜"] = ":purple_heart:"; + _textToEmoji[":black_heart:"] = "🖤"; + _emojiToText["🖤"] = ":black_heart:"; + _textToEmoji[":grey_heart:"] = "🩶"; + _emojiToText["🩶"] = ":grey_heart:"; + _textToEmoji[":white_heart:"] = "🤍"; + _emojiToText["🤍"] = ":white_heart:"; + _textToEmoji[":brown_heart:"] = "🤎"; + _emojiToText["🤎"] = ":brown_heart:"; + _textToEmoji[":broken_heart:"] = "💔"; + _emojiToText["💔"] = ":broken_heart:"; + _textToEmoji[":heart_exclamation:"] = "❣️"; + _emojiToText["❣️"] = ":heart_exclamation:"; + _textToEmoji[":heavy_heart_exclamation_mark_ornament:"] = "❣️"; + _emojiToText["❣️"] = ":heavy_heart_exclamation_mark_ornament:"; + _textToEmoji[":two_hearts:"] = "💕"; + _emojiToText["💕"] = ":two_hearts:"; + _textToEmoji[":revolving_hearts:"] = "💞"; + _emojiToText["💞"] = ":revolving_hearts:"; + _textToEmoji[":heartbeat:"] = "💓"; + _emojiToText["💓"] = ":heartbeat:"; + _textToEmoji[":beating_heart:"] = "💓"; + _emojiToText["💓"] = ":beating_heart:"; + _textToEmoji[":heartpulse:"] = "💗"; + _emojiToText["💗"] = ":heartpulse:"; + _textToEmoji[":growing_heart:"] = "💗"; + _emojiToText["💗"] = ":growing_heart:"; + _textToEmoji[":sparkling_heart:"] = "💖"; + _emojiToText["💖"] = ":sparkling_heart:"; + _textToEmoji[":cupid:"] = "💘"; + _emojiToText["💘"] = ":cupid:"; + _textToEmoji[":gift_heart:"] = "💝"; + _emojiToText["💝"] = ":gift_heart:"; + _textToEmoji[":mending_heart:"] = "❤️‍🩹"; + _emojiToText["❤️‍🩹"] = ":mending_heart:"; + _textToEmoji[":heart_on_fire:"] = "❤️‍🔥"; + _emojiToText["❤️‍🔥"] = ":heart_on_fire:"; + _textToEmoji[":heart_decoration:"] = "💟"; + _emojiToText["💟"] = ":heart_decoration:"; + _textToEmoji[":peace:"] = "☮️"; + _emojiToText["☮️"] = ":peace:"; + _textToEmoji[":peace_symbol:"] = "☮️"; + _emojiToText["☮️"] = ":peace_symbol:"; + _textToEmoji[":cross:"] = "✝️"; + _emojiToText["✝️"] = ":cross:"; + _textToEmoji[":latin_cross:"] = "✝️"; + _emojiToText["✝️"] = ":latin_cross:"; + _textToEmoji[":star_and_crescent:"] = "☪️"; + _emojiToText["☪️"] = ":star_and_crescent:"; + _textToEmoji[":om_symbol:"] = "🕉️"; + _emojiToText["🕉️"] = ":om_symbol:"; + _textToEmoji[":wheel_of_dharma:"] = "☸️"; + _emojiToText["☸️"] = ":wheel_of_dharma:"; + _textToEmoji[":khanda:"] = "🪯"; + _emojiToText["🪯"] = ":khanda:"; + _textToEmoji[":star_of_david:"] = "✡️"; + _emojiToText["✡️"] = ":star_of_david:"; + _textToEmoji[":six_pointed_star:"] = "🔯"; + _emojiToText["🔯"] = ":six_pointed_star:"; + _textToEmoji[":menorah:"] = "🕎"; + _emojiToText["🕎"] = ":menorah:"; + _textToEmoji[":yin_yang:"] = "☯️"; + _emojiToText["☯️"] = ":yin_yang:"; + _textToEmoji[":orthodox_cross:"] = "☦️"; + _emojiToText["☦️"] = ":orthodox_cross:"; + _textToEmoji[":place_of_worship:"] = "🛐"; + _emojiToText["🛐"] = ":place_of_worship:"; + _textToEmoji[":worship_symbol:"] = "🛐"; + _emojiToText["🛐"] = ":worship_symbol:"; + _textToEmoji[":ophiuchus:"] = "⛎"; + _emojiToText["⛎"] = ":ophiuchus:"; + _textToEmoji[":aries:"] = "♈"; + _emojiToText["♈"] = ":aries:"; + _textToEmoji[":taurus:"] = "♉"; + _emojiToText["♉"] = ":taurus:"; + _textToEmoji[":gemini:"] = "♊"; + _emojiToText["♊"] = ":gemini:"; + _textToEmoji[":cancer:"] = "♋"; + _emojiToText["♋"] = ":cancer:"; + _textToEmoji[":leo:"] = "♌"; + _emojiToText["♌"] = ":leo:"; + _textToEmoji[":virgo:"] = "♍"; + _emojiToText["♍"] = ":virgo:"; + _textToEmoji[":libra:"] = "♎"; + _emojiToText["♎"] = ":libra:"; + _textToEmoji[":scorpius:"] = "♏"; + _emojiToText["♏"] = ":scorpius:"; + _textToEmoji[":scorpio:"] = "♏"; + _emojiToText["♏"] = ":scorpio:"; + _textToEmoji[":sagittarius:"] = "♐"; + _emojiToText["♐"] = ":sagittarius:"; + _textToEmoji[":capricorn:"] = "♑"; + _emojiToText["♑"] = ":capricorn:"; + _textToEmoji[":aquarius:"] = "♒"; + _emojiToText["♒"] = ":aquarius:"; + _textToEmoji[":pisces:"] = "♓"; + _emojiToText["♓"] = ":pisces:"; + _textToEmoji[":id:"] = "🆔"; + _emojiToText["🆔"] = ":id:"; + _textToEmoji[":atom:"] = "⚛️"; + _emojiToText["⚛️"] = ":atom:"; + _textToEmoji[":atom_symbol:"] = "⚛️"; + _emojiToText["⚛️"] = ":atom_symbol:"; + _textToEmoji[":accept:"] = "🉑"; + _emojiToText["🉑"] = ":accept:"; + _textToEmoji[":radioactive:"] = "☢️"; + _emojiToText["☢️"] = ":radioactive:"; + _textToEmoji[":radioactive_sign:"] = "☢️"; + _emojiToText["☢️"] = ":radioactive_sign:"; + _textToEmoji[":biohazard:"] = "☣️"; + _emojiToText["☣️"] = ":biohazard:"; + _textToEmoji[":biohazard_sign:"] = "☣️"; + _emojiToText["☣️"] = ":biohazard_sign:"; + _textToEmoji[":mobile_phone_off:"] = "📴"; + _emojiToText["📴"] = ":mobile_phone_off:"; + _textToEmoji[":vibration_mode:"] = "📳"; + _emojiToText["📳"] = ":vibration_mode:"; + _textToEmoji[":u6709:"] = "🈶"; + _emojiToText["🈶"] = ":u6709:"; + _textToEmoji[":u7121:"] = "🈚"; + _emojiToText["🈚"] = ":u7121:"; + _textToEmoji[":u7533:"] = "🈸"; + _emojiToText["🈸"] = ":u7533:"; + _textToEmoji[":u55b6:"] = "🈺"; + _emojiToText["🈺"] = ":u55b6:"; + _textToEmoji[":u6708:"] = "🈷️"; + _emojiToText["🈷️"] = ":u6708:"; + _textToEmoji[":eight_pointed_black_star:"] = "✴️"; + _emojiToText["✴️"] = ":eight_pointed_black_star:"; + _textToEmoji[":vs:"] = "🆚"; + _emojiToText["🆚"] = ":vs:"; + _textToEmoji[":white_flower:"] = "💮"; + _emojiToText["💮"] = ":white_flower:"; + _textToEmoji[":ideograph_advantage:"] = "🉐"; + _emojiToText["🉐"] = ":ideograph_advantage:"; + _textToEmoji[":secret:"] = "㊙️"; + _emojiToText["㊙️"] = ":secret:"; + _textToEmoji[":congratulations:"] = "㊗️"; + _emojiToText["㊗️"] = ":congratulations:"; + _textToEmoji[":u5408:"] = "🈴"; + _emojiToText["🈴"] = ":u5408:"; + _textToEmoji[":u6e80:"] = "🈵"; + _emojiToText["🈵"] = ":u6e80:"; + _textToEmoji[":u5272:"] = "🈹"; + _emojiToText["🈹"] = ":u5272:"; + _textToEmoji[":u7981:"] = "🈲"; + _emojiToText["🈲"] = ":u7981:"; + _textToEmoji[":a:"] = "🅰️"; + _emojiToText["🅰️"] = ":a:"; + _textToEmoji[":b:"] = "🅱️"; + _emojiToText["🅱️"] = ":b:"; + _textToEmoji[":ab:"] = "🆎"; + _emojiToText["🆎"] = ":ab:"; + _textToEmoji[":cl:"] = "🆑"; + _emojiToText["🆑"] = ":cl:"; + _textToEmoji[":o2:"] = "🅾️"; + _emojiToText["🅾️"] = ":o2:"; + _textToEmoji[":sos:"] = "🆘"; + _emojiToText["🆘"] = ":sos:"; + _textToEmoji[":x:"] = "❌"; + _emojiToText["❌"] = ":x:"; + _textToEmoji[":cross_mark:"] = "❌"; + _emojiToText["❌"] = ":cross_mark:"; + _textToEmoji[":o:"] = "⭕"; + _emojiToText["⭕"] = ":o:"; + _textToEmoji[":octagonal_sign:"] = "🛑"; + _emojiToText["🛑"] = ":octagonal_sign:"; + _textToEmoji[":stop_sign:"] = "🛑"; + _emojiToText["🛑"] = ":stop_sign:"; + _textToEmoji[":no_entry:"] = "⛔"; + _emojiToText["⛔"] = ":no_entry:"; + _textToEmoji[":name_badge:"] = "📛"; + _emojiToText["📛"] = ":name_badge:"; + _textToEmoji[":no_entry_sign:"] = "🚫"; + _emojiToText["🚫"] = ":no_entry_sign:"; + _textToEmoji[":prohibited:"] = "🚫"; + _emojiToText["🚫"] = ":prohibited:"; + _textToEmoji[":anger:"] = "💢"; + _emojiToText["💢"] = ":anger:"; + _textToEmoji[":hotsprings:"] = "♨️"; + _emojiToText["♨️"] = ":hotsprings:"; + _textToEmoji[":hot_springs:"] = "♨️"; + _emojiToText["♨️"] = ":hot_springs:"; + _textToEmoji[":no_pedestrians:"] = "🚷"; + _emojiToText["🚷"] = ":no_pedestrians:"; + _textToEmoji[":do_not_litter:"] = "🚯"; + _emojiToText["🚯"] = ":do_not_litter:"; + _textToEmoji[":no_littering:"] = "🚯"; + _emojiToText["🚯"] = ":no_littering:"; + _textToEmoji[":no_bicycles:"] = "🚳"; + _emojiToText["🚳"] = ":no_bicycles:"; + _textToEmoji[":non_potable_water:"] = "🚱"; + _emojiToText["🚱"] = ":non_potable_water:"; + _textToEmoji[":underage:"] = "🔞"; + _emojiToText["🔞"] = ":underage:"; + _textToEmoji[":no_mobile_phones:"] = "📵"; + _emojiToText["📵"] = ":no_mobile_phones:"; + _textToEmoji[":no_smoking:"] = "🚭"; + _emojiToText["🚭"] = ":no_smoking:"; + _textToEmoji[":exclamation:"] = "❗"; + _emojiToText["❗"] = ":exclamation:"; + _textToEmoji[":grey_exclamation:"] = "❕"; + _emojiToText["❕"] = ":grey_exclamation:"; + _textToEmoji[":question:"] = "❓"; + _emojiToText["❓"] = ":question:"; + _textToEmoji[":question_mark:"] = "❓"; + _emojiToText["❓"] = ":question_mark:"; + _textToEmoji[":grey_question:"] = "❔"; + _emojiToText["❔"] = ":grey_question:"; + _textToEmoji[":bangbang:"] = "‼️"; + _emojiToText["‼️"] = ":bangbang:"; + _textToEmoji[":interrobang:"] = "⁉️"; + _emojiToText["⁉️"] = ":interrobang:"; + _textToEmoji[":low_brightness:"] = "🔅"; + _emojiToText["🔅"] = ":low_brightness:"; + _textToEmoji[":high_brightness:"] = "🔆"; + _emojiToText["🔆"] = ":high_brightness:"; + _textToEmoji[":part_alternation_mark:"] = "〽️"; + _emojiToText["〽️"] = ":part_alternation_mark:"; + _textToEmoji[":warning:"] = "⚠️"; + _emojiToText["⚠️"] = ":warning:"; + _textToEmoji[":children_crossing:"] = "🚸"; + _emojiToText["🚸"] = ":children_crossing:"; + _textToEmoji[":trident:"] = "🔱"; + _emojiToText["🔱"] = ":trident:"; + _textToEmoji[":fleur_de_lis:"] = "⚜️"; + _emojiToText["⚜️"] = ":fleur_de_lis:"; + _textToEmoji[":beginner:"] = "🔰"; + _emojiToText["🔰"] = ":beginner:"; + _textToEmoji[":recycle:"] = "♻️"; + _emojiToText["♻️"] = ":recycle:"; + _textToEmoji[":white_check_mark:"] = "✅"; + _emojiToText["✅"] = ":white_check_mark:"; + _textToEmoji[":u6307:"] = "🈯"; + _emojiToText["🈯"] = ":u6307:"; + _textToEmoji[":chart:"] = "💹"; + _emojiToText["💹"] = ":chart:"; + _textToEmoji[":sparkle:"] = "❇️"; + _emojiToText["❇️"] = ":sparkle:"; + _textToEmoji[":eight_spoked_asterisk:"] = "✳️"; + _emojiToText["✳️"] = ":eight_spoked_asterisk:"; + _textToEmoji[":negative_squared_cross_mark:"] = "❎"; + _emojiToText["❎"] = ":negative_squared_cross_mark:"; + _textToEmoji[":globe_with_meridians:"] = "🌐"; + _emojiToText["🌐"] = ":globe_with_meridians:"; + _textToEmoji[":diamond_shape_with_a_dot_inside:"] = "💠"; + _emojiToText["💠"] = ":diamond_shape_with_a_dot_inside:"; + _textToEmoji[":m:"] = "Ⓜ️"; + _emojiToText["Ⓜ️"] = ":m:"; + _textToEmoji[":circled_m:"] = "Ⓜ️"; + _emojiToText["Ⓜ️"] = ":circled_m:"; + _textToEmoji[":cyclone:"] = "🌀"; + _emojiToText["🌀"] = ":cyclone:"; + _textToEmoji[":zzz:"] = "💤"; + _emojiToText["💤"] = ":zzz:"; + _textToEmoji[":atm:"] = "🏧"; + _emojiToText["🏧"] = ":atm:"; + _textToEmoji[":wc:"] = "🚾"; + _emojiToText["🚾"] = ":wc:"; + _textToEmoji[":water_closet:"] = "🚾"; + _emojiToText["🚾"] = ":water_closet:"; + _textToEmoji[":wheelchair:"] = "♿"; + _emojiToText["♿"] = ":wheelchair:"; + _textToEmoji[":parking:"] = "🅿️"; + _emojiToText["🅿️"] = ":parking:"; + _textToEmoji[":elevator:"] = "🛗"; + _emojiToText["🛗"] = ":elevator:"; + _textToEmoji[":u7a7a:"] = "🈳"; + _emojiToText["🈳"] = ":u7a7a:"; + _textToEmoji[":sa:"] = "🈂️"; + _emojiToText["🈂️"] = ":sa:"; + _textToEmoji[":passport_control:"] = "🛂"; + _emojiToText["🛂"] = ":passport_control:"; + _textToEmoji[":customs:"] = "🛃"; + _emojiToText["🛃"] = ":customs:"; + _textToEmoji[":baggage_claim:"] = "🛄"; + _emojiToText["🛄"] = ":baggage_claim:"; + _textToEmoji[":left_luggage:"] = "🛅"; + _emojiToText["🛅"] = ":left_luggage:"; + _textToEmoji[":wireless:"] = "🛜"; + _emojiToText["🛜"] = ":wireless:"; + _textToEmoji[":mens:"] = "🚹"; + _emojiToText["🚹"] = ":mens:"; + _textToEmoji[":mens_room:"] = "🚹"; + _emojiToText["🚹"] = ":mens_room:"; + _textToEmoji[":womens:"] = "🚺"; + _emojiToText["🚺"] = ":womens:"; + _textToEmoji[":womens_room:"] = "🚺"; + _emojiToText["🚺"] = ":womens_room:"; + _textToEmoji[":baby_symbol:"] = "🚼"; + _emojiToText["🚼"] = ":baby_symbol:"; + _textToEmoji[":restroom:"] = "🚻"; + _emojiToText["🚻"] = ":restroom:"; + _textToEmoji[":put_litter_in_its_place:"] = "🚮"; + _emojiToText["🚮"] = ":put_litter_in_its_place:"; + _textToEmoji[":cinema:"] = "🎦"; + _emojiToText["🎦"] = ":cinema:"; + _textToEmoji[":signal_strength:"] = "📶"; + _emojiToText["📶"] = ":signal_strength:"; + _textToEmoji[":antenna_bars:"] = "📶"; + _emojiToText["📶"] = ":antenna_bars:"; + _textToEmoji[":koko:"] = "🈁"; + _emojiToText["🈁"] = ":koko:"; + _textToEmoji[":symbols:"] = "🔣"; + _emojiToText["🔣"] = ":symbols:"; + _textToEmoji[":input_symbols:"] = "🔣"; + _emojiToText["🔣"] = ":input_symbols:"; + _textToEmoji[":information_source:"] = "ℹ️"; + _emojiToText["ℹ️"] = ":information_source:"; + _textToEmoji[":information:"] = "ℹ️"; + _emojiToText["ℹ️"] = ":information:"; + _textToEmoji[":abc:"] = "🔤"; + _emojiToText["🔤"] = ":abc:"; + _textToEmoji[":abcd:"] = "🔡"; + _emojiToText["🔡"] = ":abcd:"; + _textToEmoji[":capital_abcd:"] = "🔠"; + _emojiToText["🔠"] = ":capital_abcd:"; + _textToEmoji[":ng:"] = "🆖"; + _emojiToText["🆖"] = ":ng:"; + _textToEmoji[":ok:"] = "🆗"; + _emojiToText["🆗"] = ":ok:"; + _textToEmoji[":up:"] = "🆙"; + _emojiToText["🆙"] = ":up:"; + _textToEmoji[":cool:"] = "🆒"; + _emojiToText["🆒"] = ":cool:"; + _textToEmoji[":new:"] = "🆕"; + _emojiToText["🆕"] = ":new:"; + _textToEmoji[":free:"] = "🆓"; + _emojiToText["🆓"] = ":free:"; + _textToEmoji[":zero:"] = "0️⃣"; + _emojiToText["0️⃣"] = ":zero:"; + _textToEmoji[":one:"] = "1️⃣"; + _emojiToText["1️⃣"] = ":one:"; + _textToEmoji[":two:"] = "2️⃣"; + _emojiToText["2️⃣"] = ":two:"; + _textToEmoji[":three:"] = "3️⃣"; + _emojiToText["3️⃣"] = ":three:"; + _textToEmoji[":four:"] = "4️⃣"; + _emojiToText["4️⃣"] = ":four:"; + _textToEmoji[":five:"] = "5️⃣"; + _emojiToText["5️⃣"] = ":five:"; + _textToEmoji[":six:"] = "6️⃣"; + _emojiToText["6️⃣"] = ":six:"; + _textToEmoji[":seven:"] = "7️⃣"; + _emojiToText["7️⃣"] = ":seven:"; + _textToEmoji[":eight:"] = "8️⃣"; + _emojiToText["8️⃣"] = ":eight:"; + _textToEmoji[":nine:"] = "9️⃣"; + _emojiToText["9️⃣"] = ":nine:"; + _textToEmoji[":keycap_ten:"] = "🔟"; + _emojiToText["🔟"] = ":keycap_ten:"; + _textToEmoji[":input_numbers:"] = "🔢"; + _emojiToText["🔢"] = ":input_numbers:"; + _textToEmoji[":hash:"] = "#️⃣"; + _emojiToText["#️⃣"] = ":hash:"; + _textToEmoji[":asterisk:"] = "*️⃣"; + _emojiToText["*️⃣"] = ":asterisk:"; + _textToEmoji[":keycap_asterisk:"] = "*️⃣"; + _emojiToText["*️⃣"] = ":keycap_asterisk:"; + _textToEmoji[":eject:"] = "⏏️"; + _emojiToText["⏏️"] = ":eject:"; + _textToEmoji[":eject_symbol:"] = "⏏️"; + _emojiToText["⏏️"] = ":eject_symbol:"; + _textToEmoji[":arrow_forward:"] = "▶️"; + _emojiToText["▶️"] = ":arrow_forward:"; + _textToEmoji[":pause_button:"] = "⏸️"; + _emojiToText["⏸️"] = ":pause_button:"; + _textToEmoji[":double_vertical_bar:"] = "⏸️"; + _emojiToText["⏸️"] = ":double_vertical_bar:"; + _textToEmoji[":play_pause:"] = "⏯️"; + _emojiToText["⏯️"] = ":play_pause:"; + _textToEmoji[":stop_button:"] = "⏹️"; + _emojiToText["⏹️"] = ":stop_button:"; + _textToEmoji[":record_button:"] = "⏺️"; + _emojiToText["⏺️"] = ":record_button:"; + _textToEmoji[":track_next:"] = "⏭️"; + _emojiToText["⏭️"] = ":track_next:"; + _textToEmoji[":next_track:"] = "⏭️"; + _emojiToText["⏭️"] = ":next_track:"; + _textToEmoji[":track_previous:"] = "⏮️"; + _emojiToText["⏮️"] = ":track_previous:"; + _textToEmoji[":previous_track:"] = "⏮️"; + _emojiToText["⏮️"] = ":previous_track:"; + _textToEmoji[":fast_forward:"] = "⏩"; + _emojiToText["⏩"] = ":fast_forward:"; + _textToEmoji[":rewind:"] = "⏪"; + _emojiToText["⏪"] = ":rewind:"; + _textToEmoji[":arrow_double_up:"] = "⏫"; + _emojiToText["⏫"] = ":arrow_double_up:"; + _textToEmoji[":arrow_double_down:"] = "⏬"; + _emojiToText["⏬"] = ":arrow_double_down:"; + _textToEmoji[":arrow_backward:"] = "◀️"; + _emojiToText["◀️"] = ":arrow_backward:"; + _textToEmoji[":arrow_up_small:"] = "🔼"; + _emojiToText["🔼"] = ":arrow_up_small:"; + _textToEmoji[":arrow_down_small:"] = "🔽"; + _emojiToText["🔽"] = ":arrow_down_small:"; + _textToEmoji[":arrow_right:"] = "➡️"; + _emojiToText["➡️"] = ":arrow_right:"; + _textToEmoji[":right_arrow:"] = "➡️"; + _emojiToText["➡️"] = ":right_arrow:"; + _textToEmoji[":arrow_left:"] = "⬅️"; + _emojiToText["⬅️"] = ":arrow_left:"; + _textToEmoji[":left_arrow:"] = "⬅️"; + _emojiToText["⬅️"] = ":left_arrow:"; + _textToEmoji[":arrow_up:"] = "⬆️"; + _emojiToText["⬆️"] = ":arrow_up:"; + _textToEmoji[":up_arrow:"] = "⬆️"; + _emojiToText["⬆️"] = ":up_arrow:"; + _textToEmoji[":arrow_down:"] = "⬇️"; + _emojiToText["⬇️"] = ":arrow_down:"; + _textToEmoji[":down_arrow:"] = "⬇️"; + _emojiToText["⬇️"] = ":down_arrow:"; + _textToEmoji[":arrow_upper_right:"] = "↗️"; + _emojiToText["↗️"] = ":arrow_upper_right:"; + _textToEmoji[":arrow_lower_right:"] = "↘️"; + _emojiToText["↘️"] = ":arrow_lower_right:"; + _textToEmoji[":arrow_lower_left:"] = "↙️"; + _emojiToText["↙️"] = ":arrow_lower_left:"; + _textToEmoji[":arrow_upper_left:"] = "↖️"; + _emojiToText["↖️"] = ":arrow_upper_left:"; + _textToEmoji[":up_left_arrow:"] = "↖️"; + _emojiToText["↖️"] = ":up_left_arrow:"; + _textToEmoji[":arrow_up_down:"] = "↕️"; + _emojiToText["↕️"] = ":arrow_up_down:"; + _textToEmoji[":up_down_arrow:"] = "↕️"; + _emojiToText["↕️"] = ":up_down_arrow:"; + _textToEmoji[":left_right_arrow:"] = "↔️"; + _emojiToText["↔️"] = ":left_right_arrow:"; + _textToEmoji[":arrow_right_hook:"] = "↪️"; + _emojiToText["↪️"] = ":arrow_right_hook:"; + _textToEmoji[":leftwards_arrow_with_hook:"] = "↩️"; + _emojiToText["↩️"] = ":leftwards_arrow_with_hook:"; + _textToEmoji[":arrow_heading_up:"] = "⤴️"; + _emojiToText["⤴️"] = ":arrow_heading_up:"; + _textToEmoji[":arrow_heading_down:"] = "⤵️"; + _emojiToText["⤵️"] = ":arrow_heading_down:"; + _textToEmoji[":twisted_rightwards_arrows:"] = "🔀"; + _emojiToText["🔀"] = ":twisted_rightwards_arrows:"; + _textToEmoji[":repeat:"] = "🔁"; + _emojiToText["🔁"] = ":repeat:"; + _textToEmoji[":repeat_one:"] = "🔂"; + _emojiToText["🔂"] = ":repeat_one:"; + _textToEmoji[":arrows_counterclockwise:"] = "🔄"; + _emojiToText["🔄"] = ":arrows_counterclockwise:"; + _textToEmoji[":arrows_clockwise:"] = "🔃"; + _emojiToText["🔃"] = ":arrows_clockwise:"; + _textToEmoji[":musical_note:"] = "🎵"; + _emojiToText["🎵"] = ":musical_note:"; + _textToEmoji[":notes:"] = "🎶"; + _emojiToText["🎶"] = ":notes:"; + _textToEmoji[":musical_notes:"] = "🎶"; + _emojiToText["🎶"] = ":musical_notes:"; + _textToEmoji[":heavy_plus_sign:"] = "➕"; + _emojiToText["➕"] = ":heavy_plus_sign:"; + _textToEmoji[":heavy_minus_sign:"] = "➖"; + _emojiToText["➖"] = ":heavy_minus_sign:"; + _textToEmoji[":heavy_division_sign:"] = "➗"; + _emojiToText["➗"] = ":heavy_division_sign:"; + _textToEmoji[":heavy_multiplication_x:"] = "✖️"; + _emojiToText["✖️"] = ":heavy_multiplication_x:"; + _textToEmoji[":heavy_equals_sign:"] = "🟰"; + _emojiToText["🟰"] = ":heavy_equals_sign:"; + _textToEmoji[":infinity:"] = "♾️"; + _emojiToText["♾️"] = ":infinity:"; + _textToEmoji[":heavy_dollar_sign:"] = "💲"; + _emojiToText["💲"] = ":heavy_dollar_sign:"; + _textToEmoji[":currency_exchange:"] = "💱"; + _emojiToText["💱"] = ":currency_exchange:"; + _textToEmoji[":tm:"] = "™️"; + _emojiToText["™️"] = ":tm:"; + _textToEmoji[":trade_mark:"] = "™️"; + _emojiToText["™️"] = ":trade_mark:"; + _textToEmoji[":copyright:"] = "©️"; + _emojiToText["©️"] = ":copyright:"; + _textToEmoji[":registered:"] = "®️"; + _emojiToText["®️"] = ":registered:"; + _textToEmoji[":wavy_dash:"] = "〰️"; + _emojiToText["〰️"] = ":wavy_dash:"; + _textToEmoji[":curly_loop:"] = "➰"; + _emojiToText["➰"] = ":curly_loop:"; + _textToEmoji[":loop:"] = "➿"; + _emojiToText["➿"] = ":loop:"; + _textToEmoji[":end:"] = "🔚"; + _emojiToText["🔚"] = ":end:"; + _textToEmoji[":end_arrow:"] = "🔚"; + _emojiToText["🔚"] = ":end_arrow:"; + _textToEmoji[":back:"] = "🔙"; + _emojiToText["🔙"] = ":back:"; + _textToEmoji[":back_arrow:"] = "🔙"; + _emojiToText["🔙"] = ":back_arrow:"; + _textToEmoji[":on:"] = "🔛"; + _emojiToText["🔛"] = ":on:"; + _textToEmoji[":on_arrow:"] = "🔛"; + _emojiToText["🔛"] = ":on_arrow:"; + _textToEmoji[":top:"] = "🔝"; + _emojiToText["🔝"] = ":top:"; + _textToEmoji[":top_arrow:"] = "🔝"; + _emojiToText["🔝"] = ":top_arrow:"; + _textToEmoji[":soon:"] = "🔜"; + _emojiToText["🔜"] = ":soon:"; + _textToEmoji[":soon_arrow:"] = "🔜"; + _emojiToText["🔜"] = ":soon_arrow:"; + _textToEmoji[":heavy_check_mark:"] = "✔️"; + _emojiToText["✔️"] = ":heavy_check_mark:"; + _textToEmoji[":check_mark:"] = "✔️"; + _emojiToText["✔️"] = ":check_mark:"; + _textToEmoji[":ballot_box_with_check:"] = "☑️"; + _emojiToText["☑️"] = ":ballot_box_with_check:"; + _textToEmoji[":radio_button:"] = "🔘"; + _emojiToText["🔘"] = ":radio_button:"; + _textToEmoji[":white_circle:"] = "⚪"; + _emojiToText["⚪"] = ":white_circle:"; + _textToEmoji[":black_circle:"] = "⚫"; + _emojiToText["⚫"] = ":black_circle:"; + _textToEmoji[":red_circle:"] = "🔴"; + _emojiToText["🔴"] = ":red_circle:"; + _textToEmoji[":blue_circle:"] = "🔵"; + _emojiToText["🔵"] = ":blue_circle:"; + _textToEmoji[":brown_circle:"] = "🟤"; + _emojiToText["🟤"] = ":brown_circle:"; + _textToEmoji[":purple_circle:"] = "🟣"; + _emojiToText["🟣"] = ":purple_circle:"; + _textToEmoji[":green_circle:"] = "🟢"; + _emojiToText["🟢"] = ":green_circle:"; + _textToEmoji[":yellow_circle:"] = "🟡"; + _emojiToText["🟡"] = ":yellow_circle:"; + _textToEmoji[":orange_circle:"] = "🟠"; + _emojiToText["🟠"] = ":orange_circle:"; + _textToEmoji[":small_red_triangle:"] = "🔺"; + _emojiToText["🔺"] = ":small_red_triangle:"; + _textToEmoji[":small_red_triangle_down:"] = "🔻"; + _emojiToText["🔻"] = ":small_red_triangle_down:"; + _textToEmoji[":small_orange_diamond:"] = "🔸"; + _emojiToText["🔸"] = ":small_orange_diamond:"; + _textToEmoji[":small_blue_diamond:"] = "🔹"; + _emojiToText["🔹"] = ":small_blue_diamond:"; + _textToEmoji[":large_orange_diamond:"] = "🔶"; + _emojiToText["🔶"] = ":large_orange_diamond:"; + _textToEmoji[":large_blue_diamond:"] = "🔷"; + _emojiToText["🔷"] = ":large_blue_diamond:"; + _textToEmoji[":white_square_button:"] = "🔳"; + _emojiToText["🔳"] = ":white_square_button:"; + _textToEmoji[":black_square_button:"] = "🔲"; + _emojiToText["🔲"] = ":black_square_button:"; + _textToEmoji[":black_small_square:"] = "▪️"; + _emojiToText["▪️"] = ":black_small_square:"; + _textToEmoji[":white_small_square:"] = "▫️"; + _emojiToText["▫️"] = ":white_small_square:"; + _textToEmoji[":black_medium_small_square:"] = "◾"; + _emojiToText["◾"] = ":black_medium_small_square:"; + _textToEmoji[":white_medium_small_square:"] = "◽"; + _emojiToText["◽"] = ":white_medium_small_square:"; + _textToEmoji[":black_medium_square:"] = "◼️"; + _emojiToText["◼️"] = ":black_medium_square:"; + _textToEmoji[":white_medium_square:"] = "◻️"; + _emojiToText["◻️"] = ":white_medium_square:"; + _textToEmoji[":black_large_square:"] = "⬛"; + _emojiToText["⬛"] = ":black_large_square:"; + _textToEmoji[":white_large_square:"] = "⬜"; + _emojiToText["⬜"] = ":white_large_square:"; + _textToEmoji[":orange_square:"] = "🟧"; + _emojiToText["🟧"] = ":orange_square:"; + _textToEmoji[":blue_square:"] = "🟦"; + _emojiToText["🟦"] = ":blue_square:"; + _textToEmoji[":red_square:"] = "🟥"; + _emojiToText["🟥"] = ":red_square:"; + _textToEmoji[":brown_square:"] = "🟫"; + _emojiToText["🟫"] = ":brown_square:"; + _textToEmoji[":purple_square:"] = "🟪"; + _emojiToText["🟪"] = ":purple_square:"; + _textToEmoji[":green_square:"] = "🟩"; + _emojiToText["🟩"] = ":green_square:"; + _textToEmoji[":yellow_square:"] = "🟨"; + _emojiToText["🟨"] = ":yellow_square:"; + _textToEmoji[":speaker:"] = "🔈"; + _emojiToText["🔈"] = ":speaker:"; + _textToEmoji[":mute:"] = "🔇"; + _emojiToText["🔇"] = ":mute:"; + _textToEmoji[":muted_speaker:"] = "🔇"; + _emojiToText["🔇"] = ":muted_speaker:"; + _textToEmoji[":sound:"] = "🔉"; + _emojiToText["🔉"] = ":sound:"; + _textToEmoji[":loud_sound:"] = "🔊"; + _emojiToText["🔊"] = ":loud_sound:"; + _textToEmoji[":bell:"] = "🔔"; + _emojiToText["🔔"] = ":bell:"; + _textToEmoji[":no_bell:"] = "🔕"; + _emojiToText["🔕"] = ":no_bell:"; + _textToEmoji[":mega:"] = "📣"; + _emojiToText["📣"] = ":mega:"; + _textToEmoji[":megaphone:"] = "📣"; + _emojiToText["📣"] = ":megaphone:"; + _textToEmoji[":loudspeaker:"] = "📢"; + _emojiToText["📢"] = ":loudspeaker:"; + _textToEmoji[":speech_left:"] = "🗨️"; + _emojiToText["🗨️"] = ":speech_left:"; + _textToEmoji[":left_speech_bubble:"] = "🗨️"; + _emojiToText["🗨️"] = ":left_speech_bubble:"; + _textToEmoji[":eye_in_speech_bubble:"] = "👁‍🗨"; + _emojiToText["👁‍🗨"] = ":eye_in_speech_bubble:"; + _textToEmoji[":speech_balloon:"] = "💬"; + _emojiToText["💬"] = ":speech_balloon:"; + _textToEmoji[":thought_balloon:"] = "💭"; + _emojiToText["💭"] = ":thought_balloon:"; + _textToEmoji[":anger_right:"] = "🗯️"; + _emojiToText["🗯️"] = ":anger_right:"; + _textToEmoji[":right_anger_bubble:"] = "🗯️"; + _emojiToText["🗯️"] = ":right_anger_bubble:"; + _textToEmoji[":spades:"] = "♠️"; + _emojiToText["♠️"] = ":spades:"; + _textToEmoji[":spade_suit:"] = "♠️"; + _emojiToText["♠️"] = ":spade_suit:"; + _textToEmoji[":clubs:"] = "♣️"; + _emojiToText["♣️"] = ":clubs:"; + _textToEmoji[":club_suit:"] = "♣️"; + _emojiToText["♣️"] = ":club_suit:"; + _textToEmoji[":hearts:"] = "♥️"; + _emojiToText["♥️"] = ":hearts:"; + _textToEmoji[":heart_suit:"] = "♥️"; + _emojiToText["♥️"] = ":heart_suit:"; + _textToEmoji[":diamonds:"] = "♦️"; + _emojiToText["♦️"] = ":diamonds:"; + _textToEmoji[":diamond_suit:"] = "♦️"; + _emojiToText["♦️"] = ":diamond_suit:"; + _textToEmoji[":black_joker:"] = "🃏"; + _emojiToText["🃏"] = ":black_joker:"; + _textToEmoji[":joker:"] = "🃏"; + _emojiToText["🃏"] = ":joker:"; + _textToEmoji[":flower_playing_cards:"] = "🎴"; + _emojiToText["🎴"] = ":flower_playing_cards:"; + _textToEmoji[":mahjong:"] = "🀄"; + _emojiToText["🀄"] = ":mahjong:"; + _textToEmoji[":clock1:"] = "🕐"; + _emojiToText["🕐"] = ":clock1:"; + _textToEmoji[":one_oclock:"] = "🕐"; + _emojiToText["🕐"] = ":one_oclock:"; + _textToEmoji[":clock2:"] = "🕑"; + _emojiToText["🕑"] = ":clock2:"; + _textToEmoji[":two_oclock:"] = "🕑"; + _emojiToText["🕑"] = ":two_oclock:"; + _textToEmoji[":clock3:"] = "🕒"; + _emojiToText["🕒"] = ":clock3:"; + _textToEmoji[":three_oclock:"] = "🕒"; + _emojiToText["🕒"] = ":three_oclock:"; + _textToEmoji[":clock4:"] = "🕓"; + _emojiToText["🕓"] = ":clock4:"; + _textToEmoji[":four_oclock:"] = "🕓"; + _emojiToText["🕓"] = ":four_oclock:"; + _textToEmoji[":clock5:"] = "🕔"; + _emojiToText["🕔"] = ":clock5:"; + _textToEmoji[":five_oclock:"] = "🕔"; + _emojiToText["🕔"] = ":five_oclock:"; + _textToEmoji[":clock6:"] = "🕕"; + _emojiToText["🕕"] = ":clock6:"; + _textToEmoji[":six_oclock:"] = "🕕"; + _emojiToText["🕕"] = ":six_oclock:"; + _textToEmoji[":clock7:"] = "🕖"; + _emojiToText["🕖"] = ":clock7:"; + _textToEmoji[":seven_oclock:"] = "🕖"; + _emojiToText["🕖"] = ":seven_oclock:"; + _textToEmoji[":clock8:"] = "🕗"; + _emojiToText["🕗"] = ":clock8:"; + _textToEmoji[":eight_oclock:"] = "🕗"; + _emojiToText["🕗"] = ":eight_oclock:"; + _textToEmoji[":clock9:"] = "🕘"; + _emojiToText["🕘"] = ":clock9:"; + _textToEmoji[":nine_oclock:"] = "🕘"; + _emojiToText["🕘"] = ":nine_oclock:"; + _textToEmoji[":clock10:"] = "🕙"; + _emojiToText["🕙"] = ":clock10:"; + _textToEmoji[":ten_oclock:"] = "🕙"; + _emojiToText["🕙"] = ":ten_oclock:"; + _textToEmoji[":clock11:"] = "🕚"; + _emojiToText["🕚"] = ":clock11:"; + _textToEmoji[":eleven_oclock:"] = "🕚"; + _emojiToText["🕚"] = ":eleven_oclock:"; + _textToEmoji[":clock12:"] = "🕛"; + _emojiToText["🕛"] = ":clock12:"; + _textToEmoji[":twelve_oclock:"] = "🕛"; + _emojiToText["🕛"] = ":twelve_oclock:"; + _textToEmoji[":clock130:"] = "🕜"; + _emojiToText["🕜"] = ":clock130:"; + _textToEmoji[":one_thirty:"] = "🕜"; + _emojiToText["🕜"] = ":one_thirty:"; + _textToEmoji[":clock230:"] = "🕝"; + _emojiToText["🕝"] = ":clock230:"; + _textToEmoji[":two_thirty:"] = "🕝"; + _emojiToText["🕝"] = ":two_thirty:"; + _textToEmoji[":clock330:"] = "🕞"; + _emojiToText["🕞"] = ":clock330:"; + _textToEmoji[":three_thirty:"] = "🕞"; + _emojiToText["🕞"] = ":three_thirty:"; + _textToEmoji[":clock430:"] = "🕟"; + _emojiToText["🕟"] = ":clock430:"; + _textToEmoji[":four_thirty:"] = "🕟"; + _emojiToText["🕟"] = ":four_thirty:"; + _textToEmoji[":clock530:"] = "🕠"; + _emojiToText["🕠"] = ":clock530:"; + _textToEmoji[":five_thirty:"] = "🕠"; + _emojiToText["🕠"] = ":five_thirty:"; + _textToEmoji[":clock630:"] = "🕡"; + _emojiToText["🕡"] = ":clock630:"; + _textToEmoji[":six_thirty:"] = "🕡"; + _emojiToText["🕡"] = ":six_thirty:"; + _textToEmoji[":clock730:"] = "🕢"; + _emojiToText["🕢"] = ":clock730:"; + _textToEmoji[":seven_thirty:"] = "🕢"; + _emojiToText["🕢"] = ":seven_thirty:"; + _textToEmoji[":clock830:"] = "🕣"; + _emojiToText["🕣"] = ":clock830:"; + _textToEmoji[":eight_thirty:"] = "🕣"; + _emojiToText["🕣"] = ":eight_thirty:"; + _textToEmoji[":clock930:"] = "🕤"; + _emojiToText["🕤"] = ":clock930:"; + _textToEmoji[":nine_thirty:"] = "🕤"; + _emojiToText["🕤"] = ":nine_thirty:"; + _textToEmoji[":clock1030:"] = "🕥"; + _emojiToText["🕥"] = ":clock1030:"; + _textToEmoji[":ten_thirty:"] = "🕥"; + _emojiToText["🕥"] = ":ten_thirty:"; + _textToEmoji[":clock1130:"] = "🕦"; + _emojiToText["🕦"] = ":clock1130:"; + _textToEmoji[":eleven_thirty:"] = "🕦"; + _emojiToText["🕦"] = ":eleven_thirty:"; + _textToEmoji[":clock1230:"] = "🕧"; + _emojiToText["🕧"] = ":clock1230:"; + _textToEmoji[":twelve_thirty:"] = "🕧"; + _emojiToText["🕧"] = ":twelve_thirty:"; + _textToEmoji[":female_sign:"] = "♀️"; + _emojiToText["♀️"] = ":female_sign:"; + _textToEmoji[":male_sign:"] = "♂️"; + _emojiToText["♂️"] = ":male_sign:"; + _textToEmoji[":transgender_symbol:"] = "⚧"; + _emojiToText["⚧"] = ":transgender_symbol:"; + _textToEmoji[":medical_symbol:"] = "⚕️"; + _emojiToText["⚕️"] = ":medical_symbol:"; + _textToEmoji[":regional_indicator_z:"] = "🇿"; + _emojiToText["🇿"] = ":regional_indicator_z:"; + _textToEmoji[":regional_indicator_y:"] = "🇾"; + _emojiToText["🇾"] = ":regional_indicator_y:"; + _textToEmoji[":regional_indicator_x:"] = "🇽"; + _emojiToText["🇽"] = ":regional_indicator_x:"; + _textToEmoji[":regional_indicator_w:"] = "🇼"; + _emojiToText["🇼"] = ":regional_indicator_w:"; + _textToEmoji[":regional_indicator_v:"] = "🇻"; + _emojiToText["🇻"] = ":regional_indicator_v:"; + _textToEmoji[":regional_indicator_u:"] = "🇺"; + _emojiToText["🇺"] = ":regional_indicator_u:"; + _textToEmoji[":regional_indicator_t:"] = "🇹"; + _emojiToText["🇹"] = ":regional_indicator_t:"; + _textToEmoji[":regional_indicator_s:"] = "🇸"; + _emojiToText["🇸"] = ":regional_indicator_s:"; + _textToEmoji[":regional_indicator_r:"] = "🇷"; + _emojiToText["🇷"] = ":regional_indicator_r:"; + _textToEmoji[":regional_indicator_q:"] = "🇶"; + _emojiToText["🇶"] = ":regional_indicator_q:"; + _textToEmoji[":regional_indicator_p:"] = "🇵"; + _emojiToText["🇵"] = ":regional_indicator_p:"; + _textToEmoji[":regional_indicator_o:"] = "🇴"; + _emojiToText["🇴"] = ":regional_indicator_o:"; + _textToEmoji[":regional_indicator_n:"] = "🇳"; + _emojiToText["🇳"] = ":regional_indicator_n:"; + _textToEmoji[":regional_indicator_m:"] = "🇲"; + _emojiToText["🇲"] = ":regional_indicator_m:"; + _textToEmoji[":regional_indicator_l:"] = "🇱"; + _emojiToText["🇱"] = ":regional_indicator_l:"; + _textToEmoji[":regional_indicator_k:"] = "🇰"; + _emojiToText["🇰"] = ":regional_indicator_k:"; + _textToEmoji[":regional_indicator_j:"] = "🇯"; + _emojiToText["🇯"] = ":regional_indicator_j:"; + _textToEmoji[":regional_indicator_i:"] = "🇮"; + _emojiToText["🇮"] = ":regional_indicator_i:"; + _textToEmoji[":regional_indicator_h:"] = "🇭"; + _emojiToText["🇭"] = ":regional_indicator_h:"; + _textToEmoji[":regional_indicator_g:"] = "🇬"; + _emojiToText["🇬"] = ":regional_indicator_g:"; + _textToEmoji[":regional_indicator_f:"] = "🇫"; + _emojiToText["🇫"] = ":regional_indicator_f:"; + _textToEmoji[":regional_indicator_e:"] = "🇪"; + _emojiToText["🇪"] = ":regional_indicator_e:"; + _textToEmoji[":regional_indicator_d:"] = "🇩"; + _emojiToText["🇩"] = ":regional_indicator_d:"; + _textToEmoji[":regional_indicator_c:"] = "🇨"; + _emojiToText["🇨"] = ":regional_indicator_c:"; + _textToEmoji[":regional_indicator_b:"] = "🇧"; + _emojiToText["🇧"] = ":regional_indicator_b:"; + _textToEmoji[":regional_indicator_a:"] = "🇦"; + _emojiToText["🇦"] = ":regional_indicator_a:"; + _textToEmoji[":red_car:"] = "🚗"; + _emojiToText["🚗"] = ":red_car:"; + _textToEmoji[":automobile:"] = "🚗"; + _emojiToText["🚗"] = ":automobile:"; + _textToEmoji[":taxi:"] = "🚕"; + _emojiToText["🚕"] = ":taxi:"; + _textToEmoji[":blue_car:"] = "🚙"; + _emojiToText["🚙"] = ":blue_car:"; + _textToEmoji[":pickup_truck:"] = "🛻"; + _emojiToText["🛻"] = ":pickup_truck:"; + _textToEmoji[":minibus:"] = "🚐"; + _emojiToText["🚐"] = ":minibus:"; + _textToEmoji[":bus:"] = "🚌"; + _emojiToText["🚌"] = ":bus:"; + _textToEmoji[":trolleybus:"] = "🚎"; + _emojiToText["🚎"] = ":trolleybus:"; + _textToEmoji[":race_car:"] = "🏎️"; + _emojiToText["🏎️"] = ":race_car:"; + _textToEmoji[":racing_car:"] = "🏎️"; + _emojiToText["🏎️"] = ":racing_car:"; + _textToEmoji[":police_car:"] = "🚓"; + _emojiToText["🚓"] = ":police_car:"; + _textToEmoji[":ambulance:"] = "🚑"; + _emojiToText["🚑"] = ":ambulance:"; + _textToEmoji[":fire_engine:"] = "🚒"; + _emojiToText["🚒"] = ":fire_engine:"; + _textToEmoji[":truck:"] = "🚚"; + _emojiToText["🚚"] = ":truck:"; + _textToEmoji[":articulated_lorry:"] = "🚛"; + _emojiToText["🚛"] = ":articulated_lorry:"; + _textToEmoji[":tractor:"] = "🚜"; + _emojiToText["🚜"] = ":tractor:"; + _textToEmoji[":probing_cane:"] = "🦯"; + _emojiToText["🦯"] = ":probing_cane:"; + _textToEmoji[":manual_wheelchair:"] = "🦽"; + _emojiToText["🦽"] = ":manual_wheelchair:"; + _textToEmoji[":motorized_wheelchair:"] = "🦼"; + _emojiToText["🦼"] = ":motorized_wheelchair:"; + _textToEmoji[":crutch:"] = "🩼"; + _emojiToText["🩼"] = ":crutch:"; + _textToEmoji[":scooter:"] = "🛴"; + _emojiToText["🛴"] = ":scooter:"; + _textToEmoji[":kick_scooter:"] = "🛴"; + _emojiToText["🛴"] = ":kick_scooter:"; + _textToEmoji[":bike:"] = "🚲"; + _emojiToText["🚲"] = ":bike:"; + _textToEmoji[":bicycle:"] = "🚲"; + _emojiToText["🚲"] = ":bicycle:"; + _textToEmoji[":motor_scooter:"] = "🛵"; + _emojiToText["🛵"] = ":motor_scooter:"; + _textToEmoji[":motorbike:"] = "🛵"; + _emojiToText["🛵"] = ":motorbike:"; + _textToEmoji[":motorcycle:"] = "🏍️"; + _emojiToText["🏍️"] = ":motorcycle:"; + _textToEmoji[":racing_motorcycle:"] = "🏍️"; + _emojiToText["🏍️"] = ":racing_motorcycle:"; + _textToEmoji[":auto_rickshaw:"] = "🛺"; + _emojiToText["🛺"] = ":auto_rickshaw:"; + _textToEmoji[":wheel:"] = "🛞"; + _emojiToText["🛞"] = ":wheel:"; + _textToEmoji[":rotating_light:"] = "🚨"; + _emojiToText["🚨"] = ":rotating_light:"; + _textToEmoji[":oncoming_police_car:"] = "🚔"; + _emojiToText["🚔"] = ":oncoming_police_car:"; + _textToEmoji[":oncoming_bus:"] = "🚍"; + _emojiToText["🚍"] = ":oncoming_bus:"; + _textToEmoji[":oncoming_automobile:"] = "🚘"; + _emojiToText["🚘"] = ":oncoming_automobile:"; + _textToEmoji[":oncoming_taxi:"] = "🚖"; + _emojiToText["🚖"] = ":oncoming_taxi:"; + _textToEmoji[":aerial_tramway:"] = "🚡"; + _emojiToText["🚡"] = ":aerial_tramway:"; + _textToEmoji[":mountain_cableway:"] = "🚠"; + _emojiToText["🚠"] = ":mountain_cableway:"; + _textToEmoji[":suspension_railway:"] = "🚟"; + _emojiToText["🚟"] = ":suspension_railway:"; + _textToEmoji[":railway_car:"] = "🚃"; + _emojiToText["🚃"] = ":railway_car:"; + _textToEmoji[":train:"] = "🚋"; + _emojiToText["🚋"] = ":train:"; + _textToEmoji[":tram_car:"] = "🚋"; + _emojiToText["🚋"] = ":tram_car:"; + _textToEmoji[":mountain_railway:"] = "🚞"; + _emojiToText["🚞"] = ":mountain_railway:"; + _textToEmoji[":monorail:"] = "🚝"; + _emojiToText["🚝"] = ":monorail:"; + _textToEmoji[":bullettrain_side:"] = "🚄"; + _emojiToText["🚄"] = ":bullettrain_side:"; + _textToEmoji[":bullettrain_front:"] = "🚅"; + _emojiToText["🚅"] = ":bullettrain_front:"; + _textToEmoji[":bullet_train:"] = "🚅"; + _emojiToText["🚅"] = ":bullet_train:"; + _textToEmoji[":light_rail:"] = "🚈"; + _emojiToText["🚈"] = ":light_rail:"; + _textToEmoji[":steam_locomotive:"] = "🚂"; + _emojiToText["🚂"] = ":steam_locomotive:"; + _textToEmoji[":locomotive:"] = "🚂"; + _emojiToText["🚂"] = ":locomotive:"; + _textToEmoji[":train2:"] = "🚆"; + _emojiToText["🚆"] = ":train2:"; + _textToEmoji[":metro:"] = "🚇"; + _emojiToText["🚇"] = ":metro:"; + _textToEmoji[":tram:"] = "🚊"; + _emojiToText["🚊"] = ":tram:"; + _textToEmoji[":station:"] = "🚉"; + _emojiToText["🚉"] = ":station:"; + _textToEmoji[":airplane:"] = "✈️"; + _emojiToText["✈️"] = ":airplane:"; + _textToEmoji[":airplane_departure:"] = "🛫"; + _emojiToText["🛫"] = ":airplane_departure:"; + _textToEmoji[":airplane_arriving:"] = "🛬"; + _emojiToText["🛬"] = ":airplane_arriving:"; + _textToEmoji[":airplane_small:"] = "🛩️"; + _emojiToText["🛩️"] = ":airplane_small:"; + _textToEmoji[":small_airplane:"] = "🛩️"; + _emojiToText["🛩️"] = ":small_airplane:"; + _textToEmoji[":seat:"] = "💺"; + _emojiToText["💺"] = ":seat:"; + _textToEmoji[":satellite_orbital:"] = "🛰️"; + _emojiToText["🛰️"] = ":satellite_orbital:"; + _textToEmoji[":rocket:"] = "🚀"; + _emojiToText["🚀"] = ":rocket:"; + _textToEmoji[":flying_saucer:"] = "🛸"; + _emojiToText["🛸"] = ":flying_saucer:"; + _textToEmoji[":helicopter:"] = "🚁"; + _emojiToText["🚁"] = ":helicopter:"; + _textToEmoji[":canoe:"] = "🛶"; + _emojiToText["🛶"] = ":canoe:"; + _textToEmoji[":kayak:"] = "🛶"; + _emojiToText["🛶"] = ":kayak:"; + _textToEmoji[":sailboat:"] = "⛵"; + _emojiToText["⛵"] = ":sailboat:"; + _textToEmoji[":speedboat:"] = "🚤"; + _emojiToText["🚤"] = ":speedboat:"; + _textToEmoji[":motorboat:"] = "🛥️"; + _emojiToText["🛥️"] = ":motorboat:"; + _textToEmoji[":motor_boat:"] = "🛥️"; + _emojiToText["🛥️"] = ":motor_boat:"; + _textToEmoji[":cruise_ship:"] = "🛳️"; + _emojiToText["🛳️"] = ":cruise_ship:"; + _textToEmoji[":passenger_ship:"] = "🛳️"; + _emojiToText["🛳️"] = ":passenger_ship:"; + _textToEmoji[":ferry:"] = "⛴️"; + _emojiToText["⛴️"] = ":ferry:"; + _textToEmoji[":ship:"] = "🚢"; + _emojiToText["🚢"] = ":ship:"; + _textToEmoji[":ring_buoy:"] = "🛟"; + _emojiToText["🛟"] = ":ring_buoy:"; + _textToEmoji[":anchor:"] = "⚓"; + _emojiToText["⚓"] = ":anchor:"; + _textToEmoji[":hook:"] = "🪝"; + _emojiToText["🪝"] = ":hook:"; + _textToEmoji[":fuelpump:"] = "⛽"; + _emojiToText["⛽"] = ":fuelpump:"; + _textToEmoji[":fuel_pump:"] = "⛽"; + _emojiToText["⛽"] = ":fuel_pump:"; + _textToEmoji[":construction:"] = "🚧"; + _emojiToText["🚧"] = ":construction:"; + _textToEmoji[":vertical_traffic_light:"] = "🚦"; + _emojiToText["🚦"] = ":vertical_traffic_light:"; + _textToEmoji[":traffic_light:"] = "🚥"; + _emojiToText["🚥"] = ":traffic_light:"; + _textToEmoji[":busstop:"] = "🚏"; + _emojiToText["🚏"] = ":busstop:"; + _textToEmoji[":bus_stop:"] = "🚏"; + _emojiToText["🚏"] = ":bus_stop:"; + _textToEmoji[":map:"] = "🗺️"; + _emojiToText["🗺️"] = ":map:"; + _textToEmoji[":world_map:"] = "🗺️"; + _emojiToText["🗺️"] = ":world_map:"; + _textToEmoji[":moyai:"] = "🗿"; + _emojiToText["🗿"] = ":moyai:"; + _textToEmoji[":moai:"] = "🗿"; + _emojiToText["🗿"] = ":moai:"; + _textToEmoji[":statue_of_liberty:"] = "🗽"; + _emojiToText["🗽"] = ":statue_of_liberty:"; + _textToEmoji[":tokyo_tower:"] = "🗼"; + _emojiToText["🗼"] = ":tokyo_tower:"; + _textToEmoji[":european_castle:"] = "🏰"; + _emojiToText["🏰"] = ":european_castle:"; + _textToEmoji[":castle:"] = "🏰"; + _emojiToText["🏰"] = ":castle:"; + _textToEmoji[":japanese_castle:"] = "🏯"; + _emojiToText["🏯"] = ":japanese_castle:"; + _textToEmoji[":stadium:"] = "🏟️"; + _emojiToText["🏟️"] = ":stadium:"; + _textToEmoji[":ferris_wheel:"] = "🎡"; + _emojiToText["🎡"] = ":ferris_wheel:"; + _textToEmoji[":roller_coaster:"] = "🎢"; + _emojiToText["🎢"] = ":roller_coaster:"; + _textToEmoji[":carousel_horse:"] = "🎠"; + _emojiToText["🎠"] = ":carousel_horse:"; + _textToEmoji[":fountain:"] = "⛲"; + _emojiToText["⛲"] = ":fountain:"; + _textToEmoji[":beach_umbrella:"] = "⛱️"; + _emojiToText["⛱️"] = ":beach_umbrella:"; + _textToEmoji[":umbrella_on_ground:"] = "⛱️"; + _emojiToText["⛱️"] = ":umbrella_on_ground:"; + _textToEmoji[":beach:"] = "🏖️"; + _emojiToText["🏖️"] = ":beach:"; + _textToEmoji[":beach_with_umbrella:"] = "🏖️"; + _emojiToText["🏖️"] = ":beach_with_umbrella:"; + _textToEmoji[":island:"] = "🏝️"; + _emojiToText["🏝️"] = ":island:"; + _textToEmoji[":desert_island:"] = "🏝️"; + _emojiToText["🏝️"] = ":desert_island:"; + _textToEmoji[":desert:"] = "🏜️"; + _emojiToText["🏜️"] = ":desert:"; + _textToEmoji[":volcano:"] = "🌋"; + _emojiToText["🌋"] = ":volcano:"; + _textToEmoji[":mountain:"] = "⛰️"; + _emojiToText["⛰️"] = ":mountain:"; + _textToEmoji[":mountain_snow:"] = "🏔️"; + _emojiToText["🏔️"] = ":mountain_snow:"; + _textToEmoji[":snow_capped_mountain:"] = "🏔️"; + _emojiToText["🏔️"] = ":snow_capped_mountain:"; + _textToEmoji[":mount_fuji:"] = "🗻"; + _emojiToText["🗻"] = ":mount_fuji:"; + _textToEmoji[":camping:"] = "🏕️"; + _emojiToText["🏕️"] = ":camping:"; + _textToEmoji[":tent:"] = "⛺"; + _emojiToText["⛺"] = ":tent:"; + _textToEmoji[":house:"] = "🏠"; + _emojiToText["🏠"] = ":house:"; + _textToEmoji[":house_with_garden:"] = "🏡"; + _emojiToText["🏡"] = ":house_with_garden:"; + _textToEmoji[":homes:"] = "🏘️"; + _emojiToText["🏘️"] = ":homes:"; + _textToEmoji[":house_buildings:"] = "🏘️"; + _emojiToText["🏘️"] = ":house_buildings:"; + _textToEmoji[":houses:"] = "🏘️"; + _emojiToText["🏘️"] = ":houses:"; + _textToEmoji[":house_abandoned:"] = "🏚️"; + _emojiToText["🏚️"] = ":house_abandoned:"; + _textToEmoji[":derelict_house_building:"] = "🏚️"; + _emojiToText["🏚️"] = ":derelict_house_building:"; + _textToEmoji[":hut:"] = "🛖"; + _emojiToText["🛖"] = ":hut:"; + _textToEmoji[":construction_site:"] = "🏗️"; + _emojiToText["🏗️"] = ":construction_site:"; + _textToEmoji[":building_construction:"] = "🏗️"; + _emojiToText["🏗️"] = ":building_construction:"; + _textToEmoji[":factory:"] = "🏭"; + _emojiToText["🏭"] = ":factory:"; + _textToEmoji[":office:"] = "🏢"; + _emojiToText["🏢"] = ":office:"; + _textToEmoji[":department_store:"] = "🏬"; + _emojiToText["🏬"] = ":department_store:"; + _textToEmoji[":post_office:"] = "🏣"; + _emojiToText["🏣"] = ":post_office:"; + _textToEmoji[":european_post_office:"] = "🏤"; + _emojiToText["🏤"] = ":european_post_office:"; + _textToEmoji[":hospital:"] = "🏥"; + _emojiToText["🏥"] = ":hospital:"; + _textToEmoji[":bank:"] = "🏦"; + _emojiToText["🏦"] = ":bank:"; + _textToEmoji[":hotel:"] = "🏨"; + _emojiToText["🏨"] = ":hotel:"; + _textToEmoji[":convenience_store:"] = "🏪"; + _emojiToText["🏪"] = ":convenience_store:"; + _textToEmoji[":school:"] = "🏫"; + _emojiToText["🏫"] = ":school:"; + _textToEmoji[":love_hotel:"] = "🏩"; + _emojiToText["🏩"] = ":love_hotel:"; + _textToEmoji[":wedding:"] = "💒"; + _emojiToText["💒"] = ":wedding:"; + _textToEmoji[":classical_building:"] = "🏛️"; + _emojiToText["🏛️"] = ":classical_building:"; + _textToEmoji[":church:"] = "⛪"; + _emojiToText["⛪"] = ":church:"; + _textToEmoji[":mosque:"] = "🕌"; + _emojiToText["🕌"] = ":mosque:"; + _textToEmoji[":synagogue:"] = "🕍"; + _emojiToText["🕍"] = ":synagogue:"; + _textToEmoji[":hindu_temple:"] = "🛕"; + _emojiToText["🛕"] = ":hindu_temple:"; + _textToEmoji[":kaaba:"] = "🕋"; + _emojiToText["🕋"] = ":kaaba:"; + _textToEmoji[":shinto_shrine:"] = "⛩️"; + _emojiToText["⛩️"] = ":shinto_shrine:"; + _textToEmoji[":railway_track:"] = "🛤️"; + _emojiToText["🛤️"] = ":railway_track:"; + _textToEmoji[":railroad_track:"] = "🛤️"; + _emojiToText["🛤️"] = ":railroad_track:"; + _textToEmoji[":motorway:"] = "🛣️"; + _emojiToText["🛣️"] = ":motorway:"; + _textToEmoji[":japan:"] = "🗾"; + _emojiToText["🗾"] = ":japan:"; + _textToEmoji[":map_of_japan:"] = "🗾"; + _emojiToText["🗾"] = ":map_of_japan:"; + _textToEmoji[":rice_scene:"] = "🎑"; + _emojiToText["🎑"] = ":rice_scene:"; + _textToEmoji[":park:"] = "🏞️"; + _emojiToText["🏞️"] = ":park:"; + _textToEmoji[":national_park:"] = "🏞️"; + _emojiToText["🏞️"] = ":national_park:"; + _textToEmoji[":sunrise:"] = "🌅"; + _emojiToText["🌅"] = ":sunrise:"; + _textToEmoji[":sunrise_over_mountains:"] = "🌄"; + _emojiToText["🌄"] = ":sunrise_over_mountains:"; + _textToEmoji[":stars:"] = "🌠"; + _emojiToText["🌠"] = ":stars:"; + _textToEmoji[":shooting_star:"] = "🌠"; + _emojiToText["🌠"] = ":shooting_star:"; + _textToEmoji[":sparkler:"] = "🎇"; + _emojiToText["🎇"] = ":sparkler:"; + _textToEmoji[":fireworks:"] = "🎆"; + _emojiToText["🎆"] = ":fireworks:"; + _textToEmoji[":city_sunset:"] = "🌇"; + _emojiToText["🌇"] = ":city_sunset:"; + _textToEmoji[":city_sunrise:"] = "🌇"; + _emojiToText["🌇"] = ":city_sunrise:"; + _textToEmoji[":sunset:"] = "🌇"; + _emojiToText["🌇"] = ":sunset:"; + _textToEmoji[":city_dusk:"] = "🌆"; + _emojiToText["🌆"] = ":city_dusk:"; + _textToEmoji[":cityscape:"] = "🏙️"; + _emojiToText["🏙️"] = ":cityscape:"; + _textToEmoji[":night_with_stars:"] = "🌃"; + _emojiToText["🌃"] = ":night_with_stars:"; + _textToEmoji[":milky_way:"] = "🌌"; + _emojiToText["🌌"] = ":milky_way:"; + _textToEmoji[":bridge_at_night:"] = "🌉"; + _emojiToText["🌉"] = ":bridge_at_night:"; + _textToEmoji[":foggy:"] = "🌁"; + _emojiToText["🌁"] = ":foggy:"; } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Cache/Entities/EntityCache.cs b/Oxide.Ext.Discord/Cache/Entities/EntityCache.cs index 3e6b8f7a3..bdd491d2a 100644 --- a/Oxide.Ext.Discord/Cache/Entities/EntityCache.cs +++ b/Oxide.Ext.Discord/Cache/Entities/EntityCache.cs @@ -6,59 +6,58 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Cache +namespace Oxide.Ext.Discord.Cache; + +/// +/// Cache for {T} +/// +public sealed class EntityCache : Singleton> where T : class, IDiscordCacheable, new() { + private readonly ConcurrentDictionary _cache = new(); + private readonly Func _valueFactory = id => new T { Id = id }; + /// - /// Cache for {T} + /// Readonly Cache of /// - public sealed class EntityCache : Singleton> where T : class, IDiscordCacheable, new() - { - private readonly ConcurrentDictionary _cache = new ConcurrentDictionary(); - private readonly Func _valueFactory = id => new T { Id = id }; + public readonly IReadOnlyDictionary Cache; - /// - /// Readonly Cache of - /// - public readonly IReadOnlyDictionary Cache; - - private EntityCache() - { - Cache = new ReadOnlyDictionary(_cache); - } + private EntityCache() + { + Cache = new ReadOnlyDictionary(_cache); + } - /// - /// Returns the cached entity with the given ID; default(T) otherwise - /// - /// ID of the entity - public T Get(Snowflake id) => _cache.GetValueOrDefault(id); + /// + /// Returns the cached entity with the given ID; default(T) otherwise + /// + /// ID of the entity + public T Get(Snowflake id) => _cache.GetValueOrDefault(id); - /// - /// Returns a cached for the given user ID or creates a new with that ID - /// - /// User ID to lookup in the cache - /// Cached - public T GetOrCreate(Snowflake id) => id.IsValid() ? _cache.GetOrAdd(id, _valueFactory) : default(T); + /// + /// Returns a cached {T} for the given user ID or creates a new {T} with that ID + /// + /// User ID to lookup in the cache + /// Cached + public T GetOrCreate(Snowflake id) => id.IsValid() ? _cache.GetOrAdd(id, _valueFactory) : default; - /// - /// Updates the cached entity - /// - /// - /// - public T Update(T entity) + /// + /// Updates the cached entity + /// + /// + /// + public T Update(T entity) + { + if (entity == null || !entity.Id.IsValid()) { - if (entity == null || !entity.Id.IsValid()) - { - return entity; - } - - if (!_cache.TryGetValue(entity.Id, out T existing)) - { - _cache[entity.Id] = entity; - return entity; - } + return entity; + } - existing.Update(entity); - return existing; + if (!_cache.TryGetValue(entity.Id, out T existing)) + { + _cache[entity.Id] = entity; + return entity; } + + existing.Update(entity); + return existing; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Cache/EnumCache{T}.cs b/Oxide.Ext.Discord/Cache/EnumCache{T}.cs index 0cfde63c5..c563b00fb 100644 --- a/Oxide.Ext.Discord/Cache/EnumCache{T}.cs +++ b/Oxide.Ext.Discord/Cache/EnumCache{T}.cs @@ -2,176 +2,164 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Text; using Oxide.Ext.Discord.Extensions; -using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Cache +namespace Oxide.Ext.Discord.Cache; + +/// +/// Represents a cache of enum strings +/// +/// Enum type +public sealed class EnumCache : Singleton> where T : struct, IComparable, IFormattable, IConvertible { /// - /// Represents a cache of enum strings + /// Readonly Collection of Enum Values /// - /// Enum type - public sealed class EnumCache : Singleton> where T : struct, IComparable, IFormattable, IConvertible - { - /// - /// Readonly Collection of Enum Values - /// - public readonly ReadOnlyCollection Values; + public readonly ReadOnlyCollection Values; - private readonly T[] _values; - private readonly Dictionary _cachedStrings = new Dictionary(); - private readonly Dictionary _loweredStrings = new Dictionary(); - private readonly Dictionary _numberString = new Dictionary(); - private readonly Type _type; - private readonly bool _isFlagsEnum; - private readonly TypeCode _typeCode; + private readonly T[] _values; + private readonly Dictionary _cachedStrings = new(); + private readonly Dictionary _loweredStrings = new(); + private readonly Dictionary _numberString = new(); + private readonly Type _type; + private readonly bool _isFlagsEnum; + private readonly TypeCode _typeCode; - /// - /// Constructor - /// - private EnumCache() + /// + /// Constructor + /// + private EnumCache() + { + _type = typeof(T); + _isFlagsEnum = _type.HasAttribute(false); + _values = Enum.GetValues(_type).Cast().ToArray(); + _typeCode = Convert.GetTypeCode(_values[0]); + for (int index = 0; index < _values.Length; index++) { - _type = typeof(T); - _isFlagsEnum = _type.HasAttribute(false); - _values = Enum.GetValues(_type).Cast().ToArray(); - _typeCode = Convert.GetTypeCode(_values[0]); - for (int index = 0; index < _values.Length; index++) - { - T value = _values[index]; - string enumString = value.ToString(); - _cachedStrings[value] = enumString; - _loweredStrings[value] = enumString.ToLower(); - } - Values = new ReadOnlyCollection(_values); + T value = _values[index]; + string enumString = value.ToString(); + _cachedStrings[value] = enumString; + _loweredStrings[value] = enumString.ToLower(); } + Values = new ReadOnlyCollection(_values); + } - /// - /// Returns the string representation of the enum - /// - /// Enum value - /// Enum value as string - public string ToString(T value) + /// + /// Returns the string representation of the enum + /// + /// Enum value + /// Enum value as string + public string ToString(T value) + { + if (_cachedStrings.TryGetValue(value, out string str)) { - if (_cachedStrings.TryGetValue(value, out string str)) - { - return str; - } - - str = _isFlagsEnum ? CreateFlagsString(value) : value.ToString(); - - _cachedStrings[value] = str; return str; } + + str = _isFlagsEnum ? CreateFlagsString(value) : value.ToString(); + + _cachedStrings[value] = str; + return str; + } - /// - /// Returns the lowered string representation of the enum - /// - /// Enum value - /// Enum value as lowered string - public string ToLower(T value) + /// + /// Returns the lowered string representation of the enum + /// + /// Enum value + /// Enum value as lowered string + public string ToLower(T value) + { + if (!_loweredStrings.TryGetValue(value, out string str)) { - if (!_loweredStrings.TryGetValue(value, out string str)) - { - str = ToString(value).ToLower(); - _loweredStrings[value] = str; - } - return str; + str = ToString(value).ToLower(); + _loweredStrings[value] = str; } + return str; + } - /// - /// Converts the enum to it's number form as a string - /// - /// - /// - public string ToNumber(T value) + /// + /// Converts the enum to it's number form as a string + /// + /// + /// + public string ToNumber(T value) + { + if (!_numberString.TryGetValue(value, out string str)) { - if (!_numberString.TryGetValue(value, out string str)) - { - str = value.ToType(Enum.GetUnderlyingType(_type), null).ToString(); - _numberString[value] = str; - } - - return str; + str = value.ToType(Enum.GetUnderlyingType(_type), null).ToString(); + _numberString[value] = str; } - /// - /// Returns the next enum values. If the value is the last value it will start from the beginning - /// - /// Value to get the next enum from - /// Next enum from the given value - public T Next(T value) - { - int index = Array.IndexOf(_values, value) + 1; - return _values.Length == index ? _values[0] : _values[index]; - } + return str; + } + + /// + /// Returns the next enum values. If the value is the last value, it will start from the beginning + /// + /// Value to get the next enum from + /// Next enum from the given value + public T Next(T value) + { + int index = Array.IndexOf(_values, value) + 1; + return _values.Length == index ? _values[0] : _values[index]; + } - /// - /// Returns the previous enum values. - /// - /// Value to get the previous enum from - /// Previous enum from the given value - public T Previous(T value) - { - int index = Array.IndexOf(_values, value) + 1; - return index == 0 ? _values[_values.Length] : _values[index]; - } + /// + /// Returns the previous enum values. + /// + /// Value to get the previous enum from + /// Previous enum from the given value + public T Previous(T value) + { + int index = Array.IndexOf(_values, value) + 1; + return index == 0 ? _values[_values.Length] : _values[index]; + } - private int GetTypeSize() + private int GetTypeSize() + { + return _typeCode switch { - switch (_typeCode) - { - case TypeCode.SByte: - case TypeCode.Byte: - return 8; - case TypeCode.Int16: - case TypeCode.UInt16: - return 16; - case TypeCode.Int32: - case TypeCode.UInt32: - return 32; - case TypeCode.Int64: - case TypeCode.UInt64: - return 64; - default: - throw new ArgumentOutOfRangeException(); - } - } + TypeCode.SByte or TypeCode.Byte => 8, + TypeCode.Int16 or TypeCode.UInt16 => 16, + TypeCode.Int32 or TypeCode.UInt32 => 32, + TypeCode.Int64 or TypeCode.UInt64 => 64, + _ => throw new ArgumentOutOfRangeException() + }; + } - private string CreateFlagsString(T value) + private string CreateFlagsString(T value) + { + ValueStringBuilder sb = new(); + bool initial = true; + int length = GetTypeSize(); + for (int index = 0; index < length; index++) { - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); - bool initial = true; - int length = GetTypeSize(); - for (int index = 0; index < length; index++) + ulong enumValue = 1ul << index; + if ((value.ToUInt64(null) & enumValue) != 0ul) { - ulong enumValue = 1ul << index; - if ((value.ToUInt64(null) & enumValue) != 0ul) + if (!initial) { - if (!initial) - { - sb.Append(", "); - } + sb.Append(", "); + } - initial = false; + initial = false; - object converted = Convert.ChangeType(enumValue, _typeCode); - if (Enum.IsDefined(_type, converted)) - { - sb.Append(Enum.GetName(_type, converted)); - } - else - { - sb.Append("Unknown Value (1 << "); - sb.Append(index); - sb.Append(')'); - } + object converted = Convert.ChangeType(enumValue, _typeCode); + if (Enum.IsDefined(_type, converted)) + { + sb.Append(Enum.GetName(_type, converted)); + } + else + { + sb.Append("Unknown Value (1 << "); + sb.Append(index); + sb.Append(')'); } } - - return DiscordPool.Internal.ToStringAndFree(sb); } + return sb.ToString(); } + } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Cache/FileAttachmentCache.cs b/Oxide.Ext.Discord/Cache/FileAttachmentCache.cs index 3138daaf7..a5a11ece1 100644 --- a/Oxide.Ext.Discord/Cache/FileAttachmentCache.cs +++ b/Oxide.Ext.Discord/Cache/FileAttachmentCache.cs @@ -1,28 +1,27 @@ using System.Collections.Generic; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Cache +namespace Oxide.Ext.Discord.Cache; + +/// +/// Caches file names when sending attachments +/// +internal sealed class FileAttachmentCache : Singleton { - /// - /// Caches file names when sending attachments - /// - internal sealed class FileAttachmentCache : Singleton - { - private readonly List _cache = new List(); + private readonly List _cache = new(); - private FileAttachmentCache() { } + private FileAttachmentCache() { } - internal string GetName(int index) + internal string GetName(int index) + { + if (index >= _cache.Count) { - if (index >= _cache.Count) + for (int i = _cache.Count; i <= index; i++) { - for (int i = _cache.Count; i <= index; i++) - { - _cache.Add($"files[{(index + 1).ToString()}]"); - } + _cache.Add($"files[{(index + 1).ToString()}]"); } - - return _cache[index]; } + + return _cache[index]; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Cache/MediaTypeHeaderCache.cs b/Oxide.Ext.Discord/Cache/MediaTypeHeaderCache.cs index 56f990736..2a2affc2e 100644 --- a/Oxide.Ext.Discord/Cache/MediaTypeHeaderCache.cs +++ b/Oxide.Ext.Discord/Cache/MediaTypeHeaderCache.cs @@ -3,30 +3,29 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Cache +namespace Oxide.Ext.Discord.Cache; + +internal sealed class MediaTypeHeaderCache : Singleton { - internal sealed class MediaTypeHeaderCache : Singleton + private readonly Hash _cache = new(); + private const string JsonHeader = "application/json"; + + private MediaTypeHeaderCache() { - private readonly Hash _cache = new Hash(); - private const string JsonHeader = "application/json"; + MediaTypeHeaderValue header = MediaTypeHeaderValue.Parse(JsonHeader); + header.CharSet = DiscordEncoding.Instance.Encoding.WebName; + _cache[JsonHeader] = header; + } - private MediaTypeHeaderCache() + public MediaTypeHeaderValue Get(string value) + { + MediaTypeHeaderValue header = _cache[value]; + if (header == null) { - MediaTypeHeaderValue header = MediaTypeHeaderValue.Parse(JsonHeader); - header.CharSet = DiscordEncoding.Instance.Encoding.WebName; - _cache[JsonHeader] = header; + header = MediaTypeHeaderValue.Parse(value); + _cache[value] = header; } - public MediaTypeHeaderValue Get(string value) - { - MediaTypeHeaderValue header = _cache[value]; - if (header == null) - { - header = MediaTypeHeaderValue.Parse(value); - _cache[value] = header; - } - - return header; - } + return header; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Cache/OxideLibrary.cs b/Oxide.Ext.Discord/Cache/OxideLibrary.cs index 43b2f7646..4b6ade396 100644 --- a/Oxide.Ext.Discord/Cache/OxideLibrary.cs +++ b/Oxide.Ext.Discord/Cache/OxideLibrary.cs @@ -5,16 +5,15 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Cache +namespace Oxide.Ext.Discord.Cache; + +internal sealed class OxideLibrary : Singleton { - internal sealed class OxideLibrary : Singleton - { - internal readonly Covalence Covalence = Interface.Oxide.GetLibrary(); - internal readonly Permission Permission = Interface.Oxide.GetLibrary(); - internal readonly Lang Lang = Interface.Oxide.GetLibrary(); - internal readonly Core.Libraries.Plugins Plugins = Interface.Oxide.GetLibrary(); - internal readonly CSharpPluginLoader PluginLoader = Interface.Oxide.GetPluginLoaders().OfType().FirstOrDefault(); + internal readonly Covalence Covalence = Interface.Oxide.GetLibrary(); + internal readonly Permission Permission = Interface.Oxide.GetLibrary(); + internal readonly Lang Lang = Interface.Oxide.GetLibrary(); + internal readonly Core.Libraries.Plugins Plugins = Interface.Oxide.GetLibrary(); + internal readonly CSharpPluginLoader PluginLoader = Interface.Oxide.GetPluginLoaders().OfType().FirstOrDefault(); - private OxideLibrary() { } - } + private OxideLibrary() { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Cache/ServerPlayerCache.cs b/Oxide.Ext.Discord/Cache/ServerPlayerCache.cs index d1c4d37dc..f4d923468 100644 --- a/Oxide.Ext.Discord/Cache/ServerPlayerCache.cs +++ b/Oxide.Ext.Discord/Cache/ServerPlayerCache.cs @@ -7,60 +7,59 @@ using Oxide.Ext.Discord.Services; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Cache +namespace Oxide.Ext.Discord.Cache; + +/// +/// Cache for server +/// +public sealed class ServerPlayerCache : Singleton { - /// - /// Cache for server - /// - public sealed class ServerPlayerCache : Singleton - { - private readonly ConcurrentDictionary _dummyPlayerCache = new ConcurrentDictionary(); - private readonly Func _valueFactory = id => new DiscordDummyPlayer(id); - private IPlayerSearchService _search; + private readonly ConcurrentDictionary _dummyPlayerCache = new(); + private readonly Func _valueFactory = id => new DiscordDummyPlayer(id); + private IPlayerSearchService _search; - private static readonly IPlayerManager Players = OxideLibrary.Instance.Covalence.Players; + private static readonly IPlayerManager Players = OxideLibrary.Instance.Covalence.Players; - private ServerPlayerCache() { } + private ServerPlayerCache() { } - /// - /// Returns the for the given ID - /// - /// ID of the player - /// - public IPlayer GetPlayerById(string id) => Players.FindPlayerById(id) ?? _dummyPlayerCache.GetOrAdd(id, _valueFactory); + /// + /// Returns the for the given ID + /// + /// ID of the player + /// + public IPlayer GetPlayerById(string id) => Players.FindPlayerById(id) ?? _dummyPlayerCache.GetOrAdd(id, _valueFactory); - /// - /// Returns an matching player names that are online - /// - /// Name to match on - /// - public IEnumerable GetOnlinePlayers(string name) => _search.GetOnlinePlayers(name); + /// + /// Returns an matching player names that are online + /// + /// Name to match on + /// + public IEnumerable GetOnlinePlayers(string name) => _search.GetOnlinePlayers(name); - /// - /// Returns an matching player names - /// - /// Name to match on - /// - public IEnumerable GetAllPlayers(string name) => _search.GetAllPlayers(name); + /// + /// Returns an matching player names + /// + /// Name to match on + /// + public IEnumerable GetAllPlayers(string name) => _search.GetAllPlayers(name); - internal void SetSearchService() + internal void SetSearchService() + { + if (DiscordConfig.Instance.Search.EnablePlayerNameSearchTrie) { - if (DiscordConfig.Instance.Search.EnablePlayerNameSearchTrie) - { - _search = new UkkonenTrieService(); - } - else - { - _search = new CovalenceSearchService(); - } + _search = new UkkonenTrieService(); } - - internal void OnUserConnected(IPlayer player) + else { - _search.OnUserConnected(player); + _search = new CovalenceSearchService(); } + } - internal void OnUserDisconnected(IPlayer player) => _search.OnUserDisconnected(player); - internal void OnUserNameUpdated(IPlayer player, string oldName, string newName) => _search.OnUserNameUpdated(player, oldName, newName); + internal void OnUserConnected(IPlayer player) + { + _search.OnUserConnected(player); } + + internal void OnUserDisconnected(IPlayer player) => _search.OnUserDisconnected(player); + internal void OnUserNameUpdated(IPlayer player, string oldName, string newName) => _search.OnUserNameUpdated(player, oldName, newName); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Cache/StringCache{T}.cs b/Oxide.Ext.Discord/Cache/StringCache{T}.cs index a6077e6ec..8d7835f06 100644 --- a/Oxide.Ext.Discord/Cache/StringCache{T}.cs +++ b/Oxide.Ext.Discord/Cache/StringCache{T}.cs @@ -1,48 +1,47 @@ using System.Collections.Generic; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Cache +namespace Oxide.Ext.Discord.Cache; + +/// +/// Caches strings from {T} ToString method +/// +/// Type for the cache +public sealed class StringCache : Singleton> { + private readonly Dictionary _cachedStrings = new(); + private readonly Dictionary _loweredStrings = new(); + + private StringCache() { } + /// - /// Caches strings from {T} ToString method + /// Returns a cached ToString call of the type {T} /// - /// Type for the cache - public sealed class StringCache : Singleton> + /// value to ToString + /// + public string ToString(T value) { - private readonly Dictionary _cachedStrings = new Dictionary(); - private readonly Dictionary _loweredStrings = new Dictionary(); - - private StringCache() { } - - /// - /// Returns a cached ToString call of type {T} - /// - /// value to ToString - /// - public string ToString(T value) + if (!_cachedStrings.TryGetValue(value, out string str)) { - if (!_cachedStrings.TryGetValue(value, out string str)) - { - str = value.ToString(); - _cachedStrings[value] = str; - } - - return str; + str = value.ToString(); + _cachedStrings[value] = str; } + + return str; + } - /// - /// Returns the lowered string representation of type {T} - /// - /// value to lower - /// - public string ToLower(T value) + /// + /// Returns the lowered string representation of the type {T} + /// + /// value to lower + /// + public string ToLower(T value) + { + if (!_loweredStrings.TryGetValue(value, out string str)) { - if (!_loweredStrings.TryGetValue(value, out string str)) - { - str = value.ToString().ToLower(); - _loweredStrings[value] = str; - } - return str; + str = value.ToString().ToLower(); + _loweredStrings[value] = str; } + return str; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/BaseAsyncCallback.cs b/Oxide.Ext.Discord/Callbacks/BaseAsyncCallback.cs index dbe419c7b..67293282f 100644 --- a/Oxide.Ext.Discord/Callbacks/BaseAsyncCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/BaseAsyncCallback.cs @@ -4,60 +4,59 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +/// +/// Represents a base callback to be used when needing a lambda callback so no delegate or class is generated +/// This class is pooled to prevent allocations +/// +public abstract class BaseAsyncCallback : BasePoolable { /// - /// Represents a base callback to be used when needing a lambda callback so no delegate or class is generated - /// This class is pooled to prevent allocations + /// The callback to be called by the delegate /// - public abstract class BaseAsyncCallback : BasePoolable - { - /// - /// The callback to be called by the delegate - /// - private readonly Action _callback; + private readonly Func _callback; - /// - /// Constructor - /// - protected BaseAsyncCallback() - { - _callback = CallbackInternal; - } + /// + /// Constructor + /// + protected BaseAsyncCallback() + { + _callback = CallbackInternal; + } - /// - /// Overridden in the child class to handle the callback - /// - protected abstract ValueTask HandleCallback(); + /// + /// Overridden in the child class to handle the callback + /// + protected abstract ValueTask HandleCallback(); - /// - /// Returns Exception message if an error occurs - /// - /// - protected abstract string GetExceptionMessage(); + /// + /// Returns Exception message if an error occurs + /// + /// + protected abstract string GetExceptionMessage(); - /// - /// Runs the callback using async - /// - protected void Run() + /// + /// Runs the callback using async + /// + protected void Run() + { + Task.Run(_callback); + } + + private async ValueTask CallbackInternal() + { + try { - Task.Run(_callback); + await HandleCallback().ConfigureAwait(false); } - - private async void CallbackInternal() + catch (Exception ex) + { + DiscordExtension.GlobalLogger.Exception("{0}.CallbackInternal had exception. Callback Data: {1}", GetType().GetRealTypeName(), GetExceptionMessage(), ex); + } + finally { - try - { - await HandleCallback().ConfigureAwait(false); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("{0}.CallbackInternal had exception. Callback Data: {1}", GetType().GetRealTypeName(), GetExceptionMessage(), ex); - } - finally - { - Dispose(); - } + Dispose(); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/BaseCallback.cs b/Oxide.Ext.Discord/Callbacks/BaseCallback.cs index 9dc3fe1d9..aec1aedd5 100644 --- a/Oxide.Ext.Discord/Callbacks/BaseCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/BaseCallback.cs @@ -1,50 +1,49 @@ using System; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +/// +/// Represents a base callback to be used when needing a lambda callback so no delegate or class is generated +/// This class is pooled to prevent allocations +/// +public abstract class BaseCallback : BasePoolable { /// - /// Represents a base callback to be used when needing a lambda callback so no delegate or class is generated - /// This class is pooled to prevent allocations + /// The callback to be called by the delegate /// - public abstract class BaseCallback : BasePoolable - { - /// - /// The callback to be called by the delegate - /// - protected readonly Action Callback; + protected readonly Action Callback; - /// - /// Constructor - /// - protected BaseCallback() - { - Callback = CallbackInternal; - } + /// + /// Constructor + /// + protected BaseCallback() + { + Callback = CallbackInternal; + } - /// - /// Overridden in the child class to handle the callback - /// - protected abstract void HandleCallback(); + /// + /// Overridden in the child class to handle the callback + /// + protected abstract void HandleCallback(); + + /// + /// Run the callback + /// + protected virtual void Run() + { + Callback.Invoke(); + } - /// - /// Run the callback - /// - protected virtual void Run() + private void CallbackInternal() + { + try { - Callback.Invoke(); + HandleCallback(); } - - private void CallbackInternal() + finally { - try - { - HandleCallback(); - } - finally - { - Dispose(); - } + Dispose(); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/BaseCallback{T}.cs b/Oxide.Ext.Discord/Callbacks/BaseCallback{T}.cs index ab7a874cb..f645e8f5f 100644 --- a/Oxide.Ext.Discord/Callbacks/BaseCallback{T}.cs +++ b/Oxide.Ext.Discord/Callbacks/BaseCallback{T}.cs @@ -1,50 +1,49 @@ using System; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +/// +/// Represents a base callback to be used when needing a lambda callback so no delegate or class is generated +/// This class is pooled to prevent allocations +/// +public abstract class BaseCallback : BasePoolable { /// - /// Represents a base callback to be used when needing a lambda callback so no delegate or class is generated - /// This class is pooled to prevent allocations + /// The callback to be called by the delegate /// - public abstract class BaseCallback : BasePoolable - { - /// - /// The callback to be called by the delegate - /// - private readonly Action _callback; + private readonly Action _callback; - /// - /// Constructor - /// - protected BaseCallback() - { - _callback = CallbackInternal; - } + /// + /// Constructor + /// + protected BaseCallback() + { + _callback = CallbackInternal; + } - /// - /// Overridden in the child class to handle the callback - /// - protected abstract void HandleCallback(T data); + /// + /// Overridden in the child class to handle the callback + /// + protected abstract void HandleCallback(T data); + + /// + /// Run the callback + /// + public virtual void Start(T data) + { + _callback.Invoke(data); + } - /// - /// Run the callback - /// - public virtual void Start(T data) + private void CallbackInternal(T data) + { + try { - _callback.Invoke(data); + HandleCallback(data); } - - private void CallbackInternal(T data) + finally { - try - { - HandleCallback(data); - } - finally - { - Dispose(); - } + Dispose(); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/BaseNextTickCallback.cs b/Oxide.Ext.Discord/Callbacks/BaseNextTickCallback.cs index f8f1ea63a..724fa3895 100644 --- a/Oxide.Ext.Discord/Callbacks/BaseNextTickCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/BaseNextTickCallback.cs @@ -1,16 +1,15 @@ using Oxide.Core; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +/// +/// Represents a callback that calls next tick +/// +public abstract class BaseNextTickCallback : BaseCallback { - /// - /// Represents a callback that calls next tick - /// - public abstract class BaseNextTickCallback : BaseCallback + /// + protected sealed override void Run() { - /// - protected sealed override void Run() - { - Interface.Oxide.NextTick(Callback); - } + Interface.Oxide.NextTick(Callback); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Data/GetIpDataCallback.cs b/Oxide.Ext.Discord/Callbacks/Data/GetIpDataCallback.cs index 180d2b0f7..16f2c0429 100644 --- a/Oxide.Ext.Discord/Callbacks/Data/GetIpDataCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Data/GetIpDataCallback.cs @@ -3,36 +3,35 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Services.IpApi; -namespace Oxide.Ext.Discord.Callbacks.Data +namespace Oxide.Ext.Discord.Callbacks.Data; + +internal class GetIpDataCallback : BaseAsyncCallback { - internal class GetIpDataCallback : BaseAsyncCallback - { - private string _ip; + private string _ip; - public static void Start(string ip) - { - GetIpDataCallback callback = DiscordPool.Internal.Get(); - callback.Init(ip); - callback.Run(); - } + public static void Start(string ip) + { + GetIpDataCallback callback = DiscordPool.Internal.Get(); + callback.Init(ip); + callback.Run(); + } - private void Init(string ip) - { - _ip = ip; - } + private void Init(string ip) + { + _ip = ip; + } - protected override async ValueTask HandleCallback() + protected override async ValueTask HandleCallback() + { + IpResult result = await IpApiService.Instance.GetCountryCode(_ip).ConfigureAwait(false); + if (result != null) { - IpResult result = await IpApiService.Instance.GetCountryCode(_ip).ConfigureAwait(false); - if (result != null) - { - DiscordIpData.Instance.AddData(_ip, result); - } + DiscordIpData.Instance.AddData(_ip, result); } + } - protected override string GetExceptionMessage() - { - return $"IP: {_ip}"; - } + protected override string GetExceptionMessage() + { + return $"IP: {_ip}"; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Hooks/PluginHookCallback.cs b/Oxide.Ext.Discord/Callbacks/Hooks/PluginHookCallback.cs index 912b5c08e..3480937f4 100644 --- a/Oxide.Ext.Discord/Callbacks/Hooks/PluginHookCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Hooks/PluginHookCallback.cs @@ -3,64 +3,63 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal class PluginHookCallback : BaseNextTickCallback { - internal class PluginHookCallback : BaseNextTickCallback - { - private string _name; - private object[] _args; - private Plugin _plugin; - private List _plugins; + private string _name; + private object[] _args; + private Plugin _plugin; + private List _plugins; - public static void Start(Plugin plugin, string name, object[] args) - { - PluginHookCallback callback = DiscordPool.Internal.Get(); - callback.Init(plugin, name, args); - callback.Run(); - } + public static void Start(Plugin plugin, string name, object[] args) + { + PluginHookCallback callback = DiscordPool.Internal.Get(); + callback.Init(plugin, name, args); + callback.Run(); + } - public static void Start(List plugins, string name, object[] args) - { - PluginHookCallback callback = DiscordPool.Internal.Get(); - callback.Init(plugins, name, args); - callback.Run(); - } + public static void Start(List plugins, string name, object[] args) + { + PluginHookCallback callback = DiscordPool.Internal.Get(); + callback.Init(plugins, name, args); + callback.Run(); + } - private void Init(Plugin plugin, string hook, object[] args) - { - Init(hook, args); - _plugin = plugin; - } + private void Init(Plugin plugin, string hook, object[] args) + { + Init(hook, args); + _plugin = plugin; + } - private void Init(List plugins, string hook, object[] args) - { - Init(hook, args); - _plugins = plugins; - } + private void Init(List plugins, string hook, object[] args) + { + Init(hook, args); + _plugins = plugins; + } - private void Init(string hook, object[] args) - { - _name = hook; - _args = args; - } + private void Init(string hook, object[] args) + { + _name = hook; + _args = args; + } - protected override void HandleCallback() + protected override void HandleCallback() + { + if (_plugin != null) { - if (_plugin != null) - { - DiscordHook.CallHook(_plugin, _name, _args); - return; - } - - DiscordHook.CallHook(_plugins, _name, _args); + DiscordHook.CallHook(_plugin, _name, _args); + return; } + + DiscordHook.CallHook(_plugins, _name, _args); + } - protected override void EnterPool() - { - _name = null; - _args = null; - _plugin = null; - _plugins = null; - } + protected override void EnterPool() + { + _name = null; + _args = null; + _plugin = null; + _plugins = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Libraries/AppCommandCallback.cs b/Oxide.Ext.Discord/Callbacks/Libraries/AppCommandCallback.cs index e94206b2f..ea054cf36 100644 --- a/Oxide.Ext.Discord/Callbacks/Libraries/AppCommandCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Libraries/AppCommandCallback.cs @@ -1,35 +1,34 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal class AppCommandCallback : BaseNextTickCallback { - internal class AppCommandCallback : BaseNextTickCallback - { - private BaseAppCommand _command; - private DiscordInteraction _interaction; + private BaseAppCommand _command; + private DiscordInteraction _interaction; - public static void Start(BaseAppCommand command, DiscordInteraction interaction) - { - AppCommandCallback sub = DiscordPool.Internal.Get(); - sub.Init(command, interaction); - sub.Run(); - } + public static void Start(BaseAppCommand command, DiscordInteraction interaction) + { + AppCommandCallback sub = DiscordPool.Internal.Get(); + sub.Init(command, interaction); + sub.Run(); + } - private void Init(BaseAppCommand command, DiscordInteraction interaction) - { - _command = command; - _interaction = interaction; - } + private void Init(BaseAppCommand command, DiscordInteraction interaction) + { + _command = command; + _interaction = interaction; + } - protected override void HandleCallback() - { - _command.HandleCommandInternal(_interaction); - } + protected override void HandleCallback() + { + _command.HandleCommandInternal(_interaction); + } - protected override void EnterPool() - { - _command = null; - _interaction = null; - } + protected override void EnterPool() + { + _command = null; + _interaction = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Libraries/SubscriptionCallback.cs b/Oxide.Ext.Discord/Callbacks/Libraries/SubscriptionCallback.cs index 507810193..56b928159 100644 --- a/Oxide.Ext.Discord/Callbacks/Libraries/SubscriptionCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Libraries/SubscriptionCallback.cs @@ -5,55 +5,54 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal class SubscriptionCallback : BaseNextTickCallback { - internal class SubscriptionCallback : BaseNextTickCallback + private DiscordMessage _message; + private Action _callback; + private Plugin _plugin; + + public static void Start(Plugin plugin, DiscordMessage message, Action callback) + { + SubscriptionCallback sub = DiscordPool.Internal.Get(); + sub.Init(plugin, message, callback); + sub.Run(); + } + + private void Init(Plugin plugin, DiscordMessage message, Action callback) { - private DiscordMessage _message; - private Action _callback; - private Plugin _plugin; + _message = message; + _callback = callback; + _plugin = plugin; + } - public static void Start(Plugin plugin, DiscordMessage message, Action callback) + protected override void HandleCallback() + { + if (_plugin is not {IsLoaded: true}) { - SubscriptionCallback sub = DiscordPool.Internal.Get(); - sub.Init(plugin, message, callback); - sub.Run(); + return; } - - private void Init(Plugin plugin, DiscordMessage message, Action callback) + + try { - _message = message; - _callback = callback; - _plugin = plugin; + _plugin.TrackStart(); + _callback.Invoke(_message); } - - protected override void HandleCallback() + catch (Exception ex) { - if (_plugin == null || !_plugin.IsLoaded) - { - return; - } - - try - { - _plugin.TrackStart(); - _callback.Invoke(_message); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An exception occured for discord subscription in channel {0} for plugin {1}", _message.ChannelId, _plugin.FullName(), ex); - } - finally - { - _plugin.TrackEnd(); - } + DiscordExtension.GlobalLogger.Exception("An exception occured for discord subscription in channel {0} for plugin {1}", _message.ChannelId, _plugin.FullName(), ex); } - - protected override void EnterPool() + finally { - _plugin = null; - _message = null; - _callback = null; + _plugin.TrackEnd(); } } + + protected override void EnterPool() + { + _plugin = null; + _message = null; + _callback = null; + } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Promises/BasePromiseCallback.cs b/Oxide.Ext.Discord/Callbacks/Promises/BasePromiseCallback.cs index d53db4a6f..067b9186f 100644 --- a/Oxide.Ext.Discord/Callbacks/Promises/BasePromiseCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Promises/BasePromiseCallback.cs @@ -2,53 +2,52 @@ using Oxide.Core; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal abstract class BasePromiseCallback : BasePoolable { - internal abstract class BasePromiseCallback : BasePoolable + internal readonly Action RunRejected; + private Action _onFail; + private readonly Action _dispose; + private BasePromise _rejectable; + + protected BasePromiseCallback() { - internal readonly Action RunRejected; - private Action _onFail; - private readonly Action _dispose; - private BasePromise _rejectable; + RunRejected = FailInternal; + _dispose = Dispose; + } - protected BasePromiseCallback() - { - RunRejected = FailInternal; - _dispose = Dispose; - } + protected void OnInit(BasePromise rejectable, Action onFail) + { + _rejectable = rejectable; + _onFail = onFail; + } - protected void OnInit(BasePromise rejectable, Action onFail) + private void FailInternal(Exception exception) + { + try { - _rejectable = rejectable; - _onFail = onFail; + _onFail?.Invoke(exception); + _rejectable.Reject(exception); } - - private void FailInternal(Exception exception) + catch (Exception ex) { - try - { - _onFail?.Invoke(exception); - _rejectable.Reject(exception); - } - catch (Exception ex) - { - _rejectable.Reject(ex); - } - finally - { - DelayDispose(); - } + _rejectable.Reject(ex); } - - protected override void EnterPool() + finally { - _rejectable = null; - _onFail = null; + DelayDispose(); } + } - protected void DelayDispose() - { - Interface.Oxide.NextTick(_dispose); - } + protected override void EnterPool() + { + _rejectable = null; + _onFail = null; + } + + protected void DelayDispose() + { + Interface.Oxide.NextTick(_dispose); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Promises/PromiseCallback.cs b/Oxide.Ext.Discord/Callbacks/Promises/PromiseCallback.cs index ebcf76a3b..1681999f3 100644 --- a/Oxide.Ext.Discord/Callbacks/Promises/PromiseCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Promises/PromiseCallback.cs @@ -2,55 +2,54 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal class PromiseCallback : BasePromiseCallback { - internal class PromiseCallback : BasePromiseCallback + internal readonly Action RunResolve; + private Action _onResolve; + private Promise _promise; + + public PromiseCallback() { - internal readonly Action RunResolve; - private Action _onResolve; - private Promise _promise; + RunResolve = ResolveInternal; + } - public PromiseCallback() - { - RunResolve = ResolveInternal; - } + internal static PromiseCallback Create(Promise promise, Action onResolve, Action onReject) + { + PromiseCallback callback = DiscordPool.Internal.Get(); + callback.OnInit(promise, onResolve, onReject); + return callback; + } - internal static PromiseCallback Create(Promise promise, Action onResolve, Action onReject) - { - PromiseCallback callback = DiscordPool.Internal.Get(); - callback.OnInit(promise, onResolve, onReject); - return callback; - } + private void OnInit(Promise promise, Action onResolve, Action onFail) + { + base.OnInit(promise, onFail); + _promise = promise; + _onResolve = onResolve; + } - private void OnInit(Promise promise, Action onResolve, Action onFail) + private void ResolveInternal() + { + try { - base.OnInit(promise, onFail); - _promise = promise; - _onResolve = onResolve; + _onResolve?.Invoke(); + _promise.Resolve(); } - - private void ResolveInternal() + catch (Exception ex) { - try - { - _onResolve?.Invoke(); - _promise.Resolve(); - } - catch (Exception ex) - { - _promise.Reject(ex); - } - finally - { - DelayDispose(); - } + _promise.Reject(ex); } - - protected override void EnterPool() + finally { - base.EnterPool(); - _onResolve = null; - _promise = null; + DelayDispose(); } } + + protected override void EnterPool() + { + base.EnterPool(); + _onResolve = null; + _promise = null; + } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Promises/PromiseCallback{T}.cs b/Oxide.Ext.Discord/Callbacks/Promises/PromiseCallback{T}.cs index b9d971aaa..d2c1d3019 100644 --- a/Oxide.Ext.Discord/Callbacks/Promises/PromiseCallback{T}.cs +++ b/Oxide.Ext.Discord/Callbacks/Promises/PromiseCallback{T}.cs @@ -2,55 +2,54 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal class PromiseCallback : BasePromiseCallback { - internal class PromiseCallback : BasePromiseCallback + internal readonly Action RunResolve; + private Action _onResolve; + private Promise _promise; + + public PromiseCallback() { - internal readonly Action RunResolve; - private Action _onResolve; - private Promise _promise; + RunResolve = ResolveInternal; + } - public PromiseCallback() - { - RunResolve = ResolveInternal; - } + internal static PromiseCallback Create(Promise promise, Action onResolve, Action onReject) + { + PromiseCallback callback = DiscordPool.Internal.Get>(); + callback.OnInit(promise, onResolve, onReject); + return callback; + } - internal static PromiseCallback Create(Promise promise, Action onResolve, Action onReject) - { - PromiseCallback callback = DiscordPool.Internal.Get>(); - callback.OnInit(promise, onResolve, onReject); - return callback; - } + private void OnInit(Promise promise, Action onResolve, Action onFail) + { + base.OnInit(promise, onFail); + _promise = promise; + _onResolve = onResolve; + } - private void OnInit(Promise promise, Action onResolve, Action onFail) + private void ResolveInternal(T value) + { + try { - base.OnInit(promise, onFail); - _promise = promise; - _onResolve = onResolve; + _onResolve?.Invoke(value); + _promise.Resolve(value); } - - private void ResolveInternal(T value) + catch (Exception ex) { - try - { - _onResolve?.Invoke(value); - _promise.Resolve(value); - } - catch (Exception ex) - { - _promise.Reject(ex); - } - finally - { - DelayDispose(); - } + _promise.Reject(ex); } - - protected override void EnterPool() + finally { - base.EnterPool(); - _onResolve = null; - _promise = null; + DelayDispose(); } } + + protected override void EnterPool() + { + base.EnterPool(); + _onResolve = null; + _promise = null; + } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Templates/BulkRegisterMessageTemplateCallback.cs b/Oxide.Ext.Discord/Callbacks/Templates/BulkRegisterMessageTemplateCallback.cs index 2148cebe5..818cb060e 100644 --- a/Oxide.Ext.Discord/Callbacks/Templates/BulkRegisterMessageTemplateCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Templates/BulkRegisterMessageTemplateCallback.cs @@ -4,50 +4,49 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal class BulkRegisterTemplateCallback : BaseAsyncCallback where TTemplate : class { - internal class BulkRegisterTemplateCallback : BaseAsyncCallback where TTemplate : class - { - private BaseTemplateLibrary _library; - private TemplateId _id; - private List> _templates; - private TemplateVersion _minVersion; - private IPendingPromise _promise; + private BaseTemplateLibrary _library; + private TemplateId _id; + private List> _templates; + private TemplateVersion _minVersion; + private IPendingPromise _promise; - public static void Start(BaseTemplateLibrary library, TemplateId id, List> templates, TemplateVersion minVersion, IPendingPromise promise) - { - BulkRegisterTemplateCallback register = DiscordPool.Internal.Get>(); - register.Init(library, id, templates, minVersion, promise); - register.Run(); - } + public static void Start(BaseTemplateLibrary library, TemplateId id, List> templates, TemplateVersion minVersion, IPendingPromise promise) + { + BulkRegisterTemplateCallback register = DiscordPool.Internal.Get>(); + register.Init(library, id, templates, minVersion, promise); + register.Run(); + } - private void Init(BaseTemplateLibrary library, TemplateId id, List> templates, TemplateVersion minVersion, IPendingPromise promise) - { - _library = library; - _id = id; - _templates = templates; - _minVersion = minVersion; - _promise = promise; - } + private void Init(BaseTemplateLibrary library, TemplateId id, List> templates, TemplateVersion minVersion, IPendingPromise promise) + { + _library = library; + _id = id; + _templates = templates; + _minVersion = minVersion; + _promise = promise; + } - protected override ValueTask HandleCallback() - { - _library.HandleBulkRegisterTemplate(_id, _templates, _minVersion, _promise); - return new ValueTask(); - } + protected override ValueTask HandleCallback() + { + _library.HandleBulkRegisterTemplate(_id, _templates, _minVersion, _promise); + return new ValueTask(); + } - protected override string GetExceptionMessage() - { - return $"Template ID: {_id.ToString()} Type: {_library.GetType().GetRealTypeName()}"; - } + protected override string GetExceptionMessage() + { + return $"Template ID: {_id.ToString()} Type: {_library.GetType().GetRealTypeName()}"; + } - protected override void EnterPool() - { - _library = null; - _id = default(TemplateId); - _templates = null; - _minVersion = default(TemplateVersion); - _promise = null; - } + protected override void EnterPool() + { + _library = null; + _id = default; + _templates = null; + _minVersion = default; + _promise = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Templates/BulkToEntityCallback.cs b/Oxide.Ext.Discord/Callbacks/Templates/BulkToEntityCallback.cs index 33c4465f5..6eb0b4ea5 100644 --- a/Oxide.Ext.Discord/Callbacks/Templates/BulkToEntityCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Templates/BulkToEntityCallback.cs @@ -6,64 +6,63 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal class BulkToEntityCallback : BaseAsyncCallback + where TTemplate : class, IBulkTemplate + where TEntity : class { - internal class BulkToEntityCallback : BaseAsyncCallback - where TTemplate : class, IBulkTemplate - where TEntity : class - { - private TTemplate _template; - private List _placeholders; - private IPendingPromise> _promise; + private TTemplate _template; + private List _placeholders; + private IPendingPromise> _promise; - public static void Start(TTemplate template, List data, IPendingPromise> promise) - { - BulkToEntityCallback callback = DiscordPool.Internal.Get>(); - callback.Init(template, data, promise); - callback.Run(); - } + public static void Start(TTemplate template, List data, IPendingPromise> promise) + { + BulkToEntityCallback callback = DiscordPool.Internal.Get>(); + callback.Init(template, data, promise); + callback.Run(); + } - private void Init(TTemplate template, List data, IPendingPromise> promise) - { - _template = template; - _placeholders = data; - _promise = promise; - } + private void Init(TTemplate template, List data, IPendingPromise> promise) + { + _template = template; + _placeholders = data; + _promise = promise; + } - protected override ValueTask HandleCallback() + protected override ValueTask HandleCallback() + { + try { - try + List results = new(_placeholders.Count); + for (int index = 0; index < _placeholders.Count; index++) { - List results = new List(_placeholders.Count); - for (int index = 0; index < _placeholders.Count; index++) + TEntity field = _template.ToEntity(_placeholders[index]); + if (field != null) { - TEntity field = _template.ToEntity(_placeholders[index]); - if (field != null) - { - results.Add(field); - } + results.Add(field); } - _promise.Resolve(results); } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"{nameof(BulkToEntityCallback)}.{nameof(HandleCallback)} An error occured processing placeholders.", ex); - _promise.Reject(ex); - } - - return new ValueTask(); + _promise.Resolve(results); } - - protected override string GetExceptionMessage() + catch (Exception ex) { - return $"Template: {_template.GetType().GetRealTypeName()} Placeholders: {_placeholders?.Count} Promise: {_promise?.Id}"; + DiscordExtension.GlobalLogger.Exception($"{nameof(BulkToEntityCallback)}.{nameof(HandleCallback)} An error occured processing placeholders.", ex); + _promise.Reject(ex); } - protected override void EnterPool() - { - _template = null; - _placeholders = null; - _promise = null; - } + return new ValueTask(); + } + + protected override string GetExceptionMessage() + { + return $"Template: {_template.GetType().GetRealTypeName()} Placeholders: {_placeholders?.Count} Promise: {_promise?.Id}"; + } + + protected override void EnterPool() + { + _template = null; + _placeholders = null; + _promise = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Templates/Commands/ApplyCommandLocalizationsCallback.cs b/Oxide.Ext.Discord/Callbacks/Templates/Commands/ApplyCommandLocalizationsCallback.cs index 629d0147b..4a709d3bc 100644 --- a/Oxide.Ext.Discord/Callbacks/Templates/Commands/ApplyCommandLocalizationsCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Templates/Commands/ApplyCommandLocalizationsCallback.cs @@ -4,45 +4,44 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal class ApplyCommandLocalizationsCallback : BaseAsyncCallback { - internal class ApplyCommandLocalizationsCallback : BaseAsyncCallback - { - private readonly DiscordCommandLocalizations _localizations = DiscordExtension.DiscordCommandLocalizations; - private TemplateId _id; - private CommandCreate _create; - private IPendingPromise _promise; + private readonly DiscordCommandLocalizations _localizations = DiscordExtension.DiscordCommandLocalizations; + private TemplateId _id; + private CommandCreate _create; + private IPendingPromise _promise; - public static void Start(TemplateId id, CommandCreate create, IPendingPromise promise) - { - ApplyCommandLocalizationsCallback load = DiscordPool.Internal.Get(); - load.Init(id, create, promise); - load.Run(); - } + public static void Start(TemplateId id, CommandCreate create, IPendingPromise promise) + { + ApplyCommandLocalizationsCallback load = DiscordPool.Internal.Get(); + load.Init(id, create, promise); + load.Run(); + } - private void Init(TemplateId id, CommandCreate create, IPendingPromise promise) - { - _id = id; - _create = create; - _promise = promise; - } + private void Init(TemplateId id, CommandCreate create, IPendingPromise promise) + { + _id = id; + _create = create; + _promise = promise; + } - protected override ValueTask HandleCallback() - { - _localizations.HandleApplyCommandLocalizationsAsync(_id, _create, _promise); - return new ValueTask(); - } + protected override ValueTask HandleCallback() + { + _localizations.HandleApplyCommandLocalizationsAsync(_id, _create, _promise); + return new ValueTask(); + } - protected override string GetExceptionMessage() - { - return $"Plugin: {_id.PluginId.FullName()} Name: {_id.TemplateName} Language: {_id.Language}"; - } + protected override string GetExceptionMessage() + { + return $"Plugin: {_id.PluginId.FullName()} Name: {_id.TemplateName} Language: {_id.Language}"; + } - protected override void EnterPool() - { - _id = default(TemplateId); - _create = null; - _promise = null; - } + protected override void EnterPool() + { + _id = default; + _create = null; + _promise = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Templates/RegisterMessageTemplateCallback.cs b/Oxide.Ext.Discord/Callbacks/Templates/RegisterMessageTemplateCallback.cs index af708fb80..d58098c95 100644 --- a/Oxide.Ext.Discord/Callbacks/Templates/RegisterMessageTemplateCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Templates/RegisterMessageTemplateCallback.cs @@ -3,52 +3,51 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal class RegisterTemplateCallback : BaseAsyncCallback where TTemplate : class { - internal class RegisterTemplateCallback : BaseAsyncCallback where TTemplate : class - { - private BaseTemplateLibrary _library; - private TemplateId _id; - private TTemplate _template; - private TemplateVersion _version; - private TemplateVersion _minVersion; - private IPendingPromise _promise; + private BaseTemplateLibrary _library; + private TemplateId _id; + private TTemplate _template; + private TemplateVersion _version; + private TemplateVersion _minVersion; + private IPendingPromise _promise; - public static void Start(BaseTemplateLibrary library, TemplateId id, TTemplate template, TemplateVersion version, TemplateVersion minVersion, IPendingPromise promise) - { - RegisterTemplateCallback register = DiscordPool.Internal.Get>(); - register.Init(library, id, template, version, minVersion, promise); - register.Run(); - } + public static void Start(BaseTemplateLibrary library, TemplateId id, TTemplate template, TemplateVersion version, TemplateVersion minVersion, IPendingPromise promise) + { + RegisterTemplateCallback register = DiscordPool.Internal.Get>(); + register.Init(library, id, template, version, minVersion, promise); + register.Run(); + } - private void Init(BaseTemplateLibrary library, TemplateId id, TTemplate template, TemplateVersion version, TemplateVersion minVersion, IPendingPromise promise) - { - _library = library; - _id = id; - _template = template; - _minVersion = minVersion; - _version = version; - _promise = promise; - } + private void Init(BaseTemplateLibrary library, TemplateId id, TTemplate template, TemplateVersion version, TemplateVersion minVersion, IPendingPromise promise) + { + _library = library; + _id = id; + _template = template; + _minVersion = minVersion; + _version = version; + _promise = promise; + } - protected override ValueTask HandleCallback() - { - _library.HandleRegisterTemplate(_id, _template, _version, _minVersion, _promise); - return new ValueTask(); - } + protected override ValueTask HandleCallback() + { + _library.HandleRegisterTemplate(_id, _template, _version, _minVersion, _promise); + return new ValueTask(); + } - protected override string GetExceptionMessage() - { - return $"Template ID: {_id.ToString()} Type: {_library.GetType().GetRealTypeName()}"; - } + protected override string GetExceptionMessage() + { + return $"Template ID: {_id.ToString()} Type: {_library.GetType().GetRealTypeName()}"; + } - protected override void EnterPool() - { - _library = null; - _id = default(TemplateId); - _template = null; - _minVersion = default(TemplateVersion); - _promise = null; - } + protected override void EnterPool() + { + _library = null; + _id = default; + _template = null; + _minVersion = default; + _promise = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Callbacks/Websockets/WebsocketReconnectCallback.cs b/Oxide.Ext.Discord/Callbacks/Websockets/WebsocketReconnectCallback.cs index 52b1244ac..e6f915251 100644 --- a/Oxide.Ext.Discord/Callbacks/Websockets/WebsocketReconnectCallback.cs +++ b/Oxide.Ext.Discord/Callbacks/Websockets/WebsocketReconnectCallback.cs @@ -2,37 +2,36 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.WebSockets; -namespace Oxide.Ext.Discord.Callbacks +namespace Oxide.Ext.Discord.Callbacks; + +internal class WebsocketReconnectCallback : BaseAsyncCallback { - internal class WebsocketReconnectCallback : BaseAsyncCallback - { - private WebSocketReconnectHandler _reconnect; + private WebSocketReconnectHandler _reconnect; - public static void Start(WebSocketReconnectHandler reconnect) - { - WebsocketReconnectCallback callback = DiscordPool.Internal.Get(); - callback.Init(reconnect); - callback.Run(); - } + public static void Start(WebSocketReconnectHandler reconnect) + { + WebsocketReconnectCallback callback = DiscordPool.Internal.Get(); + callback.Init(reconnect); + callback.Run(); + } - private void Init(WebSocketReconnectHandler reconnect) - { - _reconnect = reconnect; - } + private void Init(WebSocketReconnectHandler reconnect) + { + _reconnect = reconnect; + } - protected override ValueTask HandleCallback() - { - return _reconnect.StartReconnect(); - } + protected override ValueTask HandleCallback() + { + return _reconnect.StartReconnect(); + } - protected override string GetExceptionMessage() - { - return $"Websocket: {_reconnect.WebSocket.Handler.WebsocketId}"; - } + protected override string GetExceptionMessage() + { + return $"Websocket: {_reconnect.WebSocket.Handler.WebsocketId}"; + } - protected override void EnterPool() - { - _reconnect = null; - } + protected override void EnterPool() + { + _reconnect = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Clients/BaseClient.cs b/Oxide.Ext.Discord/Clients/BaseClient.cs new file mode 100644 index 000000000..aa02b16e3 --- /dev/null +++ b/Oxide.Ext.Discord/Clients/BaseClient.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Newtonsoft.Json; +using Oxide.Ext.Discord.Interfaces; +using Oxide.Ext.Discord.Logging; +using Oxide.Ext.Discord.Rest; +using Oxide.Ext.Discord.Types; + +namespace Oxide.Ext.Discord.Clients; + +/// +/// BaseClient that can connect to discord +/// +public abstract class BaseClient +{ + /// + /// Rest handler for all discord API calls + /// + public RestHandler Rest { get; protected set; } + + /// + /// If the connection is initialized and not disconnected + /// + public bool Initialized { get; protected set; } + + internal readonly ILogger Logger; + + /// + /// List of all clients using this client + /// + protected readonly List _clients = []; + + /// + /// List of all clients that are using this bot client + /// + public readonly IReadOnlyList Clients; + + /// + /// Constructor + /// + protected BaseClient() + { + Logger = DiscordLoggerFactory.Instance.CreateExtensionLogger(); + Clients = new ReadOnlyCollection(_clients); + Initialized = true; + } + + internal abstract void HandleConnect(); + internal abstract void HandleShutdown(); + + internal virtual void HandleAlreadyConnected(DiscordClient client) {} + + /// + /// Returns the list of plugins for this bot + /// + /// + public string GetClientPluginList() + { + ValueStringBuilder sb = new(); + for (int index = 0; index < _clients.Count; index++) + { + DiscordClient client = _clients[index]; + if (index != 0) + { + sb.Append(","); + } + + sb.Append('['); + sb.Append(client.PluginName); + sb.Append(']'); + } + + return sb.ToString(); + } + + /// + /// Add a to this bot / webhook client + /// + /// Client to add + /// True if this is the initial setup of the client; false otherwise + /// Thrown if already has been added to this bot / webhook client + public virtual void AddClient(DiscordClient client) + { + _clients.Add(client); + + Logger.Debug($"{nameof(BaseClient)}.{nameof(AddClient)} Add client for plugin {{0}}", client.Plugin.Title); + + if (_clients.Count == 1) + { + Logger.Debug($"{nameof(BaseClient)}.{nameof(AddClient)} Clients.Count == 1 connecting"); + HandleConnect(); + return; + } + + HandleAlreadyConnected(client); + } + + /// + /// Removes the from this bot / webhook client + /// + /// Client to remove + /// returns true if the client is shutting down; false otherwise + public virtual bool RemoveClient(DiscordClient client) + { + Logger.Debug($"{nameof(BaseClient)}.{nameof(RemoveClient)} Removing Client {{0}}", client.PluginName); + _clients.Remove(client); + Rest.OnClientClosed(client); + + if (_clients.Count == 0) + { + HandleShutdown(); + return true; + } + + return false; + } + + internal void UpdateLogLevel(DiscordLogLevel level) + { + Logger.UpdateLogLevel(level); + Logger.Debug($"{nameof(BaseClient)}.{nameof(UpdateLogLevel)} Updating log level from: {{0}} to: {{1}}", Logger.LogLevel, level); + } + + internal void ShutdownRest() + { + try + { + Rest?.Shutdown(); + } + catch (Exception ex) + { + Logger.Exception($"{nameof(WebhookClient)}.{nameof(ShutdownRest)} An error occured shutting down the bot rest client.", ex); + } + finally + { + Rest = null; + } + } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Clients/BotClient.cs b/Oxide.Ext.Discord/Clients/BotClient.cs index e6e3371e7..351e28caa 100644 --- a/Oxide.Ext.Discord/Clients/BotClient.cs +++ b/Oxide.Ext.Discord/Clients/BotClient.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Text; using Newtonsoft.Json; using Oxide.Core.Plugins; using Oxide.Ext.Discord.Connections; @@ -12,7 +9,6 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Factory; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Plugins; using Oxide.Ext.Discord.Rest; @@ -20,539 +16,458 @@ using Oxide.Ext.Discord.WebSockets; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Clients +namespace Oxide.Ext.Discord.Clients; + +/// +/// Represents a bot connected to discord +/// +public class BotClient : BaseClient, IDebugLoggable { /// - /// Represents a bot that is connected to discord + /// All the servers that this bot is in /// - public class BotClient : IDebugLoggable - { - /// - /// All the servers that this bot is in - /// - public readonly Hash Servers = new Hash(); - - /// - /// All the direct messages that we have seen by channel Id - /// - public readonly Hash DirectMessagesByChannelId = new Hash(); - - /// - /// All the direct messages that we have seen by User ID - /// - public readonly Hash DirectMessagesByUserId = new Hash(); - - /// - /// If the connection is initialized and not disconnected - /// - public bool Initialized { get; private set; } - - /// - /// Application reference for this bot - /// - public DiscordApplication Application { get; private set; } - - /// - /// Bot User - /// - public DiscordUser BotUser { get; private set; } - - /// - /// Rest handler for all discord API calls - /// - public RestHandler Rest { get; private set; } + public readonly Hash Servers = new(); + + /// + /// All the direct messages that we have seen by channel ID + /// + public readonly Hash DirectMessagesByChannelId = new(); + + /// + /// All the direct messages that we have seen by User ID + /// + public readonly Hash DirectMessagesByUserId = new(); + + /// + /// Application reference for this bot + /// + public DiscordApplication Application { get; private set; } + + /// + /// Bot User + /// + public DiscordUser BotUser { get; private set; } - /// - /// Returns if the bot has fully loaded. - /// All guilds are loaded and if is specified all guild members have been loaded - /// - public bool IsFullyLoaded { get; private set; } + /// + /// Returns if the bot has fully loaded. + /// All guilds are loaded and if is specified all guild members have been loaded + /// + public bool IsFullyLoaded { get; private set; } - /// - /// Returns if ReadyData is set - /// - public bool IsReady => _readyData != null; + /// + /// Returns if ReadyData is set + /// + public bool IsReady => _readyData != null; + + internal readonly BotConnection Connection; + internal DiscordWebSocket WebSocket; + internal readonly DiscordHook Hooks; + internal readonly JsonSerializerSettings JsonSettings; + internal readonly JsonSerializer JsonSerializer; + + private GatewayReadyEvent _readyData; + + /// + /// Connection settings to use for the bot + /// + /// + public BotClient(BotConnection connection) + { + Connection = new BotConnection(connection); + Rest = new RestHandler(this, Logger); + WebSocket = new DiscordWebSocket(this, Logger); + Hooks = new DiscordHook(Logger); - internal readonly DiscordHook Hooks; - internal readonly ILogger Logger; - internal readonly BotConnection Connection; - internal readonly JsonSerializerSettings JsonSettings; - internal readonly JsonSerializer JsonSerializer; - internal DiscordWebSocket WebSocket; - - private readonly List _clients = new List(); - - /// - /// List of all clients that are using this bot client - /// - public readonly IReadOnlyList Clients; - - private GatewayReadyEvent _readyData; - - /// - /// Connection settings to use for the bot - /// - /// - public BotClient(BotConnection connection) + JsonSettings = new JsonSerializerSettings { - Connection = new BotConnection(connection); - Logger = DiscordLoggerFactory.Instance.CreateExtensionLogger(); + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }; - JsonSettings = new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore, - Formatting = Formatting.None - }; - - JsonSerializer = JsonSerializer.Create(JsonSettings); + JsonSerializer = JsonSerializer.Create(JsonSettings); + Initialized = true; + } - Initialized = true; - - Hooks = new DiscordHook(Logger); - Rest = new RestHandler(this, Logger); - WebSocket = new DiscordWebSocket(this, Logger); - - Clients = new ReadOnlyCollection(_clients); + /// + /// Connects the websocket to discord. Should only be called if the websocket is disconnected + /// + internal override void HandleConnect() + { + if (Initialized) + { + Logger.Debug($"{nameof(BotClient)}.{nameof(HandleConnect)} Connecting to websocket"); + WebSocket.Connect(); } + } - /// - /// Connects the websocket to discord. Should only be called if the websocket is disconnected - /// - public void ConnectWebSocket() + /// + /// Close the websocket with discord + /// + /// Should we attempt to reconnect to discord after closing + /// Should we attempt to resume the previous session + public void DisconnectWebsocket(bool reconnect = false, bool resume = false) + { + if (Initialized) { - if (Initialized) - { - Logger.Debug($"{nameof(BotClient)}.{nameof(ConnectWebSocket)} Connecting to websocket"); - WebSocket.Connect(); - } + WebSocket.Disconnect(reconnect, resume); } + } - /// - /// Close the websocket with discord - /// - /// Should we attempt to reconnect to discord after closing - /// Should we attempt to resume the previous session - public void DisconnectWebsocket(bool reconnect = false, bool resume = false) + internal void ResetWebSocket() + { + try { - if (Initialized) - { - WebSocket.Disconnect(reconnect, resume); - } + WebSocket?.Shutdown(); } - - internal void ResetWebSocket() + finally { - try - { - WebSocket?.Shutdown(); - } - finally - { - WebSocket = new DiscordWebSocket(this, Logger); - WebSocket.Connect(); - } + WebSocket = new DiscordWebSocket(this, Logger); + WebSocket.Connect(); } + } - internal void ResetRestApi() + internal void ResetRestApi() + { + try { - try - { - Rest?.Shutdown(); - } - finally - { - Rest = new RestHandler(this, Logger); - } + Rest?.Shutdown(); } - - /// - /// Called when bot client is no longer used by any client and can be shutdown. - /// - internal void ShutdownBot() + finally { - Logger.Debug($"{nameof(BotClient)}.{nameof(ShutdownBot)} Shutting down the bot"); - Initialized = false; - BotClientFactory.Instance.RemoveBot(this); + Rest = new RestHandler(this, Logger); + } + } - try - { - WebSocket?.Shutdown(); - } - catch (Exception ex) - { - Logger.Exception($"{nameof(BotClient)}.{nameof(ShutdownBot)} An error occured shutting down the bot websocket.", ex); - } - finally - { - WebSocket = null; - } + /// + /// Called when the bot client is no longer used by any client and can be shutdown. + /// + internal override void HandleShutdown() + { + Logger.Debug($"{nameof(BotClient)}.{nameof(HandleShutdown)} Shutting down the bot"); + BotClientFactory.Instance.RemoveBot(this); - try - { - Rest?.Shutdown(); - } - catch (Exception ex) - { - Logger.Exception($"{nameof(BotClient)}.{nameof(ShutdownBot)} An error occured shutting down the bot rest client.", ex); - } - finally - { - Rest = null; - } - - _readyData = null; + try + { + WebSocket?.Shutdown(); } - - /// - /// Add a client to this bot client - /// - /// Client to add to the bot - /// Setup data for the plugin - public void AddClient(DiscordClient client, PluginSetup setup) + catch (Exception ex) + { + Logger.Exception($"{nameof(BotClient)}.{nameof(HandleShutdown)} An error occured shutting down the bot websocket.", ex); + } + finally { - TokenMismatchException.ThrowIfMismatchedToken(client, Connection); + WebSocket = null; + } - if (_clients.Contains(client)) - { - throw new Exception("Duplicate Client Exception"); - } - - _clients.Add(client); - Hooks.AddPlugin(client, setup); + ShutdownRest(); + + _readyData = null; + Initialized = false; + } + + /// + public override void AddClient(DiscordClient client) + { + TokenMismatchException.ThrowIfMismatchedToken(client, Connection); - Logger.Debug($"{nameof(BotClient)}.{nameof(AddClient)} Add client for plugin {{0}}", client.Plugin.Title); - - if (_clients.Count == 1) - { - Logger.Debug($"{nameof(BotClient)}.{nameof(AddClient)} Clients.Count == 1 connecting bot"); - ConnectWebSocket(); - return; - } + if (_clients.Contains(client)) + { + throw new Exception("This client is already in the list of clients"); + } - GatewayIntents intents = Connection.Intents | client.Connection.Intents; + base.AddClient(client); + Hooks.AddPlugin(client); + } + + internal override void HandleAlreadyConnected(DiscordClient client) + { + GatewayIntents intents = Connection.Intents | client.Connection.Intents; - //Our intents have changed. Disconnect websocket and reconnect with new intents. - if (intents != Connection.Intents) + //Our intents have changed. Disconnect websocket and reconnect with new intents. + if (intents != Connection.Intents) + { + Connection.Intents = intents; + if (WebSocket.Intents != Connection.Intents && WebSocket.IsConnected()) { - Connection.Intents = intents; - if (WebSocket.Intents != Connection.Intents && WebSocket.IsConnected()) - { - Logger.Debug("New intents have been requested for the a connected bot. Reconnecting with updated intents."); - DisconnectWebsocket(true); - } + Logger.Debug("New intents have been requested for the a connected bot. Reconnecting with updated intents."); + DisconnectWebsocket(true); } + } - if (_readyData != null) - { - _readyData.Guilds = Servers; - DiscordHook.CallPluginHook(client.Plugin, DiscordExtHooks.OnDiscordGatewayReady, _readyData); + if (_readyData != null) + { + _readyData.Guilds = Servers; + DiscordHook.CallPluginHook(client.Plugin, DiscordExtHooks.OnDiscordGatewayReady, _readyData); - foreach (DiscordGuild guild in Servers.Values) + foreach (DiscordGuild guild in Servers.Values) + { + if (guild.IsAvailable) { - if (guild.IsAvailable) - { - DiscordHook.CallPluginHook(client.Plugin, DiscordExtHooks.OnDiscordGuildCreated, guild); - } - - if (guild.HasLoadedAllMembers) - { - DiscordHook.CallPluginHook(client.Plugin, DiscordExtHooks.OnDiscordGuildMembersLoaded, guild); - } + DiscordHook.CallPluginHook(client.Plugin, DiscordExtHooks.OnDiscordGuildCreated, guild); } - if (IsFullyLoaded) + if (guild.HasLoadedAllMembers) { - DiscordHook.CallPluginHook(client.Plugin, DiscordExtHooks.OnDiscordBotFullyLoaded); + DiscordHook.CallPluginHook(client.Plugin, DiscordExtHooks.OnDiscordGuildMembersLoaded, guild); } } - } - /// - /// Remove a client from the bot client - /// If not clients are left bot will shutdown - /// - /// Client to remove from bot client - public void RemoveClient(DiscordClient client) - { - Logger.Debug($"{nameof(BotClient)}.{nameof(RemoveClient)} Removing Client {{0}}", client.PluginName); - _clients.Remove(client); - Rest.OnClientClosed(client); - Hooks.RemovePlugin(client.Plugin); - if (_clients.Count == 0) - { - ShutdownBot(); - Logger.Debug($"{nameof(BotClient)}.{nameof(RemoveClient)} Bot count 0 shutting down bot"); - return; - } - - GatewayIntents intents = GatewayIntents.None; - for (int index = 0; index < _clients.Count; index++) + if (IsFullyLoaded) { - DiscordClient exitingClients = _clients[index]; - intents |= exitingClients.Connection.Intents; + DiscordHook.CallPluginHook(client.Plugin, DiscordExtHooks.OnDiscordBotFullyLoaded); } - - //Update Intents so the next reconnect we supply the correct GatewayIntents for connected plugins - Connection.Intents = intents; } + } - /// - /// Returns the list of plugins for this bot - /// - /// - public string GetClientPluginList() + /// + public override bool RemoveClient(DiscordClient client) + { + if (base.RemoveClient(client)) { - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); - for (int index = 0; index < _clients.Count; index++) - { - DiscordClient client = _clients[index]; - if (index != 0) - { - sb.Append(","); - } - - sb.Append('['); - sb.Append(client.PluginName); - sb.Append(']'); - } - - return DiscordPool.Internal.ToStringAndFree(sb); + return true; } - - internal void UpdateLogLevel(DiscordLogLevel level) + + Hooks.RemovePlugin(client.Plugin); + + GatewayIntents intents = GatewayIntents.None; + for (int index = 0; index < _clients.Count; index++) { - Logger.UpdateLogLevel(level); - Logger.Debug($"{nameof(BotClient)}.{nameof(UpdateLogLevel)} Updating log level from: {{0}} to: {{1}}", Logger.LogLevel, level); + DiscordClient exitingClients = _clients[index]; + intents |= exitingClients.Connection.Intents; } - internal void OnClientReady(GatewayReadyEvent ready) - { - Application = ready.Application; - BotUser = ready.User; + //Update Intents so the next reconnect we supply the correct GatewayIntents for connected plugins + Connection.Intents = intents; + return false; + } + + internal void OnClientReady(GatewayReadyEvent ready) + { + Application = ready.Application; + BotUser = ready.User; - bool isFirst = _readyData == null; - if (isFirst) + bool isFirst = _readyData == null; + if (isFirst) + { + Hooks.CallHook(DiscordExtHooks.OnDiscordGatewayReady, ready); + if (DiscordUserData.Instance.TryGetBotData(ready.User.Id, out BotData botData)) { - Hooks.CallHook(DiscordExtHooks.OnDiscordGatewayReady, ready); - if (DiscordUserData.Instance.TryGetBotData(ready.User.Id, out BotData botData)) + foreach (UserData userData in botData.Users.Values) { - foreach (UserData userData in botData.Users.Values) - { - DiscordChannel channel = userData.CreateDmChannel(); - DirectMessagesByChannelId[channel.Id] = channel; - DirectMessagesByUserId[userData.UserId] = channel; - channel.UserData = userData; - userData.ClearBlockIfExpired(); - } + DiscordChannel channel = userData.CreateDmChannel(); + DirectMessagesByChannelId[channel.Id] = channel; + DirectMessagesByUserId[userData.UserId] = channel; + channel.UserData = userData; + userData.ClearBlockIfExpired(); } } - else - { - Hooks.CallHook(DiscordExtHooks.OnDiscordGatewayReconnected); - } + } + else + { + Hooks.CallHook(DiscordExtHooks.OnDiscordGatewayReconnected); + } - _readyData = ready; - _readyData.Guilds = Servers; + _readyData = ready; + _readyData.Guilds = Servers; - if (isFirst) - { - DiscordExtensionCore.Instance.ApplyApplicationCommands(this); - } + if (isFirst) + { + DiscordExtensionCore.Instance.ApplyApplicationCommands(this); + } - if (Connection.Intents != WebSocket.Intents) - { - DisconnectWebsocket(true); - } + if (Connection.Intents != WebSocket.Intents) + { + DisconnectWebsocket(true); } + } - internal void OnBotFullyLoaded() + internal void OnBotFullyLoaded() + { + if (!IsFullyLoaded) { - if (!IsFullyLoaded) - { - IsFullyLoaded = true; - Hooks.CallHook(DiscordExtHooks.OnDiscordBotFullyLoaded); - } + IsFullyLoaded = true; + Hooks.CallHook(DiscordExtHooks.OnDiscordBotFullyLoaded); } + } - /// - /// Returns the first client connected to this bot. - /// Only use for Gateway API call - /// - /// - internal DiscordClient GetFirstClient() + /// + /// Returns the first client connected to this bot. + /// Only use for Gateway API call + /// + /// + internal DiscordClient GetFirstClient() + { + return _clients.Count != 0 ? _clients[0] : null; + } + + /// + /// Sends a websocket command + /// + /// Client sending the command + /// OP Code for the command + /// Command Payload + public void SendWebSocketCommand(DiscordClient client, GatewayCommandCode opCode, object data) + { + if (Initialized) { - return _clients.Count != 0 ? _clients[0] : null; + WebSocket.Send(client, opCode, data); } + } - /// - /// Sends a websocket command - /// - /// Client sending the command - /// OP Code for the command - /// Command Payload - public void SendWebSocketCommand(DiscordClient client, GatewayCommandCode opCode, object data) + #region Entity Helpers + /// + /// Returns a guild for the specific ID + /// + /// ID of the guild + /// Guild with the specified ID + public DiscordGuild GetGuild(Snowflake? guildId) + { + if (guildId.HasValue && guildId.Value.IsValid()) { - if (Initialized) - { - WebSocket.Send(client, opCode, data); - } + return Servers[guildId.Value]; } - #region Entity Helpers - /// - /// Returns a guild for the specific ID - /// - /// ID of the guild - /// Guild with the specified ID - public DiscordGuild GetGuild(Snowflake? guildId) + return null; + } + + /// + /// Returns the channel for the given channel ID. + /// If guild ID is null, it will search for a direct message channel + /// If guild ID is not null, it will search for a guild channel + /// + /// + /// + /// + public DiscordChannel GetChannel(Snowflake channelId, Snowflake? guildId) + { + if (guildId.HasValue) { - if (guildId.HasValue && guildId.Value.IsValid()) + DiscordGuild guild = GetGuild(guildId); + if (guild != null) { - return Servers[guildId.Value]; + return guild.Channels[channelId] ?? guild.Threads[channelId]; } return null; } - /// - /// Returns the channel for the given channel ID. - /// If guild ID is null it will search for a direct message channel - /// If guild ID is not null it will search for a guild channel - /// - /// - /// - /// - public DiscordChannel GetChannel(Snowflake channelId, Snowflake? guildId) - { - if (guildId.HasValue) - { - DiscordGuild guild = GetGuild(guildId); - if (guild != null) - { - return guild.Channels[channelId] ?? guild.Threads[channelId]; - } + return DirectMessagesByChannelId[channelId]; + } - return null; - } + /// + /// Adds a guild to the list of servers a bot is in + /// + /// + public void AddGuild(DiscordGuild guild) + { + Servers[guild.Id] = guild; + } - return DirectMessagesByChannelId[channelId]; + /// + /// Adds a guild if it does not exist or updates the guild with + /// + /// + public void AddGuildOrUpdate(DiscordGuild guild) + { + DiscordGuild existing = Servers[guild.Id]; + if (existing != null) + { + Logger.Verbose($"{nameof(BotClient)}.{nameof(AddGuildOrUpdate)} Updating Existing Guild {{0}}", guild.Id); + existing.Edit(guild); } - - /// - /// Adds a guild to the list of servers a bot is in - /// - /// - public void AddGuild(DiscordGuild guild) + else { + Logger.Verbose($"{nameof(BotClient)}.{nameof(AddGuildOrUpdate)} Adding new Guild {{0}}", guild.Id); Servers[guild.Id] = guild; } + } - /// - /// Adds a guild if it does not exist or updates the guild with - /// - /// - public void AddGuildOrUpdate(DiscordGuild guild) - { - DiscordGuild existing = Servers[guild.Id]; - if (existing != null) - { - Logger.Verbose($"{nameof(BotClient)}.{nameof(AddGuildOrUpdate)} Updating Existing Guild {{0}}", guild.Id); - existing.Edit(guild); - } - else - { - Logger.Verbose($"{nameof(BotClient)}.{nameof(AddGuildOrUpdate)} Adding new Guild {{0}}", guild.Id); - Servers[guild.Id] = guild; - } - } + /// + /// Removes guild from the list of servers a bot is in + /// + /// Guild to remove from bot + internal void RemoveGuild(Snowflake guildId) + { + Servers.Remove(guildId); + } - /// - /// Removes guild from the list of servers a bot is in - /// - /// Guild to remove from bot - internal void RemoveGuild(Snowflake guildId) + /// + /// Adds a Direct Message Channel to the bot cache + /// + /// Channel to be added + public void AddDirectChannel(DiscordChannel channel) + { + if (channel.Type != ChannelType.Dm) { - Servers.Remove(guildId); + Logger.Warning($"{nameof(BotClient)}.{nameof(AddDirectChannel)} Tried to add a non DM channel"); + return; } - - /// - /// Adds a Direct Message Channel to the bot cache - /// - /// Channel to be added - public void AddDirectChannel(DiscordChannel channel) - { - if (channel.Type != ChannelType.Dm) - { - Logger.Warning($"{nameof(BotClient)}.{nameof(AddDirectChannel)} Tried to add a non DM channel"); - return; - } - Logger.Verbose($"{nameof(BotClient)}.{nameof(AddDirectChannel)} Adding New Channel {{0}}", channel.Id); - DirectMessagesByChannelId[channel.Id] = channel; + Logger.Verbose($"{nameof(BotClient)}.{nameof(AddDirectChannel)} Adding New Channel {{0}}", channel.Id); + DirectMessagesByChannelId[channel.Id] = channel; - BotData data = DiscordUserData.Instance.GetBotData(BotUser.Id); + BotData data = DiscordUserData.Instance.GetBotData(BotUser.Id); - foreach (DiscordUser recipient in channel.Recipients.Values) + foreach (DiscordUser recipient in channel.Recipients.Values) + { + if (!recipient.Bot.HasValue || !recipient.Bot.Value) { - if (!recipient.Bot.HasValue || !recipient.Bot.Value) - { - DirectMessagesByUserId[recipient.Id] = channel; + DirectMessagesByUserId[recipient.Id] = channel; - UserData userData = data.GetUserData(recipient.Id); - channel.UserData = userData; - if (userData.DmChannelId != channel.Id) - { - userData.DmChannelId = channel.Id; - DiscordUserData.Instance.OnDataChanged(); - } + UserData userData = data.GetUserData(recipient.Id); + channel.UserData = userData; + if (userData.DmChannelId != channel.Id) + { + userData.DmChannelId = channel.Id; + DiscordUserData.Instance.OnDataChanged(); } } } + } - /// - /// Removes a direct message channel if it exists - /// - /// ID of the channel to remove - public void RemoveDirectMessageChannel(Snowflake id) + /// + /// Removes a direct message channel if it exists + /// + /// ID of the channel to remove + public void RemoveDirectMessageChannel(Snowflake id) + { + DiscordChannel existing = DirectMessagesByChannelId[id]; + if (existing != null) { - DiscordChannel existing = DirectMessagesByChannelId[id]; - if (existing != null) - { - DirectMessagesByChannelId.Remove(id); - DirectMessagesByUserId.RemoveAll(c => c.Id == id); - } + DirectMessagesByChannelId.Remove(id); + DirectMessagesByUserId.RemoveAll(c => c.Id == id); } - #endregion + } + #endregion - #region Discord Command Helpers - internal bool IsPluginRegistered(Plugin plugin) + #region Discord Command Helpers + internal bool IsPluginRegistered(Plugin plugin) + { + for (int index = 0; index < _clients.Count; index++) { - for (int index = 0; index < _clients.Count; index++) + DiscordClient client = _clients[index]; + if (client.Plugin == plugin) { - DiscordClient client = _clients[index]; - if (client.Plugin == plugin) - { - return true; - } + return true; } - - return false; } - #endregion - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendField("Client", Connection.HiddenToken); - logger.AppendField("Initialized", Initialized); - logger.AppendFieldEnum("Log Level", Logger.LogLevel); - logger.AppendFieldEnum("Intents", Connection.Intents); - logger.AppendField("Plugins", GetClientPluginList()); + return false; + } + #endregion + + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("Client", Connection.HiddenToken); + logger.AppendField("Initialized", Initialized); + logger.AppendFieldEnum("Log Level", Logger.LogLevel); + logger.AppendFieldEnum("Intents", Connection.Intents); + logger.AppendField("Plugins", GetClientPluginList()); - logger.AppendObject("Bot", BotUser); - logger.AppendObject("Application", Application); - logger.AppendObject("Websocket", WebSocket); - logger.AppendObject("REST API", Rest); - } + logger.AppendObject("Bot", BotUser); + logger.AppendObject("Application", Application); + logger.AppendObject("Websocket", WebSocket); + logger.AppendObject("REST API", Rest); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Clients/DiscordClient.cs b/Oxide.Ext.Discord/Clients/DiscordClient.cs index 9e9dde343..7162dd023 100644 --- a/Oxide.Ext.Discord/Clients/DiscordClient.cs +++ b/Oxide.Ext.Discord/Clients/DiscordClient.cs @@ -1,159 +1,229 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Newtonsoft.Json; using Oxide.Core.Plugins; using Oxide.Ext.Discord.Connections; +using Oxide.Ext.Discord.Constants; using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Factory; using Oxide.Ext.Discord.Interfaces; +using Oxide.Ext.Discord.Json; using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Clients +namespace Oxide.Ext.Discord.Clients; + +/// +/// Represents the object a plugin uses to connect to discord +/// +public class DiscordClient { /// - /// Represents the object a plugin uses to connects to discord + /// Which plugin is the owner of this client /// - public class DiscordClient - { - /// - /// Which plugin is the owner of this client - /// - public Plugin Plugin { get; private set; } - - /// - /// The ID of the plugin - /// - public readonly PluginId PluginId; + public Plugin Plugin { get; private set; } + + /// + /// The ID of the plugin + /// + public readonly PluginId PluginId; - /// - /// The full plugin name including author and version - /// - public readonly string PluginName; + /// + /// The full plugin name including author and version + /// + public readonly string PluginName; + + /// + /// The bot client that is unique to the Token used + /// + public BotClient Bot { get; private set; } + + private readonly List _webhooks = []; + + /// + /// Webhook clients for this DiscordClient + /// + public readonly IReadOnlyList Webhooks; + + public JsonSerializerSettings JsonSettings => Bot?.JsonSettings ?? DiscordJson.Settings; - /// - /// The bot client that is unique to the Token used - /// - public BotClient Bot { get; private set; } + /// + /// Settings used to connect to discord and configure the extension + /// + internal BotConnection Connection { get; private set; } + + internal ILogger Logger; + + internal PluginSetup PluginSetup { get; private set; } + + /// + /// Constructor for a discord client + /// + /// Plugin that will own this discord client + internal DiscordClient(Plugin plugin) + { + Plugin = plugin; + PluginExt.OnPluginLoaded(Plugin); + PluginId = plugin.Id(); + PluginName = plugin.FullName(); + Webhooks = new ReadOnlyCollection(_webhooks); + BaseDiscordLibrary.ProcessPluginLoaded(this); + } - /// - /// Settings used to connect to discord and configure the extension - /// - internal BotConnection Connection { get; private set; } - - internal ILogger Logger; - - /// - /// Constructor for a discord client - /// - /// Plugin that will own this discord client - internal DiscordClient(Plugin plugin) + /// + /// Starts a connection to discord with the given apiKey and intents + /// + /// API key for the connecting bot + /// Intents the bot needs to function + public void Connect(string apiKey, GatewayIntents intents) => Connect(new BotConnection(apiKey, intents)); + + /// + /// Starts a connection to discord with the given discord settings + /// + /// Discord connection settings + public void Connect(BotConnection connection) + { + Connection = connection ?? throw new ArgumentNullException(nameof(connection)); + Logger ??= DiscordLoggerFactory.Instance.CreateExtensionLogger(connection.LogLevel); + + if (string.IsNullOrEmpty(Connection.ApiToken)) { - Plugin = plugin; - PluginId = plugin.Id(); - PluginName = plugin.FullName(); - PluginExt.OnPluginLoaded(Plugin); + Logger.Error("API Token is null or empty!"); + return; } - - /// - /// Starts a connection to discord with the given apiKey and intents - /// - /// API key for the connecting bot - /// Intents the bot needs in order to function - public void Connect(string apiKey, GatewayIntents intents) => Connect(new BotConnection(apiKey, intents)); - - /// - /// Starts a connection to discord with the given discord settings - /// - /// Discord connection settings - public void Connect(BotConnection connection) + + if (!string.IsNullOrEmpty(DiscordExtension.TestVersion)) { - Connection = connection ?? throw new ArgumentNullException(nameof(connection)); - Logger = DiscordLoggerFactory.Instance.CreateExtensionLogger(connection.LogLevel); - - if (string.IsNullOrEmpty(Connection.ApiToken)) - { - Logger.Error("API Token is null or empty!"); - return; - } + Logger.Warning("Using Discord Test Version: {0}", DiscordExtension.FullExtensionVersion); + } - if (!string.IsNullOrEmpty(DiscordExtension.TestVersion)) - { - Logger.Warning("Using Discord Test Version: {0}", DiscordExtension.FullExtensionVersion); - } + Logger.Debug($"{nameof(DiscordClient)}.{nameof(Connect)} Bot connect for {{0}}", Plugin.FullName()); - Logger.Debug($"{nameof(DiscordClient)}.{nameof(Connect)} AddDiscordClient for {{0}}", Plugin.FullName()); + Connection.Initialize(this); + PluginSetup = new PluginSetup(Plugin, Logger); + BaseDiscordLibrary.ProcessBotConnection(this); + Bot = BotClientFactory.Instance.InitializeBotClient(this, Connection); + Bot.AddClient(this); + } - Connection.Initialize(this); - PluginSetup setup = new PluginSetup(Plugin, Logger); - BaseDiscordLibrary.ProcessPluginLoaded(setup, Connection); - Bot = BotClientFactory.Instance.InitializeBotClient(this); - Bot.AddClient(this, setup); + /// + /// Connect to the webhook + /// + /// Webhook URL to connect to + public WebhookClient Connect(string webhookUrl) => Connect(new WebhookConnection(webhookUrl)); + + /// + /// Connect to the webhook + /// + /// Webhook connection to connect to + public WebhookClient Connect(WebhookConnection connection) + { + Logger ??= DiscordLoggerFactory.Instance.CreateExtensionLogger(connection.LogLevel); + + if (string.IsNullOrEmpty(connection.WebhookUrl) || !connection.WebhookUrl.StartsWith("https://discord.com/api/webhooks/")) + { + Logger.Debug("Skipping Webhook connect. Webhook URL is null, empty, or invalid: {0}", connection.WebhookUrl); + return null; + } + + if (string.IsNullOrEmpty(connection.WebhookToken)) + { + Logger.Error("Failed to parse Webhook token from webhook URL: {0}", connection.WebhookUrl); + return null; + } + + if (connection.WebhookId == default) + { + Logger.Error("Failed to parse webhook ID from webhook URL: {0}", connection.WebhookUrl); + return null; + } + + if (!string.IsNullOrEmpty(DiscordExtension.TestVersion)) + { + Logger.Warning("Using Discord Test Version: {0}", DiscordExtension.FullExtensionVersion); } + + Logger.Debug($"{nameof(DiscordClient)}.{nameof(Connect)} Webhook connect for {{0}}", Plugin.FullName()); + + WebhookClient client = WebhookClientFactory.Instance.InitializeWebhookClient(this, connection); + client.AddClient(this); + _webhooks.Add(client); + return client; + } - /// - /// Disconnects this client from discord - /// - public void Disconnect() + /// + /// Disconnects this client from discord + /// + public void Disconnect() + { + Bot?.RemoveClient(this); + Bot = null; + for (int index = _webhooks.Count - 1; index >= 0; index--) { - Bot?.RemoveClient(this); - Bot = null; + WebhookClient client = _webhooks[index]; + client.RemoveClient(this); + _webhooks.RemoveAt(index); } + } + + /// + /// Returns if the client is connected to a bot / webhook and if the bot / webhook is initialized + /// + /// + public bool IsConnected() => Bot?.Initialized ?? _webhooks.Any(w => w.Initialized); - /// - /// Returns if the client is connected to a bot and if the bot is initialized - /// - /// - public bool IsConnected() => Bot?.Initialized ?? false; - - #region Websocket Commands - /// - /// Used to request guild members from discord for a specific guild - /// - /// Request for guild members - public void RequestGuildMembers(GuildMembersRequestCommand request) => Bot?.SendWebSocketCommand(this, GatewayCommandCode.RequestGuildMembers, request); - - /// - /// Used to update the voice state for the bot - /// - /// - public void UpdateVoiceState(UpdateVoiceStatusCommand voiceState) => Bot?.SendWebSocketCommand(this, GatewayCommandCode.VoiceStateUpdate, voiceState); - - /// - /// Used to update the bots status in discord - /// - /// - public void UpdateStatus(UpdatePresenceCommand presenceUpdate) => Bot?.SendWebSocketCommand(this, GatewayCommandCode.PresenceUpdate, presenceUpdate); - #endregion + #region Websocket Commands + /// + /// Used to request guild members from discord for a specific guild + /// + /// Request for guild members + public void RequestGuildMembers(GuildMembersRequestCommand request) => Bot?.SendWebSocketCommand(this, GatewayCommandCode.RequestGuildMembers, request); + + /// + /// Used to update the voice state for the bot + /// + /// + public void UpdateVoiceState(UpdateVoiceStatusCommand voiceState) => Bot?.SendWebSocketCommand(this, GatewayCommandCode.VoiceStateUpdate, voiceState); + + /// + /// Used to update the bot status in discord + /// + /// + public void UpdateStatus(UpdatePresenceCommand presenceUpdate) => Bot?.SendWebSocketCommand(this, GatewayCommandCode.PresenceUpdate, presenceUpdate); + #endregion + + internal void UpdateLogLevel() + { + Logger.UpdateLogLevel(DiscordLoggerFactory.Instance.GetLogLevel(Connection.LogLevel)); + } - internal void UpdateLogLevel() + internal void CloseClient() + { + try { - Logger.UpdateLogLevel(DiscordLoggerFactory.Instance.GetLogLevel(Connection.LogLevel)); + DiscordExtension.GlobalLogger.Debug($"{nameof(DiscordClient)}.{nameof(CloseClient)} Closing DiscordClient for plugin {{0}}", PluginName); + Disconnect(); } - - internal void CloseClient() + catch (Exception ex) { - try - { - DiscordExtension.GlobalLogger.Debug($"{nameof(DiscordClient)}.{nameof(CloseClient)} Closing DiscordClient for plugin {{0}}", PluginName); - Disconnect(); - } - catch (Exception ex) + Logger.Exception($"Failed to close the {nameof(DiscordClient)} for {{0}}", PluginName, ex); + } + finally + { + DiscordClientFactory.Instance.RemoveClient(this); + + // ReSharper disable once SuspiciousTypeConversion.Global + if (Plugin is {IsLoaded: true} and IDiscordPlugin discordPlugin) { - Logger.Exception($"Failed to close the {nameof(DiscordClient)} for {{0}}", PluginName, ex); + discordPlugin.Client = null; } - finally - { - DiscordClientFactory.Instance.RemoveClient(this); - // ReSharper disable once SuspiciousTypeConversion.Global - if (Plugin != null && Plugin.IsLoaded && Plugin is IDiscordPlugin discordPlugin) - { - discordPlugin.Client = null; - } - - Plugin = null; - } + Plugin = null; + PluginSetup = null; } } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Clients/WebhookClient.cs b/Oxide.Ext.Discord/Clients/WebhookClient.cs new file mode 100644 index 000000000..4121f6cac --- /dev/null +++ b/Oxide.Ext.Discord/Clients/WebhookClient.cs @@ -0,0 +1,75 @@ +using Oxide.Ext.Discord.Connections; +using Oxide.Ext.Discord.Entities; +using Oxide.Ext.Discord.Factory; +using Oxide.Ext.Discord.Interfaces; +using Oxide.Ext.Discord.Logging; +using Oxide.Ext.Discord.Rest; + +namespace Oxide.Ext.Discord.Clients; + +/// +/// A client that can connect to a webhook +/// +public class WebhookClient : BaseClient, IDebugLoggable +{ + /// + /// Webhook that has been connected to + /// + public DiscordWebhook Webhook { get; private set; } + + internal readonly WebhookConnection Connection; + + /// + /// Constructor + /// + /// Connection for the webhook + public WebhookClient(WebhookConnection connection) + { + Connection = connection; + Rest = RestHandler.Global; + Webhook = new DiscordWebhook + { + Id = connection.WebhookId, + Token = connection.WebhookToken, + Client = this + }; + Initialized = true; + } + + internal override void HandleConnect() + { + DiscordWebhook.GetWebhookWithToken(_clients[0], this, Connection.WebhookId, Connection.WebhookToken) + .Then(webhook => + { + Webhook = webhook; + Webhook.Client = this; + }) + .Catch(ex => Logger.Exception("An error occured connecting the webhook", ex)); + } + + /// + public override void AddClient(DiscordClient client) + { + if (!_clients.Contains(client)) + { + base.AddClient(client); + } + } + + internal override void HandleShutdown() + { + Logger.Debug($"{nameof(WebhookClient)}.{nameof(HandleShutdown)} Shutting down the webhook"); + WebhookClientFactory.Instance.RemoveWebhook(this); + Rest = null; + Initialized = false; + } + + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("Webhook ID", Connection.WebhookId); + logger.AppendField("Initialized", Initialized); + logger.AppendFieldEnum("Log Level", Logger.LogLevel); + logger.AppendField("Plugins", GetClientPluginList()); + } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Configuration/DiscordBotConfig.cs b/Oxide.Ext.Discord/Configuration/DiscordBotConfig.cs index 48d27c7dd..03bcfa9cc 100644 --- a/Oxide.Ext.Discord/Configuration/DiscordBotConfig.cs +++ b/Oxide.Ext.Discord/Configuration/DiscordBotConfig.cs @@ -1,14 +1,13 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Configuration +namespace Oxide.Ext.Discord.Configuration; + +/// +/// Represents Discord Extension Bot Config +/// +internal class DiscordBotConfig { - /// - /// Represents Discord Extension Bot Config - /// - internal class DiscordBotConfig - { - [JsonProperty("Automatically Apply Gateway Intents")] - public bool AutomaticallyApplyGatewayIntents { get; set; } - } + [JsonProperty("Automatically Apply Gateway Intents")] + public bool AutomaticallyApplyGatewayIntents { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Configuration/DiscordCommandsConfig.cs b/Oxide.Ext.Discord/Configuration/DiscordCommandsConfig.cs index 51e0fb901..1da05fdcb 100644 --- a/Oxide.Ext.Discord/Configuration/DiscordCommandsConfig.cs +++ b/Oxide.Ext.Discord/Configuration/DiscordCommandsConfig.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Configuration +namespace Oxide.Ext.Discord.Configuration; + +/// +/// Represents discord extension command configuration +/// +internal class DiscordCommandsConfig { /// - /// Represents discord extension command configuration + /// Array of command prefixes for discord commands /// - internal class DiscordCommandsConfig - { - /// - /// Array of command prefixes for discord commands - /// - [JsonProperty("Command Prefixes")] - public char[] CommandPrefixes { get; set; } - } + [JsonProperty("Command Prefixes")] + public char[] CommandPrefixes { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Configuration/DiscordConfig.cs b/Oxide.Ext.Discord/Configuration/DiscordConfig.cs index c6d35feb0..49d962a9c 100644 --- a/Oxide.Ext.Discord/Configuration/DiscordConfig.cs +++ b/Oxide.Ext.Discord/Configuration/DiscordConfig.cs @@ -1,147 +1,145 @@ using System; -using System.Collections.Generic; using System.IO; using Newtonsoft.Json; using Oxide.Core; using Oxide.Core.Configuration; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Configuration +namespace Oxide.Ext.Discord.Configuration; + +/// +/// Represents Discord Extension Config +/// +internal class DiscordConfig : ConfigFile { + internal static DiscordConfig Instance; + /// - /// Represents Discord Extension Config + /// Discord Command Options /// - internal class DiscordConfig : ConfigFile - { - internal static DiscordConfig Instance; + [JsonProperty("Commands")] + public DiscordCommandsConfig Commands { get; set; } - /// - /// Discord Command Options - /// - [JsonProperty("Commands")] - public DiscordCommandsConfig Commands { get; set; } - - /// - /// Discord Rest Options - /// - [JsonProperty("Rest")] - public DiscordRestConfig Rest { get; set; } + /// + /// Discord Rest Options + /// + [JsonProperty("Rest")] + public DiscordRestConfig Rest { get; set; } - /// - /// Discord Logging Options - /// - [JsonProperty("Logging")] - public DiscordLoggingConfig Logging { get; set; } + /// + /// Discord Logging Options + /// + [JsonProperty("Logging")] + public DiscordLoggingConfig Logging { get; set; } - /// - /// Discord Users Options - /// - [JsonProperty("Users")] - public DiscordUsersConfig Users { get; set; } + /// + /// Discord Users Options + /// + [JsonProperty("Users")] + public DiscordUsersConfig Users { get; set; } - /// - /// Discord Search Options - /// - [JsonProperty("Search")] - public DiscordSearchConfig Search { get; set; } + /// + /// Discord Search Options + /// + [JsonProperty("Search")] + public DiscordSearchConfig Search { get; set; } - /// - /// Discord Validation Options - /// - [JsonProperty("Validation")] - public DiscordValidationConfig Validation { get; set; } + /// + /// Discord Validation Options + /// + [JsonProperty("Validation")] + public DiscordValidationConfig Validation { get; set; } - /// - /// Discord Bot Options - /// - [JsonProperty("Bot")] - public DiscordBotConfig Bot { get; set; } + /// + /// Discord Bot Options + /// + [JsonProperty("Bot")] + public DiscordBotConfig Bot { get; set; } - /// - /// Discord Bot Options - /// - [JsonProperty("Ip")] - public DiscordIpConfig Ip { get; set; } + /// + /// Discord Bot Options + /// + [JsonProperty("Ip")] + public DiscordIpConfig Ip { get; set; } - /// - /// Constructor for discord config - /// - /// Filename to use - public DiscordConfig(string filename) : base(filename) + /// + /// Constructor for discord config + /// + /// Filename to use + public DiscordConfig(string filename) : base(filename) + { + if (Instance != null) { - if (Instance != null) - { - throw new Exception("Duplicate DiscordConfig Instances"); - } - - Instance = this; - ApplyDefaults(); + throw new Exception("Duplicate DiscordConfig Instances"); } + + Instance = this; + ApplyDefaults(); + } - public static void LoadConfig() + public static void LoadConfig() + { + string configPath = Path.Combine(Interface.Oxide.InstanceDirectory, "discord.config.json"); + DiscordConfig config = File.Exists(configPath) ? ConfigFile.Load(configPath) : new DiscordConfig(configPath); + config.Save(); + } + + /// + /// Load the config file and populate it. + /// + /// + public override void Load(string filename = null) + { + try { - string configPath = Path.Combine(Interface.Oxide.InstanceDirectory, "discord.config.json"); - DiscordConfig config = File.Exists(configPath) ? ConfigFile.Load(configPath) : new DiscordConfig(configPath); - config.Save(); + base.Load(filename); + ApplyDefaults(); } - - /// - /// Load the config file and populate it. - /// - /// - public override void Load(string filename = null) + catch (Exception ex) { - try - { - base.Load(filename); - ApplyDefaults(); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("Failed to load config file. Using default config.", ex); - ApplyDefaults(); - } + DiscordExtension.GlobalLogger.Exception("Failed to load config file. Using default config.", ex); + ApplyDefaults(); } + } - private void ApplyDefaults() + private void ApplyDefaults() + { + Commands = new DiscordCommandsConfig { - Commands = new DiscordCommandsConfig - { - CommandPrefixes = Commands?.CommandPrefixes ?? new[] {'/', '!'} - }; - Rest = new DiscordRestConfig - { - ApiErrorRetries = Rest?.ApiErrorRetries ?? 3, - ApiRateLimitRetries = Rest?.ApiRateLimitRetries ?? 6 - }; - Logging = new DiscordLoggingConfig - { - HideDiscordErrorCodes = Logging?.HideDiscordErrorCodes ?? new HashSet(), - ConsoleLogLevel = Logging?.ConsoleLogLevel ?? DiscordLogLevel.Info, - FileLogLevel = Logging?.FileLogLevel ?? DiscordLogLevel.Off, - FileDateTimeFormat = "HH:mm:ss.ff" - }; - Users = new DiscordUsersConfig - { - DmBlockedDuration = Users?.DmBlockedDuration ?? 24f - }; - Search = new DiscordSearchConfig - { - EnablePlayerNameSearchTrie = true - }; - Validation = new DiscordValidationConfig - { - EnableValidation = Validation?.EnableValidation ?? true - }; - Bot = new DiscordBotConfig - { - AutomaticallyApplyGatewayIntents = Bot?.AutomaticallyApplyGatewayIntents ?? true - }; - Ip = new DiscordIpConfig - { - StoreIpDuration = Ip?.StoreIpDuration ?? 30f, - UnknownCountryEmoji = Ip?.UnknownCountryEmoji ?? ":signal_strength:" - }; - } + CommandPrefixes = Commands?.CommandPrefixes ?? ['/', '!'] + }; + Rest = new DiscordRestConfig + { + ApiErrorRetries = Rest?.ApiErrorRetries ?? 3, + ApiRateLimitRetries = Rest?.ApiRateLimitRetries ?? 6 + }; + Logging = new DiscordLoggingConfig + { + HideDiscordErrorCodes = Logging?.HideDiscordErrorCodes ?? [], + ConsoleLogLevel = Logging?.ConsoleLogLevel ?? DiscordLogLevel.Info, + FileLogLevel = Logging?.FileLogLevel ?? DiscordLogLevel.Off, + FileDateTimeFormat = "HH:mm:ss.ff" + }; + Users = new DiscordUsersConfig + { + DmBlockedDuration = Users?.DmBlockedDuration ?? 24f + }; + Search = new DiscordSearchConfig + { + EnablePlayerNameSearchTrie = true + }; + Validation = new DiscordValidationConfig + { + EnableValidation = Validation?.EnableValidation ?? true + }; + Bot = new DiscordBotConfig + { + AutomaticallyApplyGatewayIntents = Bot?.AutomaticallyApplyGatewayIntents ?? true + }; + Ip = new DiscordIpConfig + { + StoreIpDuration = Ip?.StoreIpDuration ?? 30f, + UnknownCountryEmoji = Ip?.UnknownCountryEmoji ?? ":signal_strength:" + }; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Configuration/DiscordIpConfig.cs b/Oxide.Ext.Discord/Configuration/DiscordIpConfig.cs index 0723b3a6a..5b3fa83f9 100644 --- a/Oxide.Ext.Discord/Configuration/DiscordIpConfig.cs +++ b/Oxide.Ext.Discord/Configuration/DiscordIpConfig.cs @@ -1,22 +1,21 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Configuration +namespace Oxide.Ext.Discord.Configuration; + +/// +/// IP data config +/// +internal class DiscordIpConfig { /// - /// IP data config + /// How many days to store IP data /// - internal class DiscordIpConfig - { - /// - /// How many days to store IP data - /// - [JsonProperty("Save IP Data Duration (Days)")] - public float StoreIpDuration { get; set; } + [JsonProperty("Save IP Data Duration (Days)")] + public float StoreIpDuration { get; set; } - /// - /// How many days to store IP data - /// - [JsonProperty("Unknown Country Emoji")] - public string UnknownCountryEmoji { get; set; } - } + /// + /// How many days to store IP data + /// + [JsonProperty("Unknown Country Emoji")] + public string UnknownCountryEmoji { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Configuration/DiscordLoggingConfig.cs b/Oxide.Ext.Discord/Configuration/DiscordLoggingConfig.cs index 1ccb8c921..d484c26af 100644 --- a/Oxide.Ext.Discord/Configuration/DiscordLoggingConfig.cs +++ b/Oxide.Ext.Discord/Configuration/DiscordLoggingConfig.cs @@ -3,37 +3,36 @@ using Newtonsoft.Json.Converters; using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Configuration +namespace Oxide.Ext.Discord.Configuration; + +/// +/// Represents Discord Extension Logging Config +/// +internal class DiscordLoggingConfig : IDiscordLoggingConfig { /// - /// Represents Discord Extension Logging Config + /// Server Console Log Level /// - internal class DiscordLoggingConfig : IDiscordLoggingConfig - { - /// - /// Server Console Log Level - /// - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("Server Console Log Level")] - public DiscordLogLevel ConsoleLogLevel { get; set; } + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("Server Console Log Level")] + public DiscordLogLevel ConsoleLogLevel { get; set; } - /// - /// File Log Level - /// - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("File Log Level")] - public DiscordLogLevel FileLogLevel { get; set; } + /// + /// File Log Level + /// + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("File Log Level")] + public DiscordLogLevel FileLogLevel { get; set; } - /// - /// Discord Response Error codes that will not be logged - /// - [JsonProperty("Hide Discord Error Codes")] - public HashSet HideDiscordErrorCodes { get; set; } + /// + /// Discord Response Error codes that will not be logged + /// + [JsonProperty("Hide Discord Error Codes")] + public HashSet HideDiscordErrorCodes { get; set; } - /// - /// DateTime format for file logging - /// - [JsonProperty("File DateTime Format")] - public string FileDateTimeFormat { get; set; } - } + /// + /// DateTime format for file logging + /// + [JsonProperty("File DateTime Format")] + public string FileDateTimeFormat { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Configuration/DiscordRestConfig.cs b/Oxide.Ext.Discord/Configuration/DiscordRestConfig.cs index be7f5767d..6ffa32c24 100644 --- a/Oxide.Ext.Discord/Configuration/DiscordRestConfig.cs +++ b/Oxide.Ext.Discord/Configuration/DiscordRestConfig.cs @@ -1,22 +1,21 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Configuration +namespace Oxide.Ext.Discord.Configuration; + +/// +/// Discord Rest Config +/// +internal class DiscordRestConfig { /// - /// Discord Rest Config + /// How many retries for API request errors /// - internal class DiscordRestConfig - { - /// - /// How many retries for API request errors - /// - [JsonProperty("API Error Request Retries")] - public int ApiErrorRetries { get; set; } + [JsonProperty("API Error Request Retries")] + public int ApiErrorRetries { get; set; } - /// - /// How many retries for API request rate limit errors - /// - [JsonProperty("API Rate Limit Request Retries")] - public int ApiRateLimitRetries { get; set; } - } + /// + /// How many retries for API request rate limit errors + /// + [JsonProperty("API Rate Limit Request Retries")] + public int ApiRateLimitRetries { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Configuration/DiscordSearchConfig.cs b/Oxide.Ext.Discord/Configuration/DiscordSearchConfig.cs index 2c6718fac..7fc82f272 100644 --- a/Oxide.Ext.Discord/Configuration/DiscordSearchConfig.cs +++ b/Oxide.Ext.Discord/Configuration/DiscordSearchConfig.cs @@ -1,10 +1,9 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Configuration +namespace Oxide.Ext.Discord.Configuration; + +internal class DiscordSearchConfig { - internal class DiscordSearchConfig - { - [JsonProperty("Enable Player Name Trie Search (High Performance / High Memory Usage)")] - public bool EnablePlayerNameSearchTrie { get; set; } - } + [JsonProperty("Enable Player Name Trie Search (High Performance / High Memory Usage)")] + public bool EnablePlayerNameSearchTrie { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Configuration/DiscordUsersConfig.cs b/Oxide.Ext.Discord/Configuration/DiscordUsersConfig.cs index 9e8e7dc27..1245cfe9a 100644 --- a/Oxide.Ext.Discord/Configuration/DiscordUsersConfig.cs +++ b/Oxide.Ext.Discord/Configuration/DiscordUsersConfig.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Configuration +namespace Oxide.Ext.Discord.Configuration; + +/// +/// Discord User Config +/// +internal class DiscordUsersConfig { /// - /// Discord User Config + /// How long to block DM's after we receive a 50007 Discord API Error code /// - internal class DiscordUsersConfig - { - /// - /// How long to block DM's after we receive a 50007 Discord API Error code - /// - [JsonProperty("Direct Message Blocked Duration (Hours)")] - public float DmBlockedDuration { get; set; } - } + [JsonProperty("Direct Message Blocked Duration (Hours)")] + public float DmBlockedDuration { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Configuration/DiscordValidationConfig.cs b/Oxide.Ext.Discord/Configuration/DiscordValidationConfig.cs index 45b8c073f..ee8246650 100644 --- a/Oxide.Ext.Discord/Configuration/DiscordValidationConfig.cs +++ b/Oxide.Ext.Discord/Configuration/DiscordValidationConfig.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Configuration +namespace Oxide.Ext.Discord.Configuration; + +/// +/// Discord Validation Config +/// +internal class DiscordValidationConfig { /// - /// Discord Validation Config + /// Enables request validation /// - internal class DiscordValidationConfig - { - /// - /// Enables request validation - /// - [JsonProperty("Enable Request Validation")] - public bool EnableValidation { get; set; } - } + [JsonProperty("Enable Request Validation")] + public bool EnableValidation { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Connections/BotConnection.cs b/Oxide.Ext.Discord/Connections/BotConnection.cs index d19df6cf2..4333bb960 100644 --- a/Oxide.Ext.Discord/Connections/BotConnection.cs +++ b/Oxide.Ext.Discord/Connections/BotConnection.cs @@ -3,91 +3,87 @@ using Oxide.Ext.Discord.Factory; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Connections +namespace Oxide.Ext.Discord.Connections; + +/// +/// Bot Connection Settings +/// +public class BotConnection { /// - /// Bot Connection Settings + /// API token for the bot /// - public class BotConnection - { - /// - /// API token for the bot - /// - public string ApiToken { get; set; } + public string ApiToken { get; set; } - /// - /// Intents that your bot needs to work - /// See - /// - public GatewayIntents Intents { get; set; } + /// + /// Intents that your bot needs to work + /// See + /// + public GatewayIntents Intents { get; set; } - /// - /// Discord Extension Logging Level. - /// See - /// - public DiscordLogLevel LogLevel { get; set; } + /// + /// Discord Extension Logging Level. + /// See + /// + public DiscordLogLevel LogLevel { get; set; } - /// - /// Hidden Bot Token. Used when needing to display the token. - /// - public string HiddenToken => Token?.HiddenToken ?? "Unknown Token"; + /// + /// Hidden Bot Token. Used when needing to display the token. + /// + public string HiddenToken => Token?.HiddenToken ?? "Unknown Token"; - /// - /// Application ID of the Bot Token - /// - public Snowflake ApplicationId => Token?.ApplicationId ?? default(Snowflake); + /// + /// Application ID of the Bot Token + /// + public Snowflake ApplicationId => Token?.ApplicationId ?? default(Snowflake); - private BotTokenData Token { get; set; } + private BotTokenData Token { get; set; } - /// - /// Constructor - /// - public BotConnection() { } + /// + /// Constructor + /// + public BotConnection() { } - /// - /// Constructor - /// - public BotConnection(string apiToken, GatewayIntents intents = GatewayIntents.None) - { - ApiToken = apiToken; - Intents = intents; - } + /// + /// Constructor + /// + public BotConnection(string apiToken, GatewayIntents intents = GatewayIntents.None) + { + ApiToken = apiToken; + Intents = intents; + } - /// - /// Constructor - /// - public BotConnection(string apiToken, GatewayIntents intents = GatewayIntents.None, DiscordLogLevel logLevel = DiscordLogLevel.Info) : this(apiToken, intents) - { - ApiToken = apiToken; - Intents = intents; - LogLevel = logLevel; - } + /// + /// Constructor + /// + public BotConnection(string apiToken, GatewayIntents intents = GatewayIntents.None, DiscordLogLevel logLevel = DiscordLogLevel.Info) : this(apiToken, intents) + { + ApiToken = apiToken; + Intents = intents; + LogLevel = logLevel; + } - internal BotConnection(BotConnection connection) : this(connection.ApiToken, connection.Intents) - { - Token = connection.Token; - } + internal BotConnection(BotConnection connection) : this(connection.ApiToken, connection.Intents) + { + Token = connection.Token; + } - internal void Initialize(DiscordClient client) - { - if (Token == null) - { - Token = BotTokenFactory.Instance.CreateFromClient(client); - } - } + internal void Initialize(DiscordClient client) + { + Token ??= BotTokenFactory.Instance.CreateFromClient(client); + } - /// - /// Returns if the settings has the given intents - /// - /// Intents to be compared against - /// True if settings has the given intents; False otherwise - public bool HasIntents(GatewayIntents intents) => (Intents & intents) == intents; + /// + /// Returns if the settings have the given intents + /// + /// Intents to be compared against + /// True if settings have the given intents; False otherwise + public bool HasIntents(GatewayIntents intents) => (Intents & intents) == intents; - /// - /// Returns if the settings has any intent specified - /// - /// Intents to compare against - /// True if settings has at least one of the given intents - public bool HasAnyIntent(GatewayIntents intents) => (Intents & intents) != 0; - } + /// + /// Returns if the settings have any intent specified + /// + /// Intents to compare against + /// True if settings have at least one of the given intents + public bool HasAnyIntent(GatewayIntents intents) => (Intents & intents) != 0; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Connections/BotTokenData.cs b/Oxide.Ext.Discord/Connections/BotTokenData.cs index fe3344edb..b47bfbb73 100644 Binary files a/Oxide.Ext.Discord/Connections/BotTokenData.cs and b/Oxide.Ext.Discord/Connections/BotTokenData.cs differ diff --git a/Oxide.Ext.Discord/Connections/WebhookConnection.cs b/Oxide.Ext.Discord/Connections/WebhookConnection.cs new file mode 100644 index 000000000..2daaa9dca --- /dev/null +++ b/Oxide.Ext.Discord/Connections/WebhookConnection.cs @@ -0,0 +1,51 @@ +using Oxide.Ext.Discord.Entities; +using Oxide.Ext.Discord.Logging; +using Oxide.Ext.Discord.Types; + +namespace Oxide.Ext.Discord.Connections; + +/// +/// Connection for a webhook +/// +public class WebhookConnection +{ + /// + /// API token for the bot + /// + public readonly Snowflake WebhookId; + + /// + /// Token for the webhook + /// + public readonly string WebhookToken; + + public readonly string WebhookUrl; + + /// + /// Discord Extension Logging Level. + /// See + /// + public DiscordLogLevel LogLevel { get; set; } + + /// + /// Constructor for a webhook connection + /// + /// URL of the webhook + /// Log level for the webhook + public WebhookConnection(string webhookUrl, DiscordLogLevel logLevel = DiscordLogLevel.Info) + { + WebhookUrl = webhookUrl; + ReverseStringTokenizer tokenizer = new(webhookUrl, "/"); + if (tokenizer.MoveNext()) + { + WebhookToken = tokenizer.Current.ToString(); + } + + if (tokenizer.MoveNext()) + { + Snowflake.TryParse(tokenizer.Current, out WebhookId); + } + + LogLevel = logLevel; + } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Constants/DiscordEncoding.cs b/Oxide.Ext.Discord/Constants/DiscordEncoding.cs index edcf217e3..e20c81bc5 100644 --- a/Oxide.Ext.Discord/Constants/DiscordEncoding.cs +++ b/Oxide.Ext.Discord/Constants/DiscordEncoding.cs @@ -1,18 +1,17 @@ using System.Text; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Constants +namespace Oxide.Ext.Discord.Constants; + +/// +/// Encoding format the Discord Uses +/// +public sealed class DiscordEncoding : Singleton { /// - /// Encoding format the Discord Uses + /// Encoding format used by Discord /// - public sealed class DiscordEncoding : Singleton - { - /// - /// Encoding format used by Discord - /// - public readonly Encoding Encoding = new UTF8Encoding(false); + public readonly Encoding Encoding = new UTF8Encoding(false); - private DiscordEncoding() {} - } + private DiscordEncoding() {} } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Constants/DiscordEndpoints.cs b/Oxide.Ext.Discord/Constants/DiscordEndpoints.cs index a01986454..325923674 100644 --- a/Oxide.Ext.Discord/Constants/DiscordEndpoints.cs +++ b/Oxide.Ext.Discord/Constants/DiscordEndpoints.cs @@ -1,51 +1,50 @@ -namespace Oxide.Ext.Discord.Constants +namespace Oxide.Ext.Discord.Constants; + +/// +/// Discord API endpoint settings +/// +public static class DiscordEndpoints { /// - /// Discord API endpoint settings + /// Represents Discord Rest API endpoints /// - public static class DiscordEndpoints + public static class Rest { /// - /// Represents Discord Rest API endpoints + /// Base URL for Discord /// - public static class Rest - { - /// - /// Base URL for Discord - /// - public const string DiscordBaseUrl = "https://discord.com/api"; + public const string DiscordBaseUrl = "https://discord.com/api"; - /// - /// API Version for Rest requests - /// - public const string ApiVersion = "v10"; + /// + /// API Version for Rest requests + /// + public const string ApiVersion = "v10"; - /// - /// Discord API Url - /// - public const string ApiUrl = DiscordBaseUrl + "/" + ApiVersion + "/"; - } + /// + /// Discord API Url + /// + public const string ApiUrl = DiscordBaseUrl + "/" + ApiVersion + "/"; + } + /// + /// Represents Discord Websocket Connection Args + /// + public static class Websocket + { /// - /// Represents Discord Websocket Connection Args + /// Which websocket version to use /// - public static class Websocket - { - /// - /// Which websocket version to use - /// - public const string Version = "10"; + public const string Version = "10"; - /// - /// How the data sent / received will be encoded - /// - public const string Encoding = "json"; + /// + /// How the data sent / received will be encoded + /// + public const string Encoding = "json"; - /// - /// Generated connection string for the websocket - /// - /// - public static readonly string WebsocketArgs = $"v={Version}&encoding={Encoding}"; - } + /// + /// Generated connection string for the websocket + /// + /// + public static readonly string WebsocketArgs = $"v={Version}&encoding={Encoding}"; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Constants/DiscordExtHooks.cs b/Oxide.Ext.Discord/Constants/DiscordExtHooks.cs index f389fab16..9bea02964 100644 --- a/Oxide.Ext.Discord/Constants/DiscordExtHooks.cs +++ b/Oxide.Ext.Discord/Constants/DiscordExtHooks.cs @@ -4,1423 +4,1425 @@ using Oxide.Ext.Discord.Entities; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Constants +namespace Oxide.Ext.Discord.Constants; + +/// +/// Represents all hooks available in the discord extension +/// +public static class DiscordExtHooks { /// - /// Represents all hooks available in the discord extension + /// Hooks that are called on Discord Plugins + /// + private static readonly HashSet AllHooks = []; + + /// + /// Hooks that are called on Discord Plugins + /// + private static readonly HashSet PluginHooks = []; + + /// + /// Hooks that are call globally + /// + private static readonly HashSet GlobalHooks = + [ + OnDiscordPlayerLinked, + OnDiscordPlayerUnlink, + OnDiscordPlayerUnlinked + ]; + + /// + /// A mapping of Gateway Intent to Hooks /// - public static class DiscordExtHooks + private static readonly Hash> GatewayIntentHooks = new() { - /// - /// Hooks that are called on Discord Plugins - /// - private static readonly HashSet AllHooks = new HashSet(); - - /// - /// Hooks that are called on Discord Plugins - /// - private static readonly HashSet PluginHooks = new HashSet(); - - /// - /// Hooks that are call globally - /// - private static readonly HashSet GlobalHooks = new HashSet - { - OnDiscordPlayerLinked, - OnDiscordPlayerUnlink, - OnDiscordPlayerUnlinked, - }; - - /// - /// A mapping of Gateway Intent to Hooks - /// - private static readonly Hash> GatewayIntentHooks = new Hash> - { - [GatewayIntents.Guilds] = new List - { - OnDiscordGuildCreated, - OnDiscordGuildUpdated, - OnDiscordGuildDeleted, - OnDiscordGuildUnavailable, - OnDiscordGuildRoleCreated, - OnDiscordGuildRoleUpdated, - OnDiscordGuildRoleDeleted, - OnDiscordGuildChannelCreated, - OnDiscordGuildChannelUpdated, - OnDiscordGuildChannelDeleted, - OnDiscordGuildChannelPinsUpdated, - OnDiscordGuildThreadCreated, - OnDiscordGuildThreadUpdated, - OnDiscordGuildThreadListSynced, - OnDiscordGuildThreadMemberUpdated, - OnDiscordGuildThreadMembersUpdated, - OnDiscordStageInstanceCreated, - OnDiscordStageInstanceUpdated, - OnDiscordStageInstanceDeleted - }, - [GatewayIntents.GuildMembers] = new List - { - OnDiscordGuildMemberAdded, - OnDiscordGuildMemberUpdated, - OnDiscordGuildMemberRemoved, - OnDiscordGuildMemberRoleAdded, - OnDiscordGuildMemberRoleRemoved, - OnDiscordGuildMemberBoosted, - OnDiscordGuildMemberBoostExtended, - OnDiscordGuildMemberBoostEnded, - OnDiscordGuildMemberNicknameUpdated, - OnDiscordGuildMemberAvatarUpdated, - OnDiscordGuildMemberDeafened, - OnDiscordGuildMemberUndeafened, - OnDiscordGuildMemberMuted, - OnDiscordGuildMemberUnmuted, - OnDiscordGuildMemberTimeout, - OnDiscordGuildMemberTimeoutEnded, - OnDiscordGuildThreadMembersUpdated - }, - [GatewayIntents.GuildModeration] = new List - { - OnDiscordGuildMemberBanned, - OnDiscordGuildMemberUnbanned - }, - [GatewayIntents.GuildEmojisAndStickers] = new List - { - OnDiscordGuildEmojisUpdated, - OnDiscordGuildStickersUpdated - }, - [GatewayIntents.GuildIntegrations] = new List - { - OnDiscordGuildIntegrationsUpdated, - OnDiscordGuildIntegrationCreated, - OnDiscordGuildIntegrationUpdated, - OnDiscordGuildIntegrationDeleted - }, - [GatewayIntents.GuildWebhooks] = new List - { - OnDiscordGuildWebhookUpdated, - }, - [GatewayIntents.GuildInvites] = new List - { - OnDiscordGuildInviteCreated, - OnDiscordGuildIntegrationDeleted, - }, - [GatewayIntents.GuildVoiceStates] = new List - { - OnDiscordGuildVoiceStateUpdated - }, - [GatewayIntents.GuildPresences] = new List - { - OnDiscordGuildMemberPresenceUpdated - }, - [GatewayIntents.GuildMessages] = new List - { - OnDiscordGuildMessageCreated, - OnDiscordGuildMessageUpdated, - OnDiscordGuildMessageDeleted, - OnDiscordGuildMessagesBulkDeleted, - }, - [GatewayIntents.GuildMessageReactions] = new List - { - OnDiscordGuildMessageReactionAdded, - OnDiscordGuildMessageReactionRemoved, - OnDiscordGuildMessageReactionRemovedAll, - OnDiscordGuildMessageReactionEmojiRemoved, - }, - [GatewayIntents.GuildMessageTyping] = new List - { - OnDiscordGuildTypingStarted - }, - [GatewayIntents.DirectMessages] = new List - { - OnDiscordDirectMessageCreated, - OnDiscordDirectMessageUpdated, - OnDiscordDirectMessageDeleted, - OnDiscordDirectMessagesBulkDeleted, - }, - [GatewayIntents.DirectMessageReactions] = new List - { - OnDiscordDirectMessageReactionAdded, - OnDiscordDirectMessageReactionRemoved, - OnDiscordDirectMessageReactionRemovedAll, - OnDiscordDirectMessageReactionEmojiRemoved, - }, - [GatewayIntents.DirectMessageTyping] = new List - { - OnDiscordDirectTypingStarted - }, - [GatewayIntents.GuildScheduledEvents] = new List - { - OnDiscordGuildScheduledEventCreated, - OnDiscordGuildScheduledEventUpdated, - OnDiscordGuildScheduledEventDeleted, - OnDiscordGuildScheduledEventUserAdded, - OnDiscordGuildScheduledEventUserRemoved, - }, - [GatewayIntents.AutoModerationConfiguration] = new List - { - OnDiscordAutoModRuleCreated, - OnDiscordAutoModRuleUpdated, - OnDiscordAutoModRuleDeleted, - }, - [GatewayIntents.AutoModerationExecution] = new List - { - OnDiscordAutoModActionExecuted - }, - }; + [GatewayIntents.Guilds] = + [ + OnDiscordGuildCreated, + OnDiscordGuildUpdated, + OnDiscordGuildDeleted, + OnDiscordGuildUnavailable, + OnDiscordGuildRoleCreated, + OnDiscordGuildRoleUpdated, + OnDiscordGuildRoleDeleted, + OnDiscordGuildChannelCreated, + OnDiscordGuildChannelUpdated, + OnDiscordGuildChannelDeleted, + OnDiscordGuildChannelPinsUpdated, + OnDiscordGuildThreadCreated, + OnDiscordGuildThreadUpdated, + OnDiscordGuildThreadListSynced, + OnDiscordGuildThreadMemberUpdated, + OnDiscordGuildThreadMembersUpdated, + OnDiscordStageInstanceCreated, + OnDiscordStageInstanceUpdated, + OnDiscordStageInstanceDeleted + ], + [GatewayIntents.GuildMembers] = + [ + OnDiscordGuildMemberAdded, + OnDiscordGuildMemberUpdated, + OnDiscordGuildMemberRemoved, + OnDiscordGuildMemberRoleAdded, + OnDiscordGuildMemberRoleRemoved, + OnDiscordGuildMemberBoosted, + OnDiscordGuildMemberBoostExtended, + OnDiscordGuildMemberBoostEnded, + OnDiscordGuildMemberNicknameUpdated, + OnDiscordGuildMemberAvatarUpdated, + OnDiscordGuildMemberDeafened, + OnDiscordGuildMemberUndeafened, + OnDiscordGuildMemberMuted, + OnDiscordGuildMemberUnmuted, + OnDiscordGuildMemberTimeout, + OnDiscordGuildMemberTimeoutEnded, + OnDiscordGuildThreadMembersUpdated + ], + [GatewayIntents.GuildModeration] = + [ + OnDiscordGuildMemberBanned, + OnDiscordGuildMemberUnbanned + ], + [GatewayIntents.GuildEmojisAndStickers] = + [ + OnDiscordGuildEmojisUpdated, + OnDiscordGuildStickersUpdated + ], + [GatewayIntents.GuildIntegrations] = + [ + OnDiscordGuildIntegrationsUpdated, + OnDiscordGuildIntegrationCreated, + OnDiscordGuildIntegrationUpdated, + OnDiscordGuildIntegrationDeleted + ], + [GatewayIntents.GuildWebhooks] = + [ + OnDiscordGuildWebhookUpdated + ], + [GatewayIntents.GuildInvites] = + [ + OnDiscordGuildInviteCreated, + OnDiscordGuildIntegrationDeleted + ], + [GatewayIntents.GuildVoiceStates] = [OnDiscordGuildVoiceStateUpdated], + [GatewayIntents.GuildPresences] = [OnDiscordGuildMemberPresenceUpdated], + [GatewayIntents.GuildMessages] = + [ + OnDiscordGuildMessageCreated, + OnDiscordGuildMessageUpdated, + OnDiscordGuildMessageDeleted, + OnDiscordGuildMessagesBulkDeleted + ], + [GatewayIntents.GuildMessageReactions] = + [ + OnDiscordGuildMessageReactionAdded, + OnDiscordGuildMessageReactionRemoved, + OnDiscordGuildMessageReactionRemovedAll, + OnDiscordGuildMessageReactionEmojiRemoved + ], + [GatewayIntents.GuildMessageTyping] = [OnDiscordGuildTypingStarted], + [GatewayIntents.DirectMessages] = + [ + OnDiscordDirectMessageCreated, + OnDiscordDirectMessageUpdated, + OnDiscordDirectMessageDeleted, + OnDiscordDirectMessagesBulkDeleted + ], + [GatewayIntents.DirectMessageReactions] = + [ + OnDiscordDirectMessageReactionAdded, + OnDiscordDirectMessageReactionRemoved, + OnDiscordDirectMessageReactionRemovedAll, + OnDiscordDirectMessageReactionEmojiRemoved + ], + [GatewayIntents.DirectMessageTyping] = [OnDiscordDirectTypingStarted], + [GatewayIntents.GuildScheduledEvents] = + [ + OnDiscordGuildScheduledEventCreated, + OnDiscordGuildScheduledEventUpdated, + OnDiscordGuildScheduledEventDeleted, + OnDiscordGuildScheduledEventUserAdded, + OnDiscordGuildScheduledEventUserRemoved + ], + [GatewayIntents.AutoModerationConfiguration] = + [ + OnDiscordAutoModRuleCreated, + OnDiscordAutoModRuleUpdated, + OnDiscordAutoModRuleDeleted + ], + [GatewayIntents.AutoModerationExecution] = [OnDiscordAutoModActionExecuted], + }; - /// - /// A mapping of Hooks required Gateway Intent - /// - public static readonly Hash HookGatewayIntent = new Hash(); + /// + /// A mapping of Hooks required Gateway Intent + /// + public static readonly Hash HookGatewayIntent = new(); - static DiscordExtHooks() + static DiscordExtHooks() + { + Type stringType = typeof(string); + foreach (FieldInfo field in typeof(DiscordExtHooks).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)) { - Type stringType = typeof(string); - foreach (FieldInfo field in typeof(DiscordExtHooks).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)) + if (field.IsLiteral && !field.IsInitOnly && field.FieldType == stringType) { - if (field.IsLiteral && !field.IsInitOnly && field.FieldType == stringType) + string hook = (string)field.GetRawConstantValue(); + AllHooks.Add(hook); + if (!GlobalHooks.Contains(hook)) { - string hook = (string)field.GetRawConstantValue(); - AllHooks.Add(hook); - if (!GlobalHooks.Contains(hook)) - { - PluginHooks.Add(hook); - } + PluginHooks.Add(hook); } } + } - foreach (KeyValuePair> intentHooks in GatewayIntentHooks) + foreach (KeyValuePair> intentHooks in GatewayIntentHooks) + { + foreach (string hook in intentHooks.Value) { - foreach (string hook in intentHooks.Value) - { - HookGatewayIntent[hook] |= intentHooks.Key; - } + HookGatewayIntent[hook] |= intentHooks.Key; } } - - /// - /// Returns true if the hook is a Discord Extension Global Hook - /// - /// Name of the hook - /// - public static bool IsGlobalHook(string hook) => GlobalHooks.Contains(hook); - - /// - /// Returns true if the hook is a Discord Extension Plugin Hook - /// - /// Name of the hook - /// - public static bool IsPluginHook(string hook) => PluginHooks.Contains(hook); - - /// - /// Returns true if the hook is a Discord Extension Hook - /// - /// Name of the hook - /// - public static bool IsDiscordHook(string hook) => AllHooks.Contains(hook); - - #region Bot Client Hooks - /// - /// Called when the DiscordClient is created on the bot and is ready to use. - /// This is called after the Loaded() hook on the plugin. - /// - /// void OnDiscordClientCreated() - /// { - /// Puts("OnDiscordClientCreated Works!"); - /// } - /// - /// - public const string OnDiscordClientCreated = nameof(OnDiscordClientCreated); - - /// - /// Called when the bot has fully loaded all discord guilds - /// If GatewayIntent.GuildMembers is specified then this hook is delayed until all guild members have been loaded - /// - /// void OnDiscordBotFullyLoaded() - /// { - /// Puts("OnDiscordBotFullyLoaded Works!"); - /// } - /// - /// - public const string OnDiscordBotFullyLoaded = nameof(OnDiscordBotFullyLoaded); - #endregion - - #region Socket Hooks - /// - /// Called when the discord socket connects. - /// - /// void OnDiscordWebsocketOpened() - /// { - /// Puts("OnDiscordWebsocketOpened Works!"); - /// } - /// - /// - public const string OnDiscordWebsocketOpened = nameof(OnDiscordWebsocketOpened); - - /// - /// Called when the web socket is closed for any reason. - /// - /// void OnDiscordWebsocketClosed(string reason, ushort code) - /// { - /// Puts("OnDiscordWebsocketClosed Works!"); - /// } - /// - /// - public const string OnDiscordWebsocketClosed = nameof(OnDiscordWebsocketClosed); - - /// - /// Called when the web socket has an error. - /// - /// void OnDiscordWebsocketErrored(Exception ex, string message) - /// { - /// Puts("OnDiscordWebsocketErrored Works!"); - /// } - /// - /// - public const string OnDiscordWebsocketErrored = nameof(OnDiscordWebsocketErrored); - - /// - /// Called when we receive the heartbeat interval from the websocket - /// - /// void OnDiscordSetupHeartbeat(float heartbeat) - /// { - /// Puts("OnDiscordHeartbeatSent Works!"); - /// } - /// - /// - public const string OnDiscordSetupHeartbeat = nameof(OnDiscordSetupHeartbeat); - - /// - /// Called when a heartbeat is sent over the websocket to discord to keep the connection open - /// - /// void OnDiscordHeartbeatSent() - /// { - /// Puts("OnDiscordHeartbeatSent Works!"); - /// } - /// - /// - public const string OnDiscordHeartbeatSent = nameof(OnDiscordHeartbeatSent); - #endregion - - #region Link Hooks - /// - /// These hooks are called when a player is linked or unlinked using discord link. - /// It will be called for every plugins registered to receive hooks. - /// **Note:** If your plugin supports discord link you should not supply any other hooks as the extension provides them for you. - /// **Note:** Discord Link hooks are considered global hooks and will be called on all plugins regardless of bot - /// - /// void OnDiscordPlayerLinked(IPlayer player, DiscordUser discord) - /// { - /// Puts("OnDiscordPlayerLinked Works!"); - /// } - /// - /// - public const string OnDiscordPlayerLinked = nameof(OnDiscordPlayerLinked); - - /// - /// Called when a player is being unlinked from DiscordLink Library - /// This is called before the unlink occurs - /// - /// void OnDiscordPlayerUnlink(IPlayer player, DiscordUser discord) - /// { - /// Puts("OnDiscordPlayerUnlink Works!"); - /// } - /// - /// - public const string OnDiscordPlayerUnlink = nameof(OnDiscordPlayerUnlink); - - /// - /// Called when a player has unlinked their discord and player together using the DiscordLink library - /// - /// void OnDiscordPlayerUnlinked(IPlayer player, DiscordUser discord) - /// { - /// Puts("OnDiscordPlayerUnlinked Works!"); - /// } - /// - /// - public const string OnDiscordPlayerUnlinked = nameof(OnDiscordPlayerUnlinked); - #endregion - - #region Discord Event Hooks - /// - /// - Called when the Discord Bot has successfully connected to the gateway and identified successfully. - /// **Note:** Only partial guild information is available at this point. - /// If you need full guild listen for [OnDiscordGuildCreated](#OnDiscordGuildCreated) hook - /// If you need full guild member list listen for [OnDiscordGuildMembersLoaded](#OnDiscordGuildMembersLoaded) - /// - /// void OnDiscordGatewayReady(GatewayReadyEvent ready) - /// { - /// Puts("OnDiscordGatewayReady Works!"); - /// } - /// - /// - public const string OnDiscordGatewayReady = nameof(OnDiscordGatewayReady); - - /// - /// Called when the websocket has reconnected to the websocket and resumed the previous session - /// - /// void OnDiscordGatewayResumed(GatewayResumedEvent resume) - /// { - /// Puts("OnDiscordGatewayResumed Works!"); - /// } - /// - /// - public const string OnDiscordGatewayResumed = nameof(OnDiscordGatewayResumed); - - /// - /// Called when the websocket has reconnected - /// - /// void OnDiscordGatewayReconnected() - /// { - /// Puts("OnDiscordGatewayReconnected Works!"); - /// } - /// - /// - public const string OnDiscordGatewayReconnected = nameof(OnDiscordGatewayReconnected); - - /// - /// Called when a direct message (DM) channel has been created. - /// - /// void OnDiscordDirectChannelCreated(DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectChannelCreated Works!"); - /// } - /// - /// - public const string OnDiscordDirectChannelCreated = nameof(OnDiscordDirectChannelCreated); - - /// - /// Called when a channel has been created in a guild. - /// - /// void OnDiscordGuildChannelCreated(DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildChannelCreated Works!"); - /// } - /// - /// - public const string OnDiscordGuildChannelCreated = nameof(OnDiscordGuildChannelCreated); - - /// - /// Called when a direct message (DM) channel has been updated. - /// - /// Note: previous will be null if previous channel not found - /// void OnDiscordDirectChannelUpdated(DiscordChannel channel, DiscordChannel previous) - /// { - /// Puts("OnDiscordDirectChannelUpdated Works!"); - /// } - /// - /// - public const string OnDiscordDirectChannelUpdated = nameof(OnDiscordDirectChannelUpdated); - - /// - /// Called when a channel has been updated in a guild. - /// - /// void OnDiscordGuildChannelUpdated(DiscordChannel channel, DiscordChannel previous, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildChannelUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildChannelUpdated = nameof(OnDiscordGuildChannelUpdated); - - /// - /// Called when a direct message (DM) channel has been deleted. - /// Not sure if this is possible for DM channels - /// - /// Note: Not sure if this will ever happen but we handle it if it does - /// void OnDiscordDirectChannelDeleted(DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectChannelDeleted Works!"); - /// } - /// - /// - public const string OnDiscordDirectChannelDeleted = nameof(OnDiscordDirectChannelDeleted); - - /// - /// Called when a channel has been deleted in a guild. - /// - /// void OnDiscordGuildChannelDeleted(DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildChannelDeleted Works!"); - /// } - /// - /// - public const string OnDiscordGuildChannelDeleted = nameof(OnDiscordGuildChannelDeleted); - - /// - /// Called when a direct message (DM) channel has it's pinned messages updated. - /// Channel may be null if we haven't seen it before. - /// - /// void OnDiscordDirectChannelPinsUpdated(ChannelPinsUpdatedEvent update, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectChannelPinsUpdated Works!"); - /// } - /// - /// - public const string OnDiscordDirectChannelPinsUpdated = nameof(OnDiscordDirectChannelPinsUpdated); - - /// - /// Called when an entitlement has been created - /// - /// void OnDiscordEntitlementCreated(DiscordEntitlement entitlement, DiscordGuild guild) - /// { - /// Puts("OnDiscordEntitlementCreated Works!"); - /// } - /// - /// - public const string OnDiscordEntitlementCreated = nameof(OnDiscordEntitlementCreated); - - /// - /// Called when an entitlement has been update - /// - /// void OnDiscordEntitlementUpdated(DiscordEntitlement entitlement, DiscordGuild guild) - /// { - /// Puts("OnDiscordEntitlementUpdated Works!"); - /// } - /// - /// - public const string OnDiscordEntitlementUpdated = nameof(OnDiscordEntitlementUpdated); - - /// - /// Called when an entitlement has been deleted - /// - /// void OnDiscordEntitlementDeleted(DiscordEntitlement entitlement, DiscordGuild guild) - /// { - /// Puts("OnDiscordEntitlementDeleted Works!"); - /// } - /// - /// - public const string OnDiscordEntitlementDeleted = nameof(OnDiscordEntitlementDeleted); - - /// - /// Called when a guild channel has it's pinned messages updated - /// - /// void OnDiscordGuildChannelPinsUpdated(ChannelPinsUpdatedEvent update, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildChannelPinsUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildChannelPinsUpdated = nameof(OnDiscordGuildChannelPinsUpdated); - - /// - /// Called when a discord server is fully loaded while connecting or the bot has joined a new discord server - /// - /// void OnDiscordGuildCreated(GuildDiscordGuild guild) - /// { - /// Puts("OnDiscordGuildCreated Works!"); - /// } - /// - /// - public const string OnDiscordGuildCreated = nameof(OnDiscordGuildCreated); - - /// - /// Called when any updates are made to a guild - /// Note: previous will be null if guild previously not loaded - /// - /// void OnDiscordGuildUpdated(DiscordGuild guild, DiscordGuild previous) - /// { - /// Puts("OnDiscordGuildUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildUpdated = nameof(OnDiscordGuildUpdated); - - /// - /// Called when a guild become unavailable due to a network outage - /// - /// void OnDiscordGuildUnavailable(DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildUnavailable Works!"); - /// } - /// - /// - public const string OnDiscordGuildUnavailable = nameof(OnDiscordGuildUnavailable); - - /// - /// Called when a bot is removed from a discord server or that discord server was deleted - /// - /// void OnDiscordGuildDeleted(DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildDeleted Works!"); - /// } - /// - /// - public const string OnDiscordGuildDeleted = nameof(OnDiscordGuildDeleted); - - /// - /// Called when a guild member is banned - /// - /// void OnDiscordGuildMemberBanned(GuildMemberBannedEvent ban, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberBanned Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberBanned = nameof(OnDiscordGuildMemberBanned); - - /// - /// Called when a guild member is unbanned - /// - /// void OnDiscordGuildMemberUnbanned(GuildMemberBannedEvent ban, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildBanRemoved Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberUnbanned = nameof(OnDiscordGuildMemberUnbanned); - - /// - /// Called when the custom emojis for a guild are created/updated/deleted - /// - /// void OnDiscordGuildEmojisUpdated(GuildEmojisUpdatedEvent emojis, Hash<Snowflake, DiscordEmoji> previous, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildEmojisUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildEmojisUpdated = nameof(OnDiscordGuildEmojisUpdated); - - /// - /// Called when the guild stickers are updated - /// - /// void OnDiscordGuildStickersUpdated(GuildStickersUpdatedEvent stickers, Hash<Snowflake, DiscordSticker> previous, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildStickersUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildStickersUpdated = nameof(OnDiscordGuildStickersUpdated); - - /// - /// Called when a guild integration is updated - /// - /// void OnDiscordGuildIntegrationsUpdated(GuildIntegrationsUpdatedEvent integration, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildIntegrationsUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildIntegrationsUpdated = nameof(OnDiscordGuildIntegrationsUpdated); - - /// - /// Called when a guild member has been added to the guild - /// - /// void OnDiscordGuildMemberAdded(GuildMemberAddedEvent member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberAdded Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberAdded = nameof(OnDiscordGuildMemberAdded); - - /// - /// Called when a guild member has been removed from the guild - /// - /// void OnDiscordGuildMemberRemoved(GuildMemberRemovedEvent member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberRemoved Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberRemoved = nameof(OnDiscordGuildMemberRemoved); - - /// - /// Called when a guild member has been updated - /// This also include when the DiscordUser is updated as well - /// - /// void OnDiscordGuildMemberUpdated(GuildMemberUpdatedEvent member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberUpdated = nameof(OnDiscordGuildMemberUpdated); - - /// - /// Called when a guild member nickname has been updated - /// - /// void OnDiscordGuildMemberNicknameUpdated(GuildMember member, string oldNickname, string newNickname, DateTime? lastNicknameUpdate, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberNicknameUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberNicknameUpdated = nameof(OnDiscordGuildMemberNicknameUpdated); - - /// - /// Called when a guild member avatar has been updated - /// - /// void OnDiscordGuildMemberAvatarUpdated(GuildMember member, string oldAvatar, string newAvatar, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberAvatarUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberAvatarUpdated = nameof(OnDiscordGuildMemberAvatarUpdated); - - /// - /// Called when a guild member is deafened - /// - /// void OnDiscordGuildMemberDeafened(GuildMember member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberDeafened Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberDeafened = nameof(OnDiscordGuildMemberDeafened); - - /// - /// Called when a guild member is undeafened - /// - /// void OnDiscordGuildMemberUndeafened(GuildMember member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberUndeafened Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberUndeafened = nameof(OnDiscordGuildMemberUndeafened); - - /// - /// Called when a guild member is muted - /// - /// void OnDiscordGuildMemberMuted(GuildMember member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberMuted Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberMuted = nameof(OnDiscordGuildMemberMuted); - - /// - /// Called when a guild member is unmuted - /// - /// void OnDiscordGuildMemberUnmuted(GuildMember member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberUnmuted Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberUnmuted = nameof(OnDiscordGuildMemberUnmuted); - - /// - /// Called when a guild member is placed in [Timeout](https://support.discord.com/hc/en-us/articles/4413305239191-Time-Out-FAQ) - /// - /// void OnDiscordGuildMemberTimeout(GuildMember member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberTimeout Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberTimeout = nameof(OnDiscordGuildMemberTimeout); - - /// - /// Called when a guild members [Timeout](https://support.discord.com/hc/en-us/articles/4413305239191-Time-Out-FAQ) ends - /// - /// void OnDiscordGuildMemberTimeoutEnded(GuildMember member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberTimeoutEnded Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberTimeoutEnded = nameof(OnDiscordGuildMemberTimeoutEnded); - - /// - /// Called when a guild member boosts the server - /// - /// void OnDiscordGuildMemberBoosted(GuildMember member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberBoosted Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberBoosted = nameof(OnDiscordGuildMemberBoosted); - - /// - /// Called when a guild member extends their boost - /// - /// void OnDiscordGuildMemberBoostExtended(GuildMember member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberBoostExtended Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberBoostExtended = nameof(OnDiscordGuildMemberBoostExtended); - - /// - /// Called when a guild member boost ends - /// - /// void OnDiscordGuildMemberBoostEnded(GuildMember member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberBoostEnded Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberBoostEnded = nameof(OnDiscordGuildMemberBoostEnded); - - /// - /// Called when a role is added to a guild member - /// - /// void OnDiscordGuildMemberRoleAdded(GuildMember member, Snowflake roleId, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberRoleAdded Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberRoleAdded = nameof(OnDiscordGuildMemberRoleAdded); - - /// - /// Called when a role is removed from a guild member - /// - /// void OnDiscordGuildMemberRoleRemoved(GuildMember member, Snowflake roleId, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberRoleRemoved Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberRoleRemoved = nameof(OnDiscordGuildMemberRoleRemoved); - - /// - /// Called when a guild has finished loading all guild members - /// This Discord Extension requests all guild members in the [OnDiscordGuildCreated](#ondiscordguildcreated) Hook - /// - /// void OnDiscordGuildMembersLoaded(DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMembersLoaded Works!"); - /// } - /// - /// - public const string OnDiscordGuildMembersLoaded = nameof(OnDiscordGuildMembersLoaded); - - /// - /// Called in a response to a request for guild member chunks - /// - /// void OnDiscordGuildMembersChunk(GuildMembersChunkEvent chunk, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMembersChunk Works!"); - /// } - /// - /// - public const string OnDiscordGuildMembersChunk = nameof(OnDiscordGuildMembersChunk); - - /// - /// Called when a discord guild role is created - /// - /// void OnDiscordGuildRoleCreated(DiscordRole role, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildRoleCreated Works!"); - /// } - /// - /// - public const string OnDiscordGuildRoleCreated = nameof(OnDiscordGuildRoleCreated); - - /// - /// Called when a discord guild role is updated - /// - /// void OnDiscordGuildRoleUpdated(DiscordRole role, DiscordRole previous, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildRoleUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildRoleUpdated = nameof(OnDiscordGuildRoleUpdated); - - /// - /// Called when a discord guild role is deleted - /// - /// void OnDiscordGuildRoleDeleted(DiscordRole role, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildRoleDeleted Works!"); - /// } - /// - /// - public const string OnDiscordGuildRoleDeleted = nameof(OnDiscordGuildRoleDeleted); - - /// - /// Called when a discord guild scheduled event is created - /// - /// void OnDiscordGuildScheduledEventCreated(GuildScheduledEvent guildEvent, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildScheduledEventCreated Works!"); - /// } - /// - /// - public const string OnDiscordGuildScheduledEventCreated = nameof(OnDiscordGuildScheduledEventCreated); - - /// - /// Called when a discord guild scheduled event is updated - /// - /// void OnDiscordGuildScheduledEventUpdated(GuildScheduledEvent guildEvent, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildScheduledEventUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildScheduledEventUpdated = nameof(OnDiscordGuildScheduledEventUpdated); - - /// - /// Called when a discord guild scheduled event is deleted - /// - /// void OnDiscordGuildScheduledEventDeleted(GuildScheduledEvent guildEvent, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildScheduledEventDeleted Works!"); - /// } - /// - /// - public const string OnDiscordGuildScheduledEventDeleted = nameof(OnDiscordGuildScheduledEventDeleted); - - /// - /// Called when a discord user is added to a guild scheduled event - /// - /// void OnDiscordGuildScheduledEventUserAdded(GuildScheduleEventUserAddedEvent added, GuildScheduledEvent, scheduledEvent, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildScheduledEventUserAdded Works!"); - /// } - /// - /// - public const string OnDiscordGuildScheduledEventUserAdded = nameof(OnDiscordGuildScheduledEventUserAdded); - - /// - /// Called when a discord user is removed from a guild scheduled event - /// - /// void OnDiscordGuildScheduledEventUserRemoved(GuildScheduleEventUserRemovedEvent removed, GuildScheduledEvent, scheduledEvent, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildScheduledEventUserRemoved Works!"); - /// } - /// - /// - public const string OnDiscordGuildScheduledEventUserRemoved = nameof(OnDiscordGuildScheduledEventUserRemoved); - - /// - /// Called when a message is created in a direct message channel - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectMessageCreated(DiscordMessage message, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectMessageCreated Works!"); - /// } - /// - /// - public const string OnDiscordDirectMessageCreated = nameof(OnDiscordDirectMessageCreated); - - /// - /// Called when a message is created in a guild channel - /// - /// void OnDiscordGuildMessageCreated(DiscordMessage message, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMessageCreated Works!"); - /// } - /// - /// - public const string OnDiscordGuildMessageCreated = nameof(OnDiscordGuildMessageCreated); - - /// - /// Called when a message is updated in a direct message channel - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectMessageUpdated(DiscordMessage message, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectMessageUpdated Works!"); - /// } - /// - /// - public const string OnDiscordDirectMessageUpdated = nameof(OnDiscordDirectMessageUpdated); - - /// - /// Called when a message is updated in a guild channel - /// - /// void OnDiscordDirectMessageUpdated(DiscordMessage message, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectMessageUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildMessageUpdated = nameof(OnDiscordGuildMessageUpdated); - - /// - /// Called when a message is deleted in a direct message channel - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectMessageDeleted(DiscordMessage message, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectMessageDeleted Works!"); - /// } - /// - /// - public const string OnDiscordDirectMessageDeleted = nameof(OnDiscordDirectMessageDeleted); - - /// - /// Called when a message is deleted in a guild channel - /// - /// void OnDiscordGuildMessageDeleted(DiscordMessage message, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMessageDeleted Works!"); - /// } - /// - /// - public const string OnDiscordGuildMessageDeleted = nameof(OnDiscordGuildMessageDeleted); - - /// - /// Called when a message is deleted in a direct message channel - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectMessagesBulkDeleted(List<Snowflake> messageIds, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectMessagesBulkDeleted Works!"); - /// } - /// - /// - public const string OnDiscordDirectMessagesBulkDeleted = nameof(OnDiscordDirectMessagesBulkDeleted); - - /// - /// Called when a message is deleted in a guild channel - /// - /// void OnDiscordGuildMessagesBulkDeleted(List<Snowflake> messageIds, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMessagesBulkDeleted Works!"); - /// } - /// - /// - public const string OnDiscordGuildMessagesBulkDeleted = nameof(OnDiscordDirectMessagesBulkDeleted); - - /// - /// Called when a reaction is added to a message in a direct message channel - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectMessageReactionAdded(MessageReactionAddedEvent reaction, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectMessageReactionAdded Works!"); - /// } - /// - /// - public const string OnDiscordDirectMessageReactionAdded = nameof(OnDiscordDirectMessageReactionAdded); - - /// - /// Called when a reaction is added to a message in a guild channel - /// - /// void OnDiscordGuildMessageReactionAdded(MessageReactionAddedEvent reaction, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMessageReactionAdded Works!"); - /// } - /// - /// - public const string OnDiscordGuildMessageReactionAdded = nameof(OnDiscordGuildMessageReactionAdded); - - /// - /// Called when a reaction is removed from a message in a direct message channel - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectMessageReactionRemoved(MessageReactionRemovedEvent reaction, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectMessageReactionRemoved Works!"); - /// } - /// - /// - public const string OnDiscordDirectMessageReactionRemoved = nameof(OnDiscordDirectMessageReactionRemoved); - - /// - /// Called when a reaction is removed from a message in a guild channel - /// - /// void OnDiscordGuildMessageReactionRemoved(MessageReactionRemovedEvent reaction, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMessageReactionRemoved Works!"); - /// } - /// - /// - public const string OnDiscordGuildMessageReactionRemoved = nameof(OnDiscordGuildMessageReactionRemoved); - - /// - /// Called when all reactions are removed from a message in a direct message channel - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectMessageReactionRemovedAll(MessageReactionRemovedAllEmojiEvent reaction, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectMessageReactionRemovedAll Works!"); - /// } - /// - /// - public const string OnDiscordDirectMessageReactionRemovedAll = nameof(OnDiscordDirectMessageReactionRemoved); - - /// - /// Called when all reactions are removed from a message in a guild channel - /// - /// void OnDiscordGuildMessageReactionRemovedAll(MessageReactionRemovedAllEmojiEvent reaction, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMessageReactionRemovedAll Works!"); - /// } - /// - /// - public const string OnDiscordGuildMessageReactionRemovedAll = nameof(OnDiscordGuildMessageReactionRemoved); - - /// - /// Called when all of a specific reactions is removed from a message in a direct message channel - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectMessageReactionEmojiRemoved(MessageReactionRemovedAllEmojiEvent reaction, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectMessageReactionEmojiRemoved Works!"); - /// } - /// - /// - public const string OnDiscordDirectMessageReactionEmojiRemoved = nameof(OnDiscordDirectMessageReactionEmojiRemoved); - - /// - /// Called when all of a specific reaction is removed from a message in a guild channel - /// - /// void OnDiscordGuildMessageReactionEmojiRemoved(MessageReactionRemovedAllEmojiEvent reaction, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMessageReactionEmojiRemoved Works!"); - /// } - /// - /// - public const string OnDiscordGuildMessageReactionEmojiRemoved = nameof(OnDiscordGuildMessageReactionEmojiRemoved); - - /// - /// Called when a guild members presence is updated - /// - /// void OnDiscordGuildMemberPresenceUpdated(PresenceUpdatedEvent update, GuildMember member, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildMemberPresenceUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildMemberPresenceUpdated = nameof(OnDiscordGuildMemberPresenceUpdated); - - /// - /// Called typing starts in a direct message channel - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectTypingStarted(TypingStartedEvent typing, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectTypingStarted Works!"); - /// } - /// - /// - public const string OnDiscordDirectTypingStarted = nameof(OnDiscordDirectTypingStarted); - - /// - /// Called when typing starts in a guild channel - /// - /// void OnDiscordGuildTypingStarted(TypingStartedEvent typing, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildTypingStarted Works!"); - /// } - /// - /// - public const string OnDiscordGuildTypingStarted = nameof(OnDiscordGuildTypingStarted); - - /// - /// Called when a discord user is updated - /// - /// void OnDiscordUserUpdated(DiscordUser user) - /// { - /// Puts("OnDiscordUserUpdated Works!"); - /// } - /// - /// - public const string OnDiscordUserUpdated = nameof(OnDiscordUserUpdated); - - /// - /// Called when the voice state in a direct message channel is updated - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectVoiceStateUpdated(VoiceState voice, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectVoiceStateUpdated Works!"); - /// } - /// - /// - public const string OnDiscordDirectVoiceStateUpdated = nameof(OnDiscordDirectVoiceStateUpdated); - - /// - /// Called when the voice state in a guild channel is updated - /// - /// void OnDiscordGuildVoiceStateUpdated(VoiceState voice, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildVoiceStateUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildVoiceStateUpdated = nameof(OnDiscordGuildVoiceStateUpdated); - - /// - /// Called when the voice server in a guild channel is updated - /// - /// void OnDiscordGuildVoiceServerUpdated(VoiceServerUpdatedEvent voice, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildVoiceServerUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildVoiceServerUpdated = nameof(OnDiscordGuildVoiceServerUpdated); - - /// - /// Called when a webhook ins a guild is updated - /// - /// void OnDiscordGuildWebhookUpdated(WebhooksUpdatedEvent webhook, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildWebhookUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildWebhookUpdated = nameof(OnDiscordGuildWebhookUpdated); - - /// - /// Called when an invite to a direct message channel is created - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectInviteCreated(InviteCreatedEvent invite, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectInviteCreated Works!"); - /// } - /// - /// - public const string OnDiscordDirectInviteCreated = nameof(OnDiscordDirectInviteCreated); - - /// - /// Called when an invite to a guild channel is created - /// - /// void OnDiscordGuildInviteCreated(InviteCreatedEvent invite, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildInviteCreated Works!"); - /// } - /// - /// - public const string OnDiscordGuildInviteCreated = nameof(OnDiscordGuildInviteCreated); - - /// - /// Called when an invite to a direct message channel is deleted - /// `channel` may be null if we haven't seen it yet - /// - /// void OnDiscordDirectInviteDeleted(InviteCreatedEvent invite, DiscordChannel channel) - /// { - /// Puts("OnDiscordDirectInviteDeleted Works!"); - /// } - /// - /// - public const string OnDiscordDirectInviteDeleted = nameof(OnDiscordDirectInviteDeleted); - - /// - /// Called when an invite to a guild channel is deleted - /// - /// void OnDiscordGuildInviteDeleted(InviteCreatedEvent invite, DiscordChannel channel, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildInviteDeleted Works!"); - /// } - /// - /// - public const string OnDiscordGuildInviteDeleted = nameof(OnDiscordGuildInviteDeleted); - - /// - /// Called when the bots application command permission have been updated - /// - /// void OnDiscordApplicationCommandPermissionsUpdated(CommandPermissions permissions) - /// { - /// Puts("OnDiscordInteractionCreated Works!"); - /// } - /// - /// - public const string OnDiscordApplicationCommandPermissionsUpdated = nameof(OnDiscordApplicationCommandPermissionsUpdated); - - /// - /// Called when a discord interaction occurs by a user - /// - /// void OnDiscordInteractionCreated(DiscordInteraction interaction) - /// { - /// Puts("OnDiscordInteractionCreated Works!"); - /// } - /// - /// - public const string OnDiscordInteractionCreated = nameof(OnDiscordInteractionCreated); - - /// - /// Called when a new integration is created a guild - /// - /// void OnDiscordGuildIntegrationCreated(IntegrationCreatedEvent integration, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildIntegrationCreated Works!"); - /// } - /// - /// - public const string OnDiscordGuildIntegrationCreated = nameof(OnDiscordGuildIntegrationCreated); - - /// - /// Called when an integration is updated on a guild - /// - /// void OnDiscordGuildIntegrationUpdated(IntegrationUpdatedEvent interaction, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildIntegrationUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildIntegrationUpdated = nameof(OnDiscordGuildIntegrationUpdated); - - /// - /// Called when an integration is deleted on a guild - /// - /// void OnDiscordGuildIntegrationDeleted(IntegrationDeletedEvent interaction, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildIntegrationDeleted Works!"); - /// } - /// - /// - public const string OnDiscordGuildIntegrationDeleted = nameof(OnDiscordGuildIntegrationDeleted); - - /// - /// Called when a guild thread is created - /// - /// void OnDiscordGuildThreadCreated(DiscordChannel thread, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildThreadCreated Works!"); - /// } - /// - /// - public const string OnDiscordGuildThreadCreated = nameof(OnDiscordGuildThreadCreated); - - /// - /// Called when a guild thread is updated - /// - /// void OnDiscordGuildThreadUpdated(DiscordChannel thread, DiscordChannel previous, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildThreadUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildThreadUpdated = nameof(OnDiscordGuildThreadUpdated); - - /// - /// Called when a guild thread is deleted - /// - /// void OnDiscordGuildThreadDeleted(DiscordChannel thread, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildThreadDeleted Works!"); - /// } - /// - /// - public const string OnDiscordGuildThreadDeleted = nameof(OnDiscordGuildThreadDeleted); - - /// - /// Called when a guild thread list is synced - /// - /// void OnDiscordGuildThreadListSynced(ThreadListSyncEvent sync, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildThreadListSynced Works!"); - /// } - /// - /// - public const string OnDiscordGuildThreadListSynced = nameof(OnDiscordGuildThreadListSynced); - - /// - /// Called when a thread member is updated - /// - /// void OnDiscordGuildThreadMemberUpdated(ThreadMember member, DiscordChannel thread, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildThreadMemberUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildThreadMemberUpdated = nameof(OnDiscordGuildThreadMemberUpdated); - - /// - /// Called when thread members are updated - /// - /// void OnDiscordGuildThreadMembersUpdated(ThreadMembersUpdatedEvent members, DiscordGuild guild) - /// { - /// Puts("OnDiscordGuildThreadMembersUpdated Works!"); - /// } - /// - /// - public const string OnDiscordGuildThreadMembersUpdated = nameof(OnDiscordGuildThreadMembersUpdated); - - /// - /// Called when a stage instance is created - /// - /// void OnDiscordStageInstanceCreated(StageInstance stage, DiscordGuild guild) - /// { - /// Puts("OnDiscordStageInstanceCreated Works!"); - /// } - /// - /// - public const string OnDiscordStageInstanceCreated = nameof(OnDiscordStageInstanceCreated); - - /// - /// Called when a stage instance is updated - /// - /// void OnDiscordStageInstanceUpdated(StageInstance stage, StageInstance previous, DiscordGuild guild) - /// { - /// Puts("OnDiscordStageInstanceUpdated Works!"); - /// } - /// - /// - public const string OnDiscordStageInstanceUpdated = nameof(OnDiscordStageInstanceUpdated); - - /// - /// Called when a stage instance is deleted - /// - /// void OnDiscordStageInstanceDeleted(StageInstance stage, DiscordGuild guild) - /// { - /// Puts("OnDiscordStageInstanceDeleted Works!"); - /// } - /// - /// - public const string OnDiscordStageInstanceDeleted = nameof(OnDiscordStageInstanceDeleted); - - /// - /// Called when an AutoMod rule is created in a guild - /// - /// void OnDiscordAutoModRuleCreated(AutoModRule rule, DiscordGuild guild) - /// { - /// Puts("OnDiscordAutoModRuleCreated Works!"); - /// } - /// - /// - public const string OnDiscordAutoModRuleCreated = nameof(OnDiscordAutoModRuleCreated); - - /// - /// Called when an AutoMod rule is updated on a guild - /// - /// void OnDiscordAutoModRuleUpdated(AutoModRule rule, DiscordGuild guild) - /// { - /// Puts("OnDiscordAutoModRuleUpdated Works!"); - /// } - /// - /// - public const string OnDiscordAutoModRuleUpdated = nameof(OnDiscordAutoModRuleUpdated); - - /// - /// Called when an AutoMod rule is deleted from a guild - /// - /// void OnDiscordAutoModRuleDeleted(AutoModRule rule, DiscordGuild guild) - /// { - /// Puts("OnDiscordAutoModRuleDeleted Works!"); - /// } - /// - /// - public const string OnDiscordAutoModRuleDeleted = nameof(OnDiscordAutoModRuleDeleted); - - /// - /// Called when an AutoMod rule is executed on a guild - /// - /// void OnDiscordAutoModActionExecuted(AutoModActionExecutionEvent rule, DiscordGuild guild) - /// { - /// Puts("OnDiscordAutoModActionExecuted Works!"); - /// } - /// - /// - public const string OnDiscordAutoModActionExecuted = nameof(OnDiscordAutoModActionExecuted); - - /// - /// Called when we receive an event we do not handle yet. - /// If you need this event, you can listen to it using this hook until we support it - /// Please create an issue on uMod if this error ever occurs - /// - /// void OnDiscordUnhandledCommand(EventPayload payload) - /// { - /// Puts("OnDiscordUnhandledCommand Works!"); - /// } - /// - /// - public const string OnDiscordUnhandledCommand = nameof(OnDiscordUnhandledCommand); - #endregion } + + /// + /// Returns true if the hook is a Discord Extension Global Hook + /// + /// Name of the hook + /// + public static bool IsGlobalHook(string hook) => GlobalHooks.Contains(hook); + + /// + /// Returns true if the hook is a Discord Extension Plugin Hook + /// + /// Name of the hook + /// + public static bool IsPluginHook(string hook) => PluginHooks.Contains(hook); + + /// + /// Returns true if the hook is a Discord Extension Hook + /// + /// Name of the hook + /// + public static bool IsDiscordHook(string hook) => AllHooks.Contains(hook); + + #region Bot Client Hooks + /// + /// Called when the DiscordClient is created on the bot and is ready to use. + /// This is called after the Loaded() hook on the plugin. + /// + /// void OnDiscordClientCreated() + /// { + /// Puts("OnDiscordClientCreated Works!"); + /// } + /// + /// + public const string OnDiscordClientCreated = nameof(OnDiscordClientCreated); + + /// + /// Called when the bot has fully loaded all discord guilds + /// If GatewayIntent.GuildMembers is specified then this hook is delayed until all guild members have been loaded + /// + /// void OnDiscordBotFullyLoaded() + /// { + /// Puts("OnDiscordBotFullyLoaded Works!"); + /// } + /// + /// + public const string OnDiscordBotFullyLoaded = nameof(OnDiscordBotFullyLoaded); + #endregion + + #region Socket Hooks + /// + /// Called when the discord socket connects. + /// + /// void OnDiscordWebsocketOpened() + /// { + /// Puts("OnDiscordWebsocketOpened Works!"); + /// } + /// + /// + public const string OnDiscordWebsocketOpened = nameof(OnDiscordWebsocketOpened); + + /// + /// Called when the web socket is closed for any reason. + /// + /// void OnDiscordWebsocketClosed(string reason, ushort code) + /// { + /// Puts("OnDiscordWebsocketClosed Works!"); + /// } + /// + /// + public const string OnDiscordWebsocketClosed = nameof(OnDiscordWebsocketClosed); + + /// + /// Called when the web socket has an error. + /// + /// void OnDiscordWebsocketErrored(Exception ex, string message) + /// { + /// Puts("OnDiscordWebsocketErrored Works!"); + /// } + /// + /// + public const string OnDiscordWebsocketErrored = nameof(OnDiscordWebsocketErrored); + + /// + /// Called when we receive the heartbeat interval from the websocket + /// + /// void OnDiscordSetupHeartbeat(float heartbeat) + /// { + /// Puts("OnDiscordHeartbeatSent Works!"); + /// } + /// + /// + public const string OnDiscordSetupHeartbeat = nameof(OnDiscordSetupHeartbeat); + + /// + /// Called when a heartbeat is sent over the websocket to discord to keep the connection open + /// + /// void OnDiscordHeartbeatSent() + /// { + /// Puts("OnDiscordHeartbeatSent Works!"); + /// } + /// + /// + public const string OnDiscordHeartbeatSent = nameof(OnDiscordHeartbeatSent); + #endregion + + #region Link Hooks + /// + /// These hooks are called when a player is linked or unlinked using discord link. + /// It will be called for every plugins registered to receive hooks. + /// **Note:** If your plugin supports discord link you should not supply any other hooks as the extension provides them for you. + /// **Note:** Discord Link hooks are considered global hooks and will be called on all plugins regardless of bot + /// + /// void OnDiscordPlayerLinked(IPlayer player, DiscordUser discord) + /// { + /// Puts("OnDiscordPlayerLinked Works!"); + /// } + /// + /// + public const string OnDiscordPlayerLinked = nameof(OnDiscordPlayerLinked); + + /// + /// Called when a player is being unlinked from DiscordLink Library + /// This is called before the unlink occurs + /// + /// void OnDiscordPlayerUnlink(IPlayer player, DiscordUser discord) + /// { + /// Puts("OnDiscordPlayerUnlink Works!"); + /// } + /// + /// + public const string OnDiscordPlayerUnlink = nameof(OnDiscordPlayerUnlink); + + /// + /// Called when a player has unlinked their discord and player together using the DiscordLink library + /// + /// void OnDiscordPlayerUnlinked(IPlayer player, DiscordUser discord) + /// { + /// Puts("OnDiscordPlayerUnlinked Works!"); + /// } + /// + /// + public const string OnDiscordPlayerUnlinked = nameof(OnDiscordPlayerUnlinked); + #endregion + + #region Discord Event Hooks + /// + /// - Called when the Discord Bot has successfully connected to the gateway and identified successfully. + /// **Note:** Only partial guild information is available at this point. + /// If you need full guild listen for [OnDiscordGuildCreated](#OnDiscordGuildCreated) hook + /// If you need full guild member list listen for [OnDiscordGuildMembersLoaded](#OnDiscordGuildMembersLoaded) + /// + /// void OnDiscordGatewayReady(GatewayReadyEvent ready) + /// { + /// Puts("OnDiscordGatewayReady Works!"); + /// } + /// + /// + public const string OnDiscordGatewayReady = nameof(OnDiscordGatewayReady); + + /// + /// Called when the websocket has reconnected to the websocket and resumed the previous session + /// + /// void OnDiscordGatewayResumed(GatewayResumedEvent resume) + /// { + /// Puts("OnDiscordGatewayResumed Works!"); + /// } + /// + /// + public const string OnDiscordGatewayResumed = nameof(OnDiscordGatewayResumed); + + /// + /// Called when the websocket has reconnected + /// + /// void OnDiscordGatewayReconnected() + /// { + /// Puts("OnDiscordGatewayReconnected Works!"); + /// } + /// + /// + public const string OnDiscordGatewayReconnected = nameof(OnDiscordGatewayReconnected); + + /// + /// Called when a direct message (DM) channel has been created. + /// + /// void OnDiscordDirectChannelCreated(DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectChannelCreated Works!"); + /// } + /// + /// + public const string OnDiscordDirectChannelCreated = nameof(OnDiscordDirectChannelCreated); + + /// + /// Called when a channel has been created in a guild. + /// + /// void OnDiscordGuildChannelCreated(DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildChannelCreated Works!"); + /// } + /// + /// + public const string OnDiscordGuildChannelCreated = nameof(OnDiscordGuildChannelCreated); + + /// + /// Called when a direct message (DM) channel has been updated. + /// + /// Note: previous will be null if previous channel not found + /// void OnDiscordDirectChannelUpdated(DiscordChannel channel, DiscordChannel previous) + /// { + /// Puts("OnDiscordDirectChannelUpdated Works!"); + /// } + /// + /// + public const string OnDiscordDirectChannelUpdated = nameof(OnDiscordDirectChannelUpdated); + + /// + /// Called when a channel has been updated in a guild. + /// + /// void OnDiscordGuildChannelUpdated(DiscordChannel channel, DiscordChannel previous, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildChannelUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildChannelUpdated = nameof(OnDiscordGuildChannelUpdated); + + /// + /// Called when a direct message (DM) channel has been deleted. + /// Not sure if this is possible for DM channels + /// + /// Note: Not sure if this will ever happen but we handle it if it does + /// void OnDiscordDirectChannelDeleted(DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectChannelDeleted Works!"); + /// } + /// + /// + public const string OnDiscordDirectChannelDeleted = nameof(OnDiscordDirectChannelDeleted); + + /// + /// Called when a channel has been deleted in a guild. + /// + /// void OnDiscordGuildChannelDeleted(DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildChannelDeleted Works!"); + /// } + /// + /// + public const string OnDiscordGuildChannelDeleted = nameof(OnDiscordGuildChannelDeleted); + + /// + /// Called when a direct message (DM) channel has it's pinned messages updated. + /// Channel may be null if we haven't seen it before. + /// + /// void OnDiscordDirectChannelPinsUpdated(ChannelPinsUpdatedEvent update, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectChannelPinsUpdated Works!"); + /// } + /// + /// + public const string OnDiscordDirectChannelPinsUpdated = nameof(OnDiscordDirectChannelPinsUpdated); + + /// + /// Called when an entitlement has been created + /// + /// void OnDiscordEntitlementCreated(DiscordEntitlement entitlement, DiscordGuild guild) + /// { + /// Puts("OnDiscordEntitlementCreated Works!"); + /// } + /// + /// + public const string OnDiscordEntitlementCreated = nameof(OnDiscordEntitlementCreated); + + /// + /// Called when an entitlement has been update + /// + /// void OnDiscordEntitlementUpdated(DiscordEntitlement entitlement, DiscordGuild guild) + /// { + /// Puts("OnDiscordEntitlementUpdated Works!"); + /// } + /// + /// + public const string OnDiscordEntitlementUpdated = nameof(OnDiscordEntitlementUpdated); + + /// + /// Called when an entitlement has been deleted + /// + /// void OnDiscordEntitlementDeleted(DiscordEntitlement entitlement, DiscordGuild guild) + /// { + /// Puts("OnDiscordEntitlementDeleted Works!"); + /// } + /// + /// + public const string OnDiscordEntitlementDeleted = nameof(OnDiscordEntitlementDeleted); + + /// + /// Called when a guild channel has it's pinned messages updated + /// + /// void OnDiscordGuildChannelPinsUpdated(ChannelPinsUpdatedEvent update, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildChannelPinsUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildChannelPinsUpdated = nameof(OnDiscordGuildChannelPinsUpdated); + + /// + /// Called when a discord server is fully loaded while connecting or the bot has joined a new discord server + /// + /// void OnDiscordGuildCreated(GuildDiscordGuild guild) + /// { + /// Puts("OnDiscordGuildCreated Works!"); + /// } + /// + /// + public const string OnDiscordGuildCreated = nameof(OnDiscordGuildCreated); + + /// + /// Called when any updates are made to a guild + /// Note: previous will be null if guild previously not loaded + /// + /// void OnDiscordGuildUpdated(DiscordGuild guild, DiscordGuild previous) + /// { + /// Puts("OnDiscordGuildUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildUpdated = nameof(OnDiscordGuildUpdated); + + /// + /// Called when a guild become unavailable due to a network outage + /// + /// void OnDiscordGuildUnavailable(DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildUnavailable Works!"); + /// } + /// + /// + public const string OnDiscordGuildUnavailable = nameof(OnDiscordGuildUnavailable); + + /// + /// Called when a bot is removed from a discord server or that discord server was deleted + /// + /// void OnDiscordGuildDeleted(DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildDeleted Works!"); + /// } + /// + /// + public const string OnDiscordGuildDeleted = nameof(OnDiscordGuildDeleted); + + /// + /// Called when a guild member is banned + /// + /// void OnDiscordGuildMemberBanned(GuildMemberBannedEvent ban, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberBanned Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberBanned = nameof(OnDiscordGuildMemberBanned); + + /// + /// Called when a guild member is unbanned + /// + /// void OnDiscordGuildMemberUnbanned(GuildMemberBannedEvent ban, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildBanRemoved Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberUnbanned = nameof(OnDiscordGuildMemberUnbanned); + + /// + /// Called when the custom emojis for a guild are created/updated/deleted + /// + /// void OnDiscordGuildEmojisUpdated(GuildEmojisUpdatedEvent emojis, Hash<Snowflake, DiscordEmoji> previous, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildEmojisUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildEmojisUpdated = nameof(OnDiscordGuildEmojisUpdated); + + /// + /// Called when the guild stickers are updated + /// + /// void OnDiscordGuildStickersUpdated(GuildStickersUpdatedEvent stickers, Hash<Snowflake, DiscordSticker> previous, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildStickersUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildStickersUpdated = nameof(OnDiscordGuildStickersUpdated); + + /// + /// Called when a guild integration is updated + /// + /// void OnDiscordGuildIntegrationsUpdated(GuildIntegrationsUpdatedEvent integration, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildIntegrationsUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildIntegrationsUpdated = nameof(OnDiscordGuildIntegrationsUpdated); + + /// + /// Called when a guild member has been added to the guild + /// + /// void OnDiscordGuildMemberAdded(GuildMemberAddedEvent member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberAdded Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberAdded = nameof(OnDiscordGuildMemberAdded); + + /// + /// Called when a guild member has been removed from the guild + /// + /// void OnDiscordGuildMemberRemoved(GuildMemberRemovedEvent member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberRemoved Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberRemoved = nameof(OnDiscordGuildMemberRemoved); + + /// + /// Called when a guild member has been updated + /// This also include when the DiscordUser is updated as well + /// + /// void OnDiscordGuildMemberUpdated(GuildMemberUpdatedEvent member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberUpdated = nameof(OnDiscordGuildMemberUpdated); + + /// + /// Called when a guild member nickname has been updated + /// + /// void OnDiscordGuildMemberNicknameUpdated(GuildMember member, string oldNickname, string newNickname, DateTime? lastNicknameUpdate, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberNicknameUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberNicknameUpdated = nameof(OnDiscordGuildMemberNicknameUpdated); + + /// + /// Called when a guild member avatar has been updated + /// + /// void OnDiscordGuildMemberAvatarUpdated(GuildMember member, string oldAvatar, string newAvatar, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberAvatarUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberAvatarUpdated = nameof(OnDiscordGuildMemberAvatarUpdated); + + /// + /// Called when a guild member is deafened + /// + /// void OnDiscordGuildMemberDeafened(GuildMember member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberDeafened Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberDeafened = nameof(OnDiscordGuildMemberDeafened); + + /// + /// Called when a guild member is undeafened + /// + /// void OnDiscordGuildMemberUndeafened(GuildMember member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberUndeafened Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberUndeafened = nameof(OnDiscordGuildMemberUndeafened); + + /// + /// Called when a guild member is muted + /// + /// void OnDiscordGuildMemberMuted(GuildMember member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberMuted Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberMuted = nameof(OnDiscordGuildMemberMuted); + + /// + /// Called when a guild member is unmuted + /// + /// void OnDiscordGuildMemberUnmuted(GuildMember member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberUnmuted Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberUnmuted = nameof(OnDiscordGuildMemberUnmuted); + + /// + /// Called when a guild member is placed in [Timeout](https://support.discord.com/hc/en-us/articles/4413305239191-Time-Out-FAQ) + /// + /// void OnDiscordGuildMemberTimeout(GuildMember member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberTimeout Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberTimeout = nameof(OnDiscordGuildMemberTimeout); + + /// + /// Called when a guild members [Timeout](https://support.discord.com/hc/en-us/articles/4413305239191-Time-Out-FAQ) ends + /// + /// void OnDiscordGuildMemberTimeoutEnded(GuildMember member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberTimeoutEnded Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberTimeoutEnded = nameof(OnDiscordGuildMemberTimeoutEnded); + + /// + /// Called when a guild member boosts the server + /// + /// void OnDiscordGuildMemberBoosted(GuildMember member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberBoosted Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberBoosted = nameof(OnDiscordGuildMemberBoosted); + + /// + /// Called when a guild member extends their boost + /// + /// void OnDiscordGuildMemberBoostExtended(GuildMember member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberBoostExtended Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberBoostExtended = nameof(OnDiscordGuildMemberBoostExtended); + + /// + /// Called when a guild member boost ends + /// + /// void OnDiscordGuildMemberBoostEnded(GuildMember member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberBoostEnded Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberBoostEnded = nameof(OnDiscordGuildMemberBoostEnded); + + /// + /// Called when a role is added to a guild member + /// + /// void OnDiscordGuildMemberRoleAdded(GuildMember member, Snowflake roleId, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberRoleAdded Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberRoleAdded = nameof(OnDiscordGuildMemberRoleAdded); + + /// + /// Called when a role is removed from a guild member + /// + /// void OnDiscordGuildMemberRoleRemoved(GuildMember member, Snowflake roleId, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberRoleRemoved Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberRoleRemoved = nameof(OnDiscordGuildMemberRoleRemoved); + + /// + /// Called when a guild has finished loading all guild members + /// This Discord Extension requests all guild members in the [OnDiscordGuildCreated](#ondiscordguildcreated) Hook + /// + /// void OnDiscordGuildMembersLoaded(DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMembersLoaded Works!"); + /// } + /// + /// + public const string OnDiscordGuildMembersLoaded = nameof(OnDiscordGuildMembersLoaded); + + /// + /// Called in a response to a request for guild member chunks + /// + /// void OnDiscordGuildMembersChunk(GuildMembersChunkEvent chunk, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMembersChunk Works!"); + /// } + /// + /// + public const string OnDiscordGuildMembersChunk = nameof(OnDiscordGuildMembersChunk); + + /// + /// Called when a discord guild role is created + /// + /// void OnDiscordGuildRoleCreated(DiscordRole role, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildRoleCreated Works!"); + /// } + /// + /// + public const string OnDiscordGuildRoleCreated = nameof(OnDiscordGuildRoleCreated); + + /// + /// Called when a discord guild role is updated + /// + /// void OnDiscordGuildRoleUpdated(DiscordRole role, DiscordRole previous, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildRoleUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildRoleUpdated = nameof(OnDiscordGuildRoleUpdated); + + /// + /// Called when a discord guild role is deleted + /// + /// void OnDiscordGuildRoleDeleted(DiscordRole role, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildRoleDeleted Works!"); + /// } + /// + /// + public const string OnDiscordGuildRoleDeleted = nameof(OnDiscordGuildRoleDeleted); + + /// + /// Called when a discord guild scheduled event is created + /// + /// void OnDiscordGuildScheduledEventCreated(GuildScheduledEvent guildEvent, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildScheduledEventCreated Works!"); + /// } + /// + /// + public const string OnDiscordGuildScheduledEventCreated = nameof(OnDiscordGuildScheduledEventCreated); + + /// + /// Called when a discord guild scheduled event is updated + /// + /// void OnDiscordGuildScheduledEventUpdated(GuildScheduledEvent guildEvent, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildScheduledEventUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildScheduledEventUpdated = nameof(OnDiscordGuildScheduledEventUpdated); + + /// + /// Called when a discord guild scheduled event is deleted + /// + /// void OnDiscordGuildScheduledEventDeleted(GuildScheduledEvent guildEvent, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildScheduledEventDeleted Works!"); + /// } + /// + /// + public const string OnDiscordGuildScheduledEventDeleted = nameof(OnDiscordGuildScheduledEventDeleted); + + /// + /// Called when a discord user is added to a guild scheduled event + /// + /// void OnDiscordGuildScheduledEventUserAdded(GuildScheduleEventUserAddedEvent added, GuildScheduledEvent, scheduledEvent, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildScheduledEventUserAdded Works!"); + /// } + /// + /// + public const string OnDiscordGuildScheduledEventUserAdded = nameof(OnDiscordGuildScheduledEventUserAdded); + + /// + /// Called when a discord user is removed from a guild scheduled event + /// + /// void OnDiscordGuildScheduledEventUserRemoved(GuildScheduleEventUserRemovedEvent removed, GuildScheduledEvent, scheduledEvent, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildScheduledEventUserRemoved Works!"); + /// } + /// + /// + public const string OnDiscordGuildScheduledEventUserRemoved = nameof(OnDiscordGuildScheduledEventUserRemoved); + + /// + /// Called when a message is created in a direct message channel + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectMessageCreated(DiscordMessage message, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectMessageCreated Works!"); + /// } + /// + /// + public const string OnDiscordDirectMessageCreated = nameof(OnDiscordDirectMessageCreated); + + /// + /// Called when a message is created in a guild channel + /// + /// void OnDiscordGuildMessageCreated(DiscordMessage message, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMessageCreated Works!"); + /// } + /// + /// + public const string OnDiscordGuildMessageCreated = nameof(OnDiscordGuildMessageCreated); + + /// + /// Called when a message is updated in a direct message channel + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectMessageUpdated(DiscordMessage message, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectMessageUpdated Works!"); + /// } + /// + /// + public const string OnDiscordDirectMessageUpdated = nameof(OnDiscordDirectMessageUpdated); + + /// + /// Called when a message is updated in a guild channel + /// + /// void OnDiscordDirectMessageUpdated(DiscordMessage message, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectMessageUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildMessageUpdated = nameof(OnDiscordGuildMessageUpdated); + + /// + /// Called when a message is deleted in a direct message channel + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectMessageDeleted(DiscordMessage message, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectMessageDeleted Works!"); + /// } + /// + /// + public const string OnDiscordDirectMessageDeleted = nameof(OnDiscordDirectMessageDeleted); + + /// + /// Called when a message is deleted in a guild channel + /// + /// void OnDiscordGuildMessageDeleted(DiscordMessage message, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMessageDeleted Works!"); + /// } + /// + /// + public const string OnDiscordGuildMessageDeleted = nameof(OnDiscordGuildMessageDeleted); + + /// + /// Called when a message is deleted in a direct message channel + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectMessagesBulkDeleted(List<Snowflake> messageIds, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectMessagesBulkDeleted Works!"); + /// } + /// + /// + public const string OnDiscordDirectMessagesBulkDeleted = nameof(OnDiscordDirectMessagesBulkDeleted); + + /// + /// Called when a message is deleted in a guild channel + /// + /// void OnDiscordGuildMessagesBulkDeleted(List<Snowflake> messageIds, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMessagesBulkDeleted Works!"); + /// } + /// + /// + public const string OnDiscordGuildMessagesBulkDeleted = nameof(OnDiscordDirectMessagesBulkDeleted); + + /// + /// Called when a reaction is added to a message in a direct message channel + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectMessageReactionAdded(MessageReactionAddedEvent reaction, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectMessageReactionAdded Works!"); + /// } + /// + /// + public const string OnDiscordDirectMessageReactionAdded = nameof(OnDiscordDirectMessageReactionAdded); + + /// + /// Called when a reaction is added to a message in a guild channel + /// + /// void OnDiscordGuildMessageReactionAdded(MessageReactionAddedEvent reaction, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMessageReactionAdded Works!"); + /// } + /// + /// + public const string OnDiscordGuildMessageReactionAdded = nameof(OnDiscordGuildMessageReactionAdded); + + /// + /// Called when a reaction is removed from a message in a direct message channel + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectMessageReactionRemoved(MessageReactionRemovedEvent reaction, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectMessageReactionRemoved Works!"); + /// } + /// + /// + public const string OnDiscordDirectMessageReactionRemoved = nameof(OnDiscordDirectMessageReactionRemoved); + + /// + /// Called when a reaction is removed from a message in a guild channel + /// + /// void OnDiscordGuildMessageReactionRemoved(MessageReactionRemovedEvent reaction, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMessageReactionRemoved Works!"); + /// } + /// + /// + public const string OnDiscordGuildMessageReactionRemoved = nameof(OnDiscordGuildMessageReactionRemoved); + + /// + /// Called when all reactions are removed from a message in a direct message channel + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectMessageReactionRemovedAll(MessageReactionRemovedAllEmojiEvent reaction, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectMessageReactionRemovedAll Works!"); + /// } + /// + /// + public const string OnDiscordDirectMessageReactionRemovedAll = nameof(OnDiscordDirectMessageReactionRemoved); + + /// + /// Called when all reactions are removed from a message in a guild channel + /// + /// void OnDiscordGuildMessageReactionRemovedAll(MessageReactionRemovedAllEmojiEvent reaction, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMessageReactionRemovedAll Works!"); + /// } + /// + /// + public const string OnDiscordGuildMessageReactionRemovedAll = nameof(OnDiscordGuildMessageReactionRemoved); + + /// + /// Called when all of a specific reactions is removed from a message in a direct message channel + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectMessageReactionEmojiRemoved(MessageReactionRemovedAllEmojiEvent reaction, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectMessageReactionEmojiRemoved Works!"); + /// } + /// + /// + public const string OnDiscordDirectMessageReactionEmojiRemoved = nameof(OnDiscordDirectMessageReactionEmojiRemoved); + + /// + /// Called when all of a specific reaction is removed from a message in a guild channel + /// + /// void OnDiscordGuildMessageReactionEmojiRemoved(MessageReactionRemovedAllEmojiEvent reaction, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMessageReactionEmojiRemoved Works!"); + /// } + /// + /// + public const string OnDiscordGuildMessageReactionEmojiRemoved = nameof(OnDiscordGuildMessageReactionEmojiRemoved); + + /// + /// Called when a guild members presence is updated + /// + /// void OnDiscordGuildMemberPresenceUpdated(PresenceUpdatedEvent update, GuildMember member, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildMemberPresenceUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildMemberPresenceUpdated = nameof(OnDiscordGuildMemberPresenceUpdated); + + /// + /// Called typing starts in a direct message channel + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectTypingStarted(TypingStartedEvent typing, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectTypingStarted Works!"); + /// } + /// + /// + public const string OnDiscordDirectTypingStarted = nameof(OnDiscordDirectTypingStarted); + + /// + /// Called when typing starts in a guild channel + /// + /// void OnDiscordGuildTypingStarted(TypingStartedEvent typing, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildTypingStarted Works!"); + /// } + /// + /// + public const string OnDiscordGuildTypingStarted = nameof(OnDiscordGuildTypingStarted); + + /// + /// Called when a discord user is updated + /// + /// void OnDiscordUserUpdated(DiscordUser user) + /// { + /// Puts("OnDiscordUserUpdated Works!"); + /// } + /// + /// + public const string OnDiscordUserUpdated = nameof(OnDiscordUserUpdated); + + /// + /// Called when the voice state in a direct message channel is updated + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectVoiceStateUpdated(VoiceState voice, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectVoiceStateUpdated Works!"); + /// } + /// + /// + public const string OnDiscordDirectVoiceStateUpdated = nameof(OnDiscordDirectVoiceStateUpdated); + + /// + /// Called when the voice state in a guild channel is updated + /// + /// void OnDiscordGuildVoiceStateUpdated(VoiceState voice, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildVoiceStateUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildVoiceStateUpdated = nameof(OnDiscordGuildVoiceStateUpdated); + + /// + /// Called when the voice server in a guild channel is updated + /// + /// void OnDiscordGuildVoiceServerUpdated(VoiceServerUpdatedEvent voice, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildVoiceServerUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildVoiceServerUpdated = nameof(OnDiscordGuildVoiceServerUpdated); + + /// + /// Called when a webhook ins a guild is updated + /// + /// void OnDiscordGuildWebhookUpdated(WebhooksUpdatedEvent webhook, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildWebhookUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildWebhookUpdated = nameof(OnDiscordGuildWebhookUpdated); + + /// + /// Called when an invite to a direct message channel is created + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectInviteCreated(InviteCreatedEvent invite, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectInviteCreated Works!"); + /// } + /// + /// + public const string OnDiscordDirectInviteCreated = nameof(OnDiscordDirectInviteCreated); + + /// + /// Called when an invite to a guild channel is created + /// + /// void OnDiscordGuildInviteCreated(InviteCreatedEvent invite, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildInviteCreated Works!"); + /// } + /// + /// + public const string OnDiscordGuildInviteCreated = nameof(OnDiscordGuildInviteCreated); + + /// + /// Called when an invite to a direct message channel is deleted + /// `channel` may be null if we haven't seen it yet + /// + /// void OnDiscordDirectInviteDeleted(InviteCreatedEvent invite, DiscordChannel channel) + /// { + /// Puts("OnDiscordDirectInviteDeleted Works!"); + /// } + /// + /// + public const string OnDiscordDirectInviteDeleted = nameof(OnDiscordDirectInviteDeleted); + + /// + /// Called when an invite to a guild channel is deleted + /// + /// void OnDiscordGuildInviteDeleted(InviteCreatedEvent invite, DiscordChannel channel, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildInviteDeleted Works!"); + /// } + /// + /// + public const string OnDiscordGuildInviteDeleted = nameof(OnDiscordGuildInviteDeleted); + + /// + /// Called when the bots application command permission have been updated + /// + /// void OnDiscordApplicationCommandPermissionsUpdated(CommandPermissions permissions) + /// { + /// Puts("OnDiscordInteractionCreated Works!"); + /// } + /// + /// + public const string OnDiscordApplicationCommandPermissionsUpdated = nameof(OnDiscordApplicationCommandPermissionsUpdated); + + /// + /// Called when a discord interaction occurs by a user + /// + /// void OnDiscordInteractionCreated(DiscordInteraction interaction) + /// { + /// Puts("OnDiscordInteractionCreated Works!"); + /// } + /// + /// + public const string OnDiscordInteractionCreated = nameof(OnDiscordInteractionCreated); + + /// + /// Called when a new integration is created a guild + /// + /// void OnDiscordGuildIntegrationCreated(IntegrationCreatedEvent integration, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildIntegrationCreated Works!"); + /// } + /// + /// + public const string OnDiscordGuildIntegrationCreated = nameof(OnDiscordGuildIntegrationCreated); + + /// + /// Called when an integration is updated on a guild + /// + /// void OnDiscordGuildIntegrationUpdated(IntegrationUpdatedEvent interaction, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildIntegrationUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildIntegrationUpdated = nameof(OnDiscordGuildIntegrationUpdated); + + /// + /// Called when an integration is deleted on a guild + /// + /// void OnDiscordGuildIntegrationDeleted(IntegrationDeletedEvent interaction, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildIntegrationDeleted Works!"); + /// } + /// + /// + public const string OnDiscordGuildIntegrationDeleted = nameof(OnDiscordGuildIntegrationDeleted); + + /// + /// Called when a guild thread is created + /// + /// void OnDiscordGuildThreadCreated(DiscordChannel thread, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildThreadCreated Works!"); + /// } + /// + /// + public const string OnDiscordGuildThreadCreated = nameof(OnDiscordGuildThreadCreated); + + /// + /// Called when a guild thread is updated + /// + /// void OnDiscordGuildThreadUpdated(DiscordChannel thread, DiscordChannel previous, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildThreadUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildThreadUpdated = nameof(OnDiscordGuildThreadUpdated); + + /// + /// Called when a guild thread is deleted + /// + /// void OnDiscordGuildThreadDeleted(DiscordChannel thread, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildThreadDeleted Works!"); + /// } + /// + /// + public const string OnDiscordGuildThreadDeleted = nameof(OnDiscordGuildThreadDeleted); + + /// + /// Called when a guild thread list is synced + /// + /// void OnDiscordGuildThreadListSynced(ThreadListSyncEvent sync, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildThreadListSynced Works!"); + /// } + /// + /// + public const string OnDiscordGuildThreadListSynced = nameof(OnDiscordGuildThreadListSynced); + + /// + /// Called when a thread member is updated + /// + /// void OnDiscordGuildThreadMemberUpdated(ThreadMember member, DiscordChannel thread, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildThreadMemberUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildThreadMemberUpdated = nameof(OnDiscordGuildThreadMemberUpdated); + + /// + /// Called when thread members are updated + /// + /// void OnDiscordGuildThreadMembersUpdated(ThreadMembersUpdatedEvent members, DiscordGuild guild) + /// { + /// Puts("OnDiscordGuildThreadMembersUpdated Works!"); + /// } + /// + /// + public const string OnDiscordGuildThreadMembersUpdated = nameof(OnDiscordGuildThreadMembersUpdated); + + /// + /// Called when a stage instance is created + /// + /// void OnDiscordStageInstanceCreated(StageInstance stage, DiscordGuild guild) + /// { + /// Puts("OnDiscordStageInstanceCreated Works!"); + /// } + /// + /// + public const string OnDiscordStageInstanceCreated = nameof(OnDiscordStageInstanceCreated); + + /// + /// Called when a stage instance is updated + /// + /// void OnDiscordStageInstanceUpdated(StageInstance stage, StageInstance previous, DiscordGuild guild) + /// { + /// Puts("OnDiscordStageInstanceUpdated Works!"); + /// } + /// + /// + public const string OnDiscordStageInstanceUpdated = nameof(OnDiscordStageInstanceUpdated); + + /// + /// Called when a stage instance is deleted + /// + /// void OnDiscordStageInstanceDeleted(StageInstance stage, DiscordGuild guild) + /// { + /// Puts("OnDiscordStageInstanceDeleted Works!"); + /// } + /// + /// + public const string OnDiscordStageInstanceDeleted = nameof(OnDiscordStageInstanceDeleted); + + /// + /// Called when an AutoMod rule is created in a guild + /// + /// void OnDiscordAutoModRuleCreated(AutoModRule rule, DiscordGuild guild) + /// { + /// Puts("OnDiscordAutoModRuleCreated Works!"); + /// } + /// + /// + public const string OnDiscordAutoModRuleCreated = nameof(OnDiscordAutoModRuleCreated); + + /// + /// Called when an AutoMod rule is updated on a guild + /// + /// void OnDiscordAutoModRuleUpdated(AutoModRule rule, DiscordGuild guild) + /// { + /// Puts("OnDiscordAutoModRuleUpdated Works!"); + /// } + /// + /// + public const string OnDiscordAutoModRuleUpdated = nameof(OnDiscordAutoModRuleUpdated); + + /// + /// Called when an AutoMod rule is deleted from a guild + /// + /// void OnDiscordAutoModRuleDeleted(AutoModRule rule, DiscordGuild guild) + /// { + /// Puts("OnDiscordAutoModRuleDeleted Works!"); + /// } + /// + /// + public const string OnDiscordAutoModRuleDeleted = nameof(OnDiscordAutoModRuleDeleted); + + /// + /// Called when an AutoMod rule is executed on a guild + /// + /// void OnDiscordAutoModActionExecuted(AutoModActionExecutionEvent rule, DiscordGuild guild) + /// { + /// Puts("OnDiscordAutoModActionExecuted Works!"); + /// } + /// + /// + public const string OnDiscordAutoModActionExecuted = nameof(OnDiscordAutoModActionExecuted); + + /// + /// Called when we receive an event we do not handle yet. + /// If you need this event, you can listen to it using this hook until we support it + /// Please create an issue on uMod if this error ever occurs + /// + /// void OnDiscordPollVoteAdded(MessagePollVoteAddedEvent vote, DiscordGuild guild) + /// { + /// Puts("OnDiscordPollVoteAdded Works!"); + /// } + /// + /// + public const string OnDiscordPollVoteAdded = nameof(OnDiscordPollVoteAdded); + + /// + /// void OnDiscordAutoModActionExecuted(MessagePollVoteRemovedEvent vote, DiscordGuild guild) + /// { + /// Puts("OnDiscordPollVoteRemoved Works!"); + /// } + /// + public const string OnDiscordPollVoteRemoved = nameof(OnDiscordPollVoteRemoved); + + /// + /// + /// void OnDiscordUnhandledCommand(EventPayload payload) + /// { + /// Puts("OnDiscordUnhandledCommand Works!"); + /// } + /// + /// + public const string OnDiscordUnhandledCommand = nameof(OnDiscordUnhandledCommand); + #endregion } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Constants/DiscordHttpMethods.cs b/Oxide.Ext.Discord/Constants/DiscordHttpMethods.cs index 9b5f0aa34..cf33dc134 100644 --- a/Oxide.Ext.Discord/Constants/DiscordHttpMethods.cs +++ b/Oxide.Ext.Discord/Constants/DiscordHttpMethods.cs @@ -2,29 +2,22 @@ using System.Net.Http; using Oxide.Core.Libraries; -namespace Oxide.Ext.Discord.Constants +namespace Oxide.Ext.Discord.Constants; + +internal static class DiscordHttpMethods { - internal static class DiscordHttpMethods - { - private static readonly HttpMethod Patch = new HttpMethod("PATCH"); + private static readonly HttpMethod Patch = new("PATCH"); - public static HttpMethod GetMethod(RequestMethod method) + public static HttpMethod GetMethod(RequestMethod method) + { + return method switch { - switch (method) - { - case RequestMethod.DELETE: - return HttpMethod.Delete; - case RequestMethod.GET: - return HttpMethod.Get; - case RequestMethod.PATCH: - return Patch; - case RequestMethod.POST: - return HttpMethod.Post; - case RequestMethod.PUT: - return HttpMethod.Put; - default: - throw new ArgumentOutOfRangeException(nameof(method), method, null); - } - } + RequestMethod.DELETE => HttpMethod.Delete, + RequestMethod.GET => HttpMethod.Get, + RequestMethod.PATCH => Patch, + RequestMethod.POST => HttpMethod.Post, + RequestMethod.PUT => HttpMethod.Put, + _ => throw new ArgumentOutOfRangeException(nameof(method), method, null) + }; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Constants/RateLimitHeaders.cs b/Oxide.Ext.Discord/Constants/RateLimitHeaders.cs index b4a51c975..ff38bc680 100644 --- a/Oxide.Ext.Discord/Constants/RateLimitHeaders.cs +++ b/Oxide.Ext.Discord/Constants/RateLimitHeaders.cs @@ -1,48 +1,47 @@ -namespace Oxide.Ext.Discord.Constants +namespace Oxide.Ext.Discord.Constants; + +/// +/// Represents Header Format +/// +public static class RateLimitHeaders { /// - /// Represents Header Format + /// The number of seconds to wait before submitting another request. /// - public static class RateLimitHeaders - { - /// - /// The number of seconds to wait before submitting another request. - /// - public const string RetryAfter = "Retry-After"; + public const string RetryAfter = "Retry-After"; - /// - /// Returned only on HTTP 429 responses if the rate limit encountered is the global rate limit (not per-route) - /// - public const string IsGlobal = "X-RateLimit-Global"; + /// + /// Returned only on HTTP 429 responses if the rate limit encountered is the global rate limit (not per-route) + /// + public const string IsGlobal = "X-RateLimit-Global"; - /// - /// A unique string denoting the rate limit being encountered (non-inclusive of top-level resources in the path) - /// - public const string BucketId = "X-RateLimit-Bucket"; + /// + /// A unique string denoting the rate limit being encountered (non-inclusive of top-level resources in the path) + /// + public const string BucketId = "X-RateLimit-Bucket"; - /// - /// The number of requests that can be made - /// - public const string BucketLimit = "X-RateLimit-Limit"; + /// + /// The number of requests that can be made + /// + public const string BucketLimit = "X-RateLimit-Limit"; - /// - /// The number of remaining requests that can be made - /// - public const string BucketRemaining = "X-RateLimit-Remaining"; + /// + /// The number of remaining requests that can be made + /// + public const string BucketRemaining = "X-RateLimit-Remaining"; - /// - /// Total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond ratelimit precision - /// - public const string BucketResetAfter = "X-RateLimit-Reset-After"; + /// + /// Total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond rate-limit precision + /// + public const string BucketResetAfter = "X-RateLimit-Reset-After"; - /// - /// Epoch time (seconds since 00:00:00 UTC on January 1, 1970) at which the rate limit resets - /// - public const string BucketReset = "X-RateLimit-Reset"; + /// + /// Epoch time (seconds since 00:00:00 UTC on January 1, 1970) at which the rate limit resets + /// + public const string BucketReset = "X-RateLimit-Reset"; - /// - /// Scope of the rate limit - /// - public const string Scope = "X-RateLimit-Scope"; - } + /// + /// Scope of the rate limit + /// + public const string Scope = "X-RateLimit-Scope"; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Data/BaseDataFile.cs b/Oxide.Ext.Discord/Data/BaseDataFile.cs index 32ba254f8..6aa25b239 100644 --- a/Oxide.Ext.Discord/Data/BaseDataFile.cs +++ b/Oxide.Ext.Discord/Data/BaseDataFile.cs @@ -1,26 +1,25 @@ -namespace Oxide.Ext.Discord.Data +namespace Oxide.Ext.Discord.Data; + +internal abstract class BaseDataFile where TData : BaseDataFile, new() { - internal abstract class BaseDataFile where TData : BaseDataFile, new() - { - internal static TData Instance; - internal DataFileInfo FileInfo; + internal static TData Instance; + internal DataFileInfo FileInfo; - internal bool DataUpdated { get; private set; } + internal bool DataUpdated { get; private set; } - internal virtual void OnDataLoaded(DataFileInfo info) - { - FileInfo = info; - } + internal virtual void OnDataLoaded(DataFileInfo info) + { + FileInfo = info; + } - internal void OnDataChanged() - { - DataUpdated = true; - } + internal void OnDataChanged() + { + DataUpdated = true; + } - internal void OnDataSaved() - { - DataUpdated = false; - } + internal void OnDataSaved() + { + DataUpdated = false; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Data/DataFileInfo.cs b/Oxide.Ext.Discord/Data/DataFileInfo.cs index 0cb89a088..0dcf7b7b1 100644 --- a/Oxide.Ext.Discord/Data/DataFileInfo.cs +++ b/Oxide.Ext.Discord/Data/DataFileInfo.cs @@ -1,38 +1,37 @@ using System.IO; -namespace Oxide.Ext.Discord.Data +namespace Oxide.Ext.Discord.Data; + +internal class DataFileInfo { - internal class DataFileInfo - { - public readonly string FilePath; - public readonly int NumBackups; + public readonly string FilePath; + public readonly int NumBackups; - private readonly string[] _backupPaths; + private readonly string[] _backupPaths; + + public DataFileInfo(string fileName, int numBackups) + { + FilePath = Path.Combine(DataHandler.RootPath, fileName); + NumBackups = numBackups; + _backupPaths = new string[numBackups + 1]; + } - public DataFileInfo(string fileName, int numBackups) + public string GetPathForIndex(int index) + { + if (index == 0) { - FilePath = Path.Combine(DataHandler.RootPath, fileName); - NumBackups = numBackups; - _backupPaths = new string[numBackups + 1]; + return FilePath; } - public string GetPathForIndex(int index) + string backup = _backupPaths[index]; + if (backup != null) { - if (index == 0) - { - return FilePath; - } - - string backup = _backupPaths[index]; - if (backup != null) - { - return backup; - } - - backup = $"{FilePath}.{index.ToString()}"; - _backupPaths[index] = backup; - return backup; } + + backup = $"{FilePath}.{index.ToString()}"; + _backupPaths[index] = backup; + + return backup; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Data/DataHandler.cs b/Oxide.Ext.Discord/Data/DataHandler.cs index cbbec8e78..e27a3bfb2 100644 --- a/Oxide.Ext.Discord/Data/DataHandler.cs +++ b/Oxide.Ext.Discord/Data/DataHandler.cs @@ -7,120 +7,117 @@ using Oxide.Ext.Discord.Types; using ProtoBuf; -namespace Oxide.Ext.Discord.Data +namespace Oxide.Ext.Discord.Data; + +internal sealed class DataHandler : Singleton { - internal sealed class DataHandler : Singleton - { - internal static readonly string RootPath = Path.Combine(Interface.Oxide.DataDirectory, "DiscordExtension"); + internal static readonly string RootPath = Path.Combine(Interface.Oxide.DataDirectory, "DiscordExtension"); - private DataHandler() { } + private DataHandler() { } - public void LoadAll() + public void LoadAll() + { + if (!Directory.Exists(RootPath)) { - if (!Directory.Exists(RootPath)) - { - Directory.CreateDirectory(RootPath); - } - - Load(new DataFileInfo("discord.users.data", 2)); - Load(new DataFileInfo("discord.ip.data", 1)); + Directory.CreateDirectory(RootPath); } + + Load(new DataFileInfo("discord.users.data", 2)); + Load(new DataFileInfo("discord.ip.data", 1)); + } - public void OnServerSave() => SaveAll(false); + public void OnServerSave() => SaveAll(false); - public void Shutdown() => SaveAll(true); + public void Shutdown() => SaveAll(true); - private void SaveAll(bool force) - { - Save(DiscordUserData.Instance, force); - Save(DiscordIpData.Instance, force); - } + private void SaveAll(bool force) + { + Save(DiscordUserData.Instance, force); + Save(DiscordIpData.Instance, force); + } - public void Load(DataFileInfo info) where TData : BaseDataFile, new() + public void Load(DataFileInfo info) where TData : BaseDataFile, new() + { + int index = 0; + while (true) { - int index = 0; - while (true) + try { - try + if (index >= info.NumBackups) { - if (index >= info.NumBackups) - { - break; - } - - string path = info.GetPathForIndex(index); - if (!File.Exists(path)) - { - continue; - } - - using (FileStream file = File.OpenRead(path)) - { - TData data = Serializer.Deserialize(file); - if (data != null) - { - BaseDataFile.Instance = data; - data.OnDataLoaded(info); - return; - } - } + break; } - catch (Exception ex) + + string path = info.GetPathForIndex(index); + if (!File.Exists(path)) { - DiscordExtension.GlobalLogger.Exception("An error occured loading the {0} Data File of type {1}", info.FilePath, typeof(TData).FullName, ex); + continue; } - finally + + using FileStream file = File.OpenRead(path); + TData data = Serializer.Deserialize(file); + if (data != null) { - index++; + BaseDataFile.Instance = data; + data.OnDataLoaded(info); + return; } } - - TData newData = new TData(); - newData.OnDataLoaded(info); - BaseDataFile.Instance = newData; + catch (Exception ex) + { + DiscordExtension.GlobalLogger.Exception("An error occured loading the {0} Data File of type {1}", info.FilePath, typeof(TData).FullName, ex); + } + finally + { + index++; + } } + + TData newData = new(); + newData.OnDataLoaded(info); + BaseDataFile.Instance = newData; + } - public void Save(TData data, bool force) where TData : BaseDataFile, new() + public void Save(TData data, bool force) where TData : BaseDataFile, new() + { + if (!data.DataUpdated && !force) { - if (!data.DataUpdated && !force) + return; + } + + DataFileInfo info = data.FileInfo; + + try + { + int numBackups = info.NumBackups; + string path = info.GetPathForIndex(numBackups); + if (File.Exists(path)) { - return; + File.Delete(path); } - - DataFileInfo info = data.FileInfo; - try + for (int i = numBackups - 1; i >= 0; i--) { - int numBackups = info.NumBackups; - string path = info.GetPathForIndex(numBackups); + path = info.GetPathForIndex(i); if (File.Exists(path)) { - File.Delete(path); - } - - for (int i = numBackups - 1; i >= 0; i--) - { - path = info.GetPathForIndex(i); - if (File.Exists(path)) - { - File.Move(path, info.GetPathForIndex(i + 1)); - } + File.Move(path, info.GetPathForIndex(i + 1)); } + } - path = info.GetPathForIndex(0); - FileMode saveMode = File.Exists(path) ? FileMode.Truncate : FileMode.Create; + path = info.GetPathForIndex(0); + FileMode saveMode = File.Exists(path) ? FileMode.Truncate : FileMode.Create; - using (FileStream file = File.Open(path, saveMode)) - { - Serializer.Serialize(file, BaseDataFile.Instance); - } - - data.OnDataSaved(); - } - catch (Exception ex) + using (FileStream file = File.Open(path, saveMode)) { - DiscordExtension.GlobalLogger.Exception("An error occured saving the data file. {0}", typeof(TData).GetRealTypeName(), ex); + Serializer.Serialize(file, BaseDataFile.Instance); } + + data.OnDataSaved(); + } + catch (Exception ex) + { + DiscordExtension.GlobalLogger.Exception("An error occured saving the data file. {0}", typeof(TData).GetRealTypeName(), ex); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Data/Ip/DiscordIpData.cs b/Oxide.Ext.Discord/Data/Ip/DiscordIpData.cs index 365a9d5d8..778f712da 100644 --- a/Oxide.Ext.Discord/Data/Ip/DiscordIpData.cs +++ b/Oxide.Ext.Discord/Data/Ip/DiscordIpData.cs @@ -3,34 +3,33 @@ using Oxide.Ext.Discord.Services.IpApi; using ProtoBuf; -namespace Oxide.Ext.Discord.Data.Ip +namespace Oxide.Ext.Discord.Data.Ip; + +[ProtoContract] +internal sealed class DiscordIpData : BaseDataFile { - [ProtoContract] - internal sealed class DiscordIpData : BaseDataFile - { - [ProtoMember(1)] - private readonly Dictionary _ips = new Dictionary(); + [ProtoMember(1)] + private readonly Dictionary _ips = new(); - public bool HasData(string ip) => _ips.ContainsKey(ip); + public bool HasData(string ip) => _ips.ContainsKey(ip); - public void AddData(string ip, IpResult result) - { - _ips[ip] = new IpData(result); - OnDataChanged(); - } + public void AddData(string ip, IpResult result) + { + _ips[ip] = new IpData(result); + OnDataChanged(); + } - public string GetCountryName(string ip) => _ips.TryGetValue(ip, out IpData data) ? data.CountryName : "Unknown"; - public string GetCountryCode(string ip) => _ips.TryGetValue(ip, out IpData data) ? data.CountryCode : string.Empty; + public string GetCountryName(string ip) => _ips.TryGetValue(ip, out IpData data) ? data.CountryName : "Unknown"; + public string GetCountryCode(string ip) => _ips.TryGetValue(ip, out IpData data) ? data.CountryCode : string.Empty; - internal override void OnDataLoaded(DataFileInfo info) + internal override void OnDataLoaded(DataFileInfo info) + { + base.OnDataLoaded(info); + int count = _ips.Count; + _ips.RemoveAll(ip => ip.IsExpired); + if (count != _ips.Count) { - base.OnDataLoaded(info); - int count = _ips.Count; - _ips.RemoveAll(ip => ip.IsExpired); - if (count != _ips.Count) - { - OnDataChanged(); - } + OnDataChanged(); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Data/Ip/IpData.cs b/Oxide.Ext.Discord/Data/Ip/IpData.cs index 3921674e3..a5f2a27e8 100644 --- a/Oxide.Ext.Discord/Data/Ip/IpData.cs +++ b/Oxide.Ext.Discord/Data/Ip/IpData.cs @@ -3,40 +3,39 @@ using Oxide.Ext.Discord.Services.IpApi; using ProtoBuf; -namespace Oxide.Ext.Discord.Data.Ip +namespace Oxide.Ext.Discord.Data.Ip; + +[ProtoContract] +internal class IpData { - [ProtoContract] - internal class IpData - { - [ProtoMember(1)] - public string CountryCode { get; set; } + [ProtoMember(1)] + public string CountryCode { get; set; } - [ProtoMember(2)] - public string CountryName { get; set; } + [ProtoMember(2)] + public string CountryName { get; set; } - [ProtoMember(3)] - public DateTime CreatedDate { get; set; } + [ProtoMember(3)] + public DateTime CreatedDate { get; set; } - public bool IsExpired + public bool IsExpired + { + get { - get + float duration = DiscordConfig.Instance.Ip.StoreIpDuration; + if (duration < 0) { - float duration = DiscordConfig.Instance.Ip.StoreIpDuration; - if (duration < 0) - { - return false; - } - return DateTime.UtcNow > CreatedDate + TimeSpan.FromDays(duration); + return false; } + return DateTime.UtcNow > CreatedDate + TimeSpan.FromDays(duration); } + } - public IpData() { } + public IpData() { } - public IpData(IpResult result) - { - CountryName = result.Country; - CountryCode = result.CountryCode.ToLower(); - CreatedDate = DateTime.UtcNow; - } + public IpData(IpResult result) + { + CountryName = result.Country; + CountryCode = result.CountryCode.ToLower(); + CreatedDate = DateTime.UtcNow; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Data/Users/BotData.cs b/Oxide.Ext.Discord/Data/Users/BotData.cs index 653efc808..c47fe1bda 100644 --- a/Oxide.Ext.Discord/Data/Users/BotData.cs +++ b/Oxide.Ext.Discord/Data/Users/BotData.cs @@ -2,24 +2,23 @@ using Oxide.Ext.Discord.Entities; using ProtoBuf; -namespace Oxide.Ext.Discord.Data +namespace Oxide.Ext.Discord.Data; + +[ProtoContract] +internal class BotData { - [ProtoContract] - internal class BotData - { - [ProtoMember(1)] - public Dictionary Users { get; set; } = new Dictionary(); + [ProtoMember(1)] + public Dictionary Users { get; set; } = new(); - public UserData GetUserData(Snowflake userId) + public UserData GetUserData(Snowflake userId) + { + if (!Users.TryGetValue(userId, out UserData data)) { - if (!Users.TryGetValue(userId, out UserData data)) - { - data = new UserData(userId); - Users[userId] = data; - DiscordUserData.Instance.OnDataChanged(); - } - - return data; + data = new UserData(userId); + Users[userId] = data; + DiscordUserData.Instance.OnDataChanged(); } + + return data; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Data/Users/DiscordUserData.cs b/Oxide.Ext.Discord/Data/Users/DiscordUserData.cs index ff9d47e66..63dc8bb3c 100644 --- a/Oxide.Ext.Discord/Data/Users/DiscordUserData.cs +++ b/Oxide.Ext.Discord/Data/Users/DiscordUserData.cs @@ -2,26 +2,25 @@ using Oxide.Ext.Discord.Entities; using ProtoBuf; -namespace Oxide.Ext.Discord.Data +namespace Oxide.Ext.Discord.Data; + +[ProtoContract] +internal sealed class DiscordUserData : BaseDataFile { - [ProtoContract] - internal sealed class DiscordUserData : BaseDataFile - { - [ProtoMember(1)] - private Dictionary _bots = new Dictionary(); + [ProtoMember(1)] + private Dictionary _bots = new(); - public bool TryGetBotData(Snowflake id, out BotData data) => _bots.TryGetValue(id, out data); + public bool TryGetBotData(Snowflake id, out BotData data) => _bots.TryGetValue(id, out data); - public BotData GetBotData(Snowflake botId) + public BotData GetBotData(Snowflake botId) + { + if (!_bots.TryGetValue(botId, out BotData data)) { - if (!_bots.TryGetValue(botId, out BotData data)) - { - data = new BotData(); - _bots[botId] = data; - OnDataChanged(); - } - - return data; + data = new BotData(); + _bots[botId] = data; + OnDataChanged(); } + + return data; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Data/Users/UserData.cs b/Oxide.Ext.Discord/Data/Users/UserData.cs index 905551838..fad41d7d2 100644 --- a/Oxide.Ext.Discord/Data/Users/UserData.cs +++ b/Oxide.Ext.Discord/Data/Users/UserData.cs @@ -7,81 +7,80 @@ using Oxide.Plugins; using ProtoBuf; -namespace Oxide.Ext.Discord.Data +namespace Oxide.Ext.Discord.Data; + +[ProtoContract] +internal class UserData { - [ProtoContract] - internal class UserData - { - [ProtoMember(1)] - public Snowflake UserId { get; set; } + [ProtoMember(1)] + public Snowflake UserId { get; set; } - [ProtoMember(2)] - public Snowflake DmChannelId { get; set; } + [ProtoMember(2)] + public Snowflake DmChannelId { get; set; } - [ProtoMember(3)] - public DateTime? DmBlockedDate { get; set; } + [ProtoMember(3)] + public DateTime? DmBlockedDate { get; set; } - //Needed by ProtoBuff - internal UserData() { } + //Needed by ProtoBuff + internal UserData() { } - public UserData(Snowflake userId) + public UserData(Snowflake userId) + { + UserId = userId; + } + + public void ProcessError(DiscordClient client, ResponseError request) + { + ResponseErrorMessage error = request?.DiscordError; + if (error != null && error.Code == 50007) { - UserId = userId; + SetDmBlock(); + DiscordUser user = GetUser(); + client.Logger.Debug("We're unable to send DM's to {0} ({1}). We are blocking attempts until {2}.", user.FullUserName, user.Id, GetBlockedUntil()); + request.SuppressErrorMessage(); } + } - public void ProcessError(DiscordClient client, ResponseError request) + public DiscordChannel CreateDmChannel() + { + return new DiscordChannel { - ResponseErrorMessage error = request?.DiscordError; - if (error != null && error.Code == 50007) + Id = DmChannelId, + Type = ChannelType.Dm, + Recipients = new Hash { - SetDmBlock(); - DiscordUser user = GetUser(); - client.Logger.Debug("We're unable to send DM's to {0} ({1}). We are blocking attempts until {2}.", user.FullUserName, user.Id, GetBlockedUntil()); - request.SuppressErrorMessage(); + [UserId] = GetUser() } - } + }; + } - public DiscordChannel CreateDmChannel() - { - return new DiscordChannel - { - Id = DmChannelId, - Type = ChannelType.Dm, - Recipients = new Hash - { - [UserId] = GetUser() - } - }; - } + public void SetDmBlock() + { + DmBlockedDate = DateTime.UtcNow; + DiscordUserData.Instance.OnDataChanged(); + } - public void SetDmBlock() + public void ClearBlockIfExpired() + { + if (DmBlockedDate.HasValue && DmBlockedDate.Value < DateTime.UtcNow) { - DmBlockedDate = DateTime.UtcNow; + DmBlockedDate = null; DiscordUserData.Instance.OnDataChanged(); } + } - public void ClearBlockIfExpired() - { - if (DmBlockedDate.HasValue && DmBlockedDate.Value < DateTime.UtcNow) - { - DmBlockedDate = null; - DiscordUserData.Instance.OnDataChanged(); - } - } - - public DateTime? GetBlockedUntil() - { - return DmBlockedDate.HasValue ? DmBlockedDate.Value + TimeSpan.FromHours(DiscordConfig.Instance.Users.DmBlockedDuration) : (DateTime?)null; - } + public DateTime? GetBlockedUntil() + { + return DmBlockedDate.HasValue ? DmBlockedDate.Value + TimeSpan.FromHours(DiscordConfig.Instance.Users.DmBlockedDuration) : null; + } - public bool IsDmBlocked() - { - return DmBlockedDate.HasValue && GetBlockedUntil() > DateTime.UtcNow; - } + public bool IsDmBlocked() + { + return DmBlockedDate.HasValue && GetBlockedUntil() > DateTime.UtcNow; + } - public DiscordUser GetUser() - { - return EntityCache.Instance.GetOrCreate(UserId); - } + public DiscordUser GetUser() + { + return EntityCache.Instance.GetOrCreate(UserId); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/DiscordExtension.Carbon.cs b/Oxide.Ext.Discord/DiscordExtension.Carbon.cs index b5a43d751..4d379216f 100644 --- a/Oxide.Ext.Discord/DiscordExtension.Carbon.cs +++ b/Oxide.Ext.Discord/DiscordExtension.Carbon.cs @@ -15,123 +15,122 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord +namespace Oxide.Ext.Discord; + +/// +/// Discord Extension that is loaded by Carbon +/// +public class DiscordExtension : ICarbonExtension { /// - /// Discord Extension that is loaded by Carbon + /// Test version information if using a test version /// - public class DiscordExtension : ICarbonExtension - { - /// - /// Test version information if using a test version - /// - internal const string TestVersion = ""; + internal const string TestVersion = ""; - internal const string Authors = "PsychoTea & DylanSMR & Tricky & Kirollos & MJSU"; + internal const string Authors = "PsychoTea & DylanSMR & Tricky & Kirollos & MJSU"; - /// - /// Version number of the extension - /// - internal static VersionNumber ExtensionVersion; + /// + /// Version number of the extension + /// + internal static VersionNumber ExtensionVersion; - /// - /// Gets full extension version including test version - /// - internal static string FullExtensionVersion { get; private set; } + /// + /// Gets full extension version including test version + /// + internal static string FullExtensionVersion { get; private set; } - /// - /// Global logger for areas that aren't part of a client connection - /// - internal static ILogger GlobalLogger; + /// + /// Global logger for areas that aren't part of a client connection + /// + internal static ILogger GlobalLogger; - internal static DiscordMessageTemplates DiscordMessageTemplates; - internal static DiscordEmbedTemplates DiscordEmbedTemplates; - internal static DiscordEmbedFieldTemplates DiscordEmbedFieldTemplates; - internal static DiscordModalTemplates DiscordModalTemplates; - internal static DiscordButtonTemplates DiscordButtonTemplates; - internal static DiscordInputTextTemplates DiscordInputTextTemplates; - internal static DiscordSelectMenuTemplates DiscordSelectMenuTemplates; - internal static DiscordCommandLocalizations DiscordCommandLocalizations; + internal static DiscordMessageTemplates DiscordMessageTemplates; + internal static DiscordEmbedTemplates DiscordEmbedTemplates; + internal static DiscordEmbedFieldTemplates DiscordEmbedFieldTemplates; + internal static DiscordModalTemplates DiscordModalTemplates; + internal static DiscordButtonTemplates DiscordButtonTemplates; + internal static DiscordInputTextTemplates DiscordInputTextTemplates; + internal static DiscordSelectMenuTemplates DiscordSelectMenuTemplates; + internal static DiscordCommandLocalizations DiscordCommandLocalizations; - internal static bool IsShuttingDown; + internal static bool IsShuttingDown; - /// - /// Constructor for the extension - /// - public DiscordExtension() - { - AssemblyName assembly = Assembly.GetExecutingAssembly().GetName(); - ExtensionVersion = new VersionNumber(assembly.Version.Major, assembly.Version.Minor, assembly.Version.Build); - FullExtensionVersion = $"{ExtensionVersion}{TestVersion}"; - } + /// + /// Constructor for the extension + /// + public DiscordExtension() + { + AssemblyName assembly = Assembly.GetExecutingAssembly().GetName(); + ExtensionVersion = new VersionNumber(assembly.Version.Major, assembly.Version.Minor, assembly.Version.Build); + FullExtensionVersion = $"{ExtensionVersion}{TestVersion}"; + } - /// - /// Called when mod is loaded - /// - public void OnLoaded(EventArgs args) - { - DiscordConfig.LoadConfig(); + /// + /// Called when mod is loaded + /// + public void OnLoaded(EventArgs args) + { + DiscordConfig.LoadConfig(); - GlobalLogger = DiscordLoggerFactory.Instance.CreateExtensionLogger(string.IsNullOrEmpty(TestVersion) ? DiscordLogLevel.Warning : DiscordLogLevel.Verbose); - GlobalLogger.Info("Using Discord Extension Version: {0}", FullExtensionVersion); + GlobalLogger = DiscordLoggerFactory.Instance.CreateExtensionLogger(string.IsNullOrEmpty(TestVersion) ? DiscordLogLevel.Warning : DiscordLogLevel.Verbose); + GlobalLogger.Info("Using Discord Extension Version: {0}", FullExtensionVersion); - ThreadEx.Initialize(); + ThreadEx.Initialize(); - AppDomain.CurrentDomain.UnhandledException += (sender, exception) => - { - GlobalLogger.Exception("An unhandled exception was thrown!", exception?.ExceptionObject as Exception); - }; + AppDomain.CurrentDomain.UnhandledException += (sender, exception) => + { + GlobalLogger.Exception("An unhandled exception was thrown!", exception?.ExceptionObject as Exception); + }; - new DiscordPool(GlobalLogger); - new DiscordAppCommand(GlobalLogger); - new DiscordLink(GlobalLogger); - new DiscordCommand(DiscordConfig.Instance.Commands.CommandPrefixes, GlobalLogger); - new DiscordSubscriptions(GlobalLogger); - new DiscordLocales(GlobalLogger); - new DiscordPlaceholders(GlobalLogger); + new DiscordPool(GlobalLogger); + new DiscordAppCommand(GlobalLogger); + new DiscordLink(GlobalLogger); + new DiscordCommand(DiscordConfig.Instance.Commands.CommandPrefixes, GlobalLogger); + new DiscordSubscriptions(GlobalLogger); + new DiscordLocales(GlobalLogger); + new DiscordPlaceholders(GlobalLogger); - DiscordMessageTemplates = new DiscordMessageTemplates(GlobalLogger); - DiscordEmbedTemplates = new DiscordEmbedTemplates(GlobalLogger); - DiscordEmbedFieldTemplates = new DiscordEmbedFieldTemplates(GlobalLogger); - DiscordModalTemplates = new DiscordModalTemplates(GlobalLogger); - DiscordCommandLocalizations = new DiscordCommandLocalizations(GlobalLogger); - DiscordButtonTemplates = new DiscordButtonTemplates(GlobalLogger); - DiscordInputTextTemplates = new DiscordInputTextTemplates(GlobalLogger); - DiscordSelectMenuTemplates = new DiscordSelectMenuTemplates(GlobalLogger); + DiscordMessageTemplates = new DiscordMessageTemplates(GlobalLogger); + DiscordEmbedTemplates = new DiscordEmbedTemplates(GlobalLogger); + DiscordEmbedFieldTemplates = new DiscordEmbedFieldTemplates(GlobalLogger); + DiscordModalTemplates = new DiscordModalTemplates(GlobalLogger); + DiscordCommandLocalizations = new DiscordCommandLocalizations(GlobalLogger); + DiscordButtonTemplates = new DiscordButtonTemplates(GlobalLogger); + DiscordInputTextTemplates = new DiscordInputTextTemplates(GlobalLogger); + DiscordSelectMenuTemplates = new DiscordSelectMenuTemplates(GlobalLogger); - EmojiCache.Instance.Build(); + EmojiCache.Instance.Build(); - Community.Runtime.Plugins.AddPlugin(new DiscordExtensionCore()); + Community.Runtime.Plugins.AddPlugin(new DiscordExtensionCore()); - //Interface.Oxide.OnFrame(PromiseTimer.Instance.Update); + //Interface.Oxide.OnFrame(PromiseTimer.Instance.Update); - Interface.Oxide.Config.Compiler.PreprocessorDirectives.AddRange(GetPreProcessorDirectives()); + Interface.Oxide.Config.Compiler.PreprocessorDirectives.AddRange(GetPreProcessorDirectives()); - Interface.Oxide.RootPluginManager.OnPluginAdded += DiscordClientFactory.Instance.OnPluginLoaded; - Interface.Oxide.RootPluginManager.OnPluginRemoved += DiscordClientFactory.Instance.OnPluginUnloaded; - } + Interface.Oxide.RootPluginManager.OnPluginAdded += DiscordClientFactory.Instance.OnPluginLoaded; + Interface.Oxide.RootPluginManager.OnPluginRemoved += DiscordClientFactory.Instance.OnPluginUnloaded; + } - /// - /// Called when server is shutdown - /// - public void OnUnloaded(EventArgs args) - { - DiscordClientFactory.Instance.OnShutdown(); - GlobalLogger.Debug("Disconnected all clients - server shutdown."); - DataHandler.Instance.Shutdown(); - DiscordLoggerFactory.Instance.OnServerShutdown(); - } + /// + /// Called when server is shutdown + /// + public void OnUnloaded(EventArgs args) + { + DiscordClientFactory.Instance.OnShutdown(); + GlobalLogger.Debug("Disconnected all clients - server shutdown."); + DataHandler.Instance.Shutdown(); + DiscordLoggerFactory.Instance.OnServerShutdown(); + } - private IEnumerable GetPreProcessorDirectives() - { - yield return "DiscordExt"; - yield return "DiscordExt3_0"; - } + private IEnumerable GetPreProcessorDirectives() + { + yield return "DiscordExt"; + yield return "DiscordExt3_0"; + } - public void Awake(EventArgs args) - { + public void Awake(EventArgs args) + { - } } } #endif \ No newline at end of file diff --git a/Oxide.Ext.Discord/DiscordExtension.Oxide.cs b/Oxide.Ext.Discord/DiscordExtension.Oxide.cs index 422b933d5..515ce3ca2 100644 --- a/Oxide.Ext.Discord/DiscordExtension.Oxide.cs +++ b/Oxide.Ext.Discord/DiscordExtension.Oxide.cs @@ -14,142 +14,146 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord +namespace Oxide.Ext.Discord; + +/// +/// Discord Extension that is loaded by Oxide +/// +public class DiscordExtension : Extension { /// - /// Discord Extension that is loaded by Oxide + /// Test version information if using a test version /// - public class DiscordExtension : Extension - { - /// - /// Test version information if using a test version - /// - internal const string TestVersion = ""; + internal const string TestVersion = ""; - internal const string Authors = "PsychoTea & DylanSMR & Tricky & Kirollos & MJSU"; + internal const string Authors = "PsychoTea & DylanSMR & Tricky & Kirollos & MJSU"; - /// - /// Version number of the extension - /// - internal static VersionNumber ExtensionVersion; + /// + /// Version number of the extension + /// + internal static VersionNumber ExtensionVersion; - /// - /// Gets full extension version including test version - /// - internal static string FullExtensionVersion { get; private set; } + /// + /// Gets full extension version including test version + /// + internal static string FullExtensionVersion { get; private set; } - /// - /// Global logger for areas that aren't part of a client connection - /// - internal static ILogger GlobalLogger; + /// + /// Global logger for areas that aren't part of a client connection + /// + internal static ILogger GlobalLogger; - internal static DiscordMessageTemplates DiscordMessageTemplates; - internal static DiscordEmbedTemplates DiscordEmbedTemplates; - internal static DiscordEmbedFieldTemplates DiscordEmbedFieldTemplates; - internal static DiscordModalTemplates DiscordModalTemplates; - internal static DiscordButtonTemplates DiscordButtonTemplates; - internal static DiscordInputTextTemplates DiscordInputTextTemplates; - internal static DiscordSelectMenuTemplates DiscordSelectMenuTemplates; - internal static DiscordCommandLocalizations DiscordCommandLocalizations; + internal static DiscordMessageTemplates DiscordMessageTemplates; + internal static DiscordEmbedTemplates DiscordEmbedTemplates; + internal static DiscordEmbedFieldTemplates DiscordEmbedFieldTemplates; + internal static DiscordModalTemplates DiscordModalTemplates; + internal static DiscordButtonTemplates DiscordButtonTemplates; + internal static DiscordInputTextTemplates DiscordInputTextTemplates; + internal static DiscordSelectMenuTemplates DiscordSelectMenuTemplates; + internal static DiscordCommandLocalizations DiscordCommandLocalizations; - internal static bool IsShuttingDown; + internal static bool IsShuttingDown; - /// - /// Constructor for the extension - /// - /// Oxide extension manager - public DiscordExtension(ExtensionManager manager) : base(manager) - { - AssemblyName assembly = Assembly.GetExecutingAssembly().GetName(); - ExtensionVersion = new VersionNumber(assembly.Version.Major, assembly.Version.Minor, assembly.Version.Build); - FullExtensionVersion = $"{ExtensionVersion}{TestVersion}"; - } + /// + /// Constructor for the extension + /// + /// Oxide extension manager + public DiscordExtension(ExtensionManager manager) : base(manager) + { + AssemblyName assembly = Assembly.GetExecutingAssembly().GetName(); + ExtensionVersion = new VersionNumber(assembly.Version.Major, assembly.Version.Minor, assembly.Version.Build); + FullExtensionVersion = $"{ExtensionVersion}{TestVersion}"; + } - /// - /// Name of the extension - /// - public override string Name => "Discord"; + /// + /// Name of the extension + /// + public override string Name => "Discord"; - /// - /// Authors for the extension - /// - public override string Author => Authors; + /// + /// Authors for the extension + /// + public override string Author => Authors; - /// - /// Version number used by oxide - /// - public override VersionNumber Version => ExtensionVersion; + /// + /// Version number used by oxide + /// + public override VersionNumber Version => ExtensionVersion; - /// - /// Called when mod is loaded - /// - public override void OnModLoad() - { - DiscordConfig.LoadConfig(); + /// + /// Called when mod is loaded + /// + public override void OnModLoad() + { + DiscordConfig.LoadConfig(); - GlobalLogger = DiscordLoggerFactory.Instance.CreateExtensionLogger(string.IsNullOrEmpty(TestVersion) ? DiscordLogLevel.Warning : DiscordLogLevel.Verbose); - GlobalLogger.Info("Using Discord Extension Version: {0}", FullExtensionVersion); + GlobalLogger = DiscordLoggerFactory.Instance.CreateExtensionLogger(string.IsNullOrEmpty(TestVersion) ? DiscordLogLevel.Warning : DiscordLogLevel.Verbose); + GlobalLogger.Info("Using Discord Extension Version: {0}", FullExtensionVersion); - ThreadEx.Initialize(); + ThreadEx.Initialize(); - AppDomain.CurrentDomain.UnhandledException += (sender, exception) => - { - GlobalLogger.Exception("An unhandled exception was thrown!", exception?.ExceptionObject as Exception); - }; + AppDomain.CurrentDomain.UnhandledException += (sender, exception) => + { + GlobalLogger.Exception("An unhandled exception was thrown!", exception?.ExceptionObject as Exception); + }; - Manager.RegisterLibrary(nameof(DiscordPool), new DiscordPool(GlobalLogger)); - Manager.RegisterLibrary(nameof(DiscordAppCommand), new DiscordAppCommand(GlobalLogger)); - Manager.RegisterLibrary(nameof(DiscordLink), new DiscordLink(GlobalLogger)); - Manager.RegisterLibrary(nameof(DiscordCommand), new DiscordCommand(DiscordConfig.Instance.Commands.CommandPrefixes, GlobalLogger)); - Manager.RegisterLibrary(nameof(DiscordSubscriptions), new DiscordSubscriptions(GlobalLogger)); - Manager.RegisterLibrary(nameof(DiscordLocales), new DiscordLocales(GlobalLogger)); - Manager.RegisterLibrary(nameof(DiscordPlaceholders), new DiscordPlaceholders(GlobalLogger)); + Manager.RegisterLibrary(nameof(DiscordPool), new DiscordPool(GlobalLogger)); + Manager.RegisterLibrary(nameof(DiscordAppCommand), new DiscordAppCommand(GlobalLogger)); + Manager.RegisterLibrary(nameof(DiscordLink), new DiscordLink(GlobalLogger)); + Manager.RegisterLibrary(nameof(DiscordCommand), new DiscordCommand(DiscordConfig.Instance.Commands.CommandPrefixes, GlobalLogger)); + Manager.RegisterLibrary(nameof(DiscordSubscriptions), new DiscordSubscriptions(GlobalLogger)); + Manager.RegisterLibrary(nameof(DiscordLocales), new DiscordLocales(GlobalLogger)); + Manager.RegisterLibrary(nameof(DiscordPlaceholders), new DiscordPlaceholders(GlobalLogger)); - DiscordMessageTemplates = new DiscordMessageTemplates(GlobalLogger); - DiscordEmbedTemplates = new DiscordEmbedTemplates(GlobalLogger); - DiscordEmbedFieldTemplates = new DiscordEmbedFieldTemplates(GlobalLogger); - DiscordModalTemplates = new DiscordModalTemplates(GlobalLogger); - DiscordCommandLocalizations = new DiscordCommandLocalizations(GlobalLogger); - DiscordButtonTemplates = new DiscordButtonTemplates(GlobalLogger); - DiscordInputTextTemplates = new DiscordInputTextTemplates(GlobalLogger); - DiscordSelectMenuTemplates = new DiscordSelectMenuTemplates(GlobalLogger); + DiscordMessageTemplates = new DiscordMessageTemplates(GlobalLogger); + DiscordEmbedTemplates = new DiscordEmbedTemplates(GlobalLogger); + DiscordEmbedFieldTemplates = new DiscordEmbedFieldTemplates(GlobalLogger); + DiscordModalTemplates = new DiscordModalTemplates(GlobalLogger); + DiscordCommandLocalizations = new DiscordCommandLocalizations(GlobalLogger); + DiscordButtonTemplates = new DiscordButtonTemplates(GlobalLogger); + DiscordInputTextTemplates = new DiscordInputTextTemplates(GlobalLogger); + DiscordSelectMenuTemplates = new DiscordSelectMenuTemplates(GlobalLogger); - Manager.RegisterLibrary(nameof(DiscordMessageTemplates), DiscordMessageTemplates); - Manager.RegisterLibrary(nameof(DiscordEmbedTemplates), DiscordEmbedTemplates); - Manager.RegisterLibrary(nameof(DiscordEmbedFieldTemplates), DiscordEmbedFieldTemplates); - Manager.RegisterLibrary(nameof(DiscordModalTemplates), DiscordModalTemplates); - Manager.RegisterLibrary(nameof(DiscordCommandLocalizations), DiscordCommandLocalizations); - Manager.RegisterLibrary(nameof(DiscordButtonTemplates), DiscordButtonTemplates); - Manager.RegisterLibrary(nameof(DiscordInputTextTemplates), DiscordInputTextTemplates); - Manager.RegisterLibrary(nameof(DiscordSelectMenuTemplates), DiscordSelectMenuTemplates); + Manager.RegisterLibrary(nameof(DiscordMessageTemplates), DiscordMessageTemplates); + Manager.RegisterLibrary(nameof(DiscordEmbedTemplates), DiscordEmbedTemplates); + Manager.RegisterLibrary(nameof(DiscordEmbedFieldTemplates), DiscordEmbedFieldTemplates); + Manager.RegisterLibrary(nameof(DiscordModalTemplates), DiscordModalTemplates); + Manager.RegisterLibrary(nameof(DiscordCommandLocalizations), DiscordCommandLocalizations); + Manager.RegisterLibrary(nameof(DiscordButtonTemplates), DiscordButtonTemplates); + Manager.RegisterLibrary(nameof(DiscordInputTextTemplates), DiscordInputTextTemplates); + Manager.RegisterLibrary(nameof(DiscordSelectMenuTemplates), DiscordSelectMenuTemplates); - EmojiCache.Instance.Build(); + EmojiCache.Instance.Build(); - Manager.RegisterPluginLoader(new DiscordExtPluginLoader()); - //Interface.Oxide.OnFrame(PromiseTimer.Instance.Update); + Manager.RegisterPluginLoader(new DiscordExtPluginLoader()); + //Interface.Oxide.OnFrame(PromiseTimer.Instance.Update); - Interface.Oxide.Config.Compiler.PreprocessorDirectives.AddRange(GetPreProcessorDirectives()); + Interface.Oxide.Config.Compiler.PreprocessorDirectives.AddRange(GetPreProcessorDirectives()); - Interface.Oxide.RootPluginManager.OnPluginAdded += DiscordClientFactory.Instance.OnPluginLoaded; - Interface.Oxide.RootPluginManager.OnPluginRemoved += DiscordClientFactory.Instance.OnPluginUnloaded; - } - - /// - /// Called when server is shutdown - /// - public override void OnShutdown() + Interface.Oxide.RootPluginManager.OnPluginAdded += DiscordClientFactory.Instance.OnPluginLoaded; + Interface.Oxide.RootPluginManager.OnPluginRemoved += plugin => { - DiscordClientFactory.Instance.OnShutdown(); - GlobalLogger.Debug("Disconnected all clients - server shutdown."); - DataHandler.Instance.Shutdown(); - DiscordLoggerFactory.Instance.OnServerShutdown(); - } + DiscordClientFactory.Instance.OnPluginUnloaded(plugin); + //Only remove logger if we actually unload a plugin and not if a client is created. Causes issues with plugin loggers otherwise. + DiscordLoggerFactory.Instance.OnPluginUnloaded(plugin); + }; + } - private IEnumerable GetPreProcessorDirectives() - { - yield return "DiscordExt"; - yield return "DiscordExt3_0"; - } + /// + /// Called when server is shutdown + /// + public override void OnShutdown() + { + DiscordClientFactory.Instance.OnShutdown(); + GlobalLogger.Debug("Disconnected all clients - server shutdown."); + DataHandler.Instance.Shutdown(); + DiscordLoggerFactory.Instance.OnServerShutdown(); + } + + private IEnumerable GetPreProcessorDirectives() + { + yield return "DiscordExt"; + yield return "DiscordExt3_0"; } } #endif \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Activities/ActivityAssets.cs b/Oxide.Ext.Discord/Entities/Activities/ActivityAssets.cs index 6e2ce1e24..fae7fb8da 100644 --- a/Oxide.Ext.Discord/Entities/Activities/ActivityAssets.cs +++ b/Oxide.Ext.Discord/Entities/Activities/ActivityAssets.cs @@ -1,35 +1,34 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Activity Assets +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ActivityAssets { /// - /// Represents Activity Assets + /// The id for a large asset of the activity, usually a snowflake /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ActivityAssets - { - /// - /// The id for a large asset of the activity, usually a snowflake - /// - [JsonProperty("large_image")] - public string LargeImage { get; set; } + [JsonProperty("large_image")] + public string LargeImage { get; set; } - /// - /// Text displayed when hovering over the large image of the activity - /// - [JsonProperty("large_text")] - public string LargeText { get; set; } + /// + /// Text displayed when hovering over the large image of the activity + /// + [JsonProperty("large_text")] + public string LargeText { get; set; } - /// - /// The id for a small asset of the activity, usually a snowflake - /// - [JsonProperty("small_image")] - public string SmallImage { get; set; } + /// + /// The id for a small asset of the activity, usually a snowflake + /// + [JsonProperty("small_image")] + public string SmallImage { get; set; } - /// - /// Text displayed when hovering over the small image of the activity - /// - [JsonProperty("small_text")] - public string SmallText { get; set; } - } + /// + /// Text displayed when hovering over the small image of the activity + /// + [JsonProperty("small_text")] + public string SmallText { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Activities/ActivityButton.cs b/Oxide.Ext.Discord/Entities/Activities/ActivityButton.cs index cc9f0edd0..d26e3ac89 100644 --- a/Oxide.Ext.Discord/Entities/Activities/ActivityButton.cs +++ b/Oxide.Ext.Discord/Entities/Activities/ActivityButton.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Activity Buttons +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ActivityButton { /// - /// Represents Activity Buttons + /// The text shown on the button (1-32 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ActivityButton - { - /// - /// The text shown on the button (1-32 characters) - /// - [JsonProperty("label")] - public string Label { get; set; } + [JsonProperty("label")] + public string Label { get; set; } - /// - /// The url opened when clicking the button (1-512 characters) - /// - [JsonProperty("url")] - public string Url { get; set; } - } + /// + /// The url opened when clicking the button (1-512 characters) + /// + [JsonProperty("url")] + public string Url { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Activities/ActivityFlags.cs b/Oxide.Ext.Discord/Entities/Activities/ActivityFlags.cs index 76bd5b6ea..745775691 100644 --- a/Oxide.Ext.Discord/Entities/Activities/ActivityFlags.cs +++ b/Oxide.Ext.Discord/Entities/Activities/ActivityFlags.cs @@ -1,72 +1,71 @@ using System; using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Activity Flags +/// +[Flags] +public enum ActivityFlags { /// - /// Represents Activity Flags + /// No Actions can be done to this activity /// - [Flags] - public enum ActivityFlags - { - /// - /// No Actions can be done to this activity - /// - [DiscordEnum("NONE")] - None = 0, + [DiscordEnum("NONE")] + None = 0, - /// - /// No Actions can be done to this activity - /// - [DiscordEnum("INSTANCE")] - Instance = 1 << 0, + /// + /// No Actions can be done to this activity + /// + [DiscordEnum("INSTANCE")] + Instance = 1 << 0, - /// - /// Activity can be joined - /// - [DiscordEnum("JOIN")] - Join = 1 << 1, + /// + /// Activity can be joined + /// + [DiscordEnum("JOIN")] + Join = 1 << 1, - /// - /// Activity can be spectated - /// - [DiscordEnum("SPECTATE")] - Spectate = 1 << 2, + /// + /// Activity can be spectated + /// + [DiscordEnum("SPECTATE")] + Spectate = 1 << 2, - /// - /// User may request to join activity - /// - [DiscordEnum("JOIN_REQUEST")] - JoinRequest = 1 << 3, + /// + /// User may request to join activity + /// + [DiscordEnum("JOIN_REQUEST")] + JoinRequest = 1 << 3, - /// - /// User can listen along in spotify - /// - [DiscordEnum("SYNC")] - Sync = 1 << 4, + /// + /// User can listen along in spotify + /// + [DiscordEnum("SYNC")] + Sync = 1 << 4, - /// - /// User can play this song - /// - [DiscordEnum("PLAY")] - Play = 1 << 5, + /// + /// User can play this song + /// + [DiscordEnum("PLAY")] + Play = 1 << 5, - /// - /// User is playing an activity in a voice channel with friends - /// - [DiscordEnum("PARTY_PRIVACY_FRIENDS")] - PartyPrivacyFriends = 1 << 6, + /// + /// User is playing an activity in a voice channel with friends + /// + [DiscordEnum("PARTY_PRIVACY_FRIENDS")] + PartyPrivacyFriends = 1 << 6, - /// - /// User is playing an activity in a voice channel - /// - [DiscordEnum("PARTY_PRIVACY_VOICE_CHANNEL")] - PartyPrivacyVoiceChannel = 1 << 7, + /// + /// User is playing an activity in a voice channel + /// + [DiscordEnum("PARTY_PRIVACY_VOICE_CHANNEL")] + PartyPrivacyVoiceChannel = 1 << 7, - /// - /// User is playing embedded activity - /// - [DiscordEnum("EMBEDDED")] - Embedded = 1 << 8, - } + /// + /// User is playing embedded activity + /// + [DiscordEnum("EMBEDDED")] + Embedded = 1 << 8, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Activities/ActivityParty.cs b/Oxide.Ext.Discord/Entities/Activities/ActivityParty.cs index 09e06216b..76d0ffaa3 100644 --- a/Oxide.Ext.Discord/Entities/Activities/ActivityParty.cs +++ b/Oxide.Ext.Discord/Entities/Activities/ActivityParty.cs @@ -1,34 +1,33 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Activity Party +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ActivityParty { /// - /// Represents Activity Party + /// The id of the party /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ActivityParty - { - /// - /// The id of the party - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Used to show the party's current and maximum size - /// - [JsonProperty("size")] - public List Size { get; set; } + /// + /// Used to show the party's current and maximum size + /// + [JsonProperty("size")] + public List Size { get; set; } - /// - /// The current party size - /// - public int CurrentSize => Size[0]; + /// + /// The current party size + /// + public int CurrentSize => Size[0]; - /// - /// The maximum party size - /// - public int MaxSize => Size[1]; - } + /// + /// The maximum party size + /// + public int MaxSize => Size[1]; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Activities/ActivitySecrets.cs b/Oxide.Ext.Discord/Entities/Activities/ActivitySecrets.cs index f703d83c0..b09375cb2 100644 --- a/Oxide.Ext.Discord/Entities/Activities/ActivitySecrets.cs +++ b/Oxide.Ext.Discord/Entities/Activities/ActivitySecrets.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Activity Secrets +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ActivitySecrets { /// - /// Represents Activity Secrets + /// The secret for joining a party /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ActivitySecrets - { - /// - /// The secret for joining a party - /// - [JsonProperty("join")] - public string Join { get; set; } + [JsonProperty("join")] + public string Join { get; set; } - /// - /// The secret for spectating a game - /// - [JsonProperty("spectate")] - public string Spectate { get; set; } + /// + /// The secret for spectating a game + /// + [JsonProperty("spectate")] + public string Spectate { get; set; } - /// - /// The secret for a specific instanced match - /// - [JsonProperty("match")] - public string Match { get; set; } - } + /// + /// The secret for a specific instanced match + /// + [JsonProperty("match")] + public string Match { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Activities/ActivityTimestamps.cs b/Oxide.Ext.Discord/Entities/Activities/ActivityTimestamps.cs index c2e6ec351..2b04f2621 100644 --- a/Oxide.Ext.Discord/Entities/Activities/ActivityTimestamps.cs +++ b/Oxide.Ext.Discord/Entities/Activities/ActivityTimestamps.cs @@ -2,26 +2,25 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Activity Timestamps +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ActivityTimestamps { /// - /// Represents Activity Timestamps + /// Unix time (in milliseconds) of when the activity started /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ActivityTimestamps - { - /// - /// Unix time (in milliseconds) of when the activity started - /// - [JsonConverter(typeof(UnixDateTimeConverter))] - [JsonProperty("start")] - public DateTimeOffset Start { get; set; } + [JsonConverter(typeof(UnixDateTimeConverter))] + [JsonProperty("start")] + public DateTimeOffset Start { get; set; } - /// - /// Unix time (in milliseconds) of when the activity ends - /// - [JsonConverter(typeof(UnixDateTimeConverter))] - [JsonProperty("end")] - public DateTimeOffset End { get; set; } - } + /// + /// Unix time (in milliseconds) of when the activity ends + /// + [JsonConverter(typeof(UnixDateTimeConverter))] + [JsonProperty("end")] + public DateTimeOffset End { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Activities/ActivityType.cs b/Oxide.Ext.Discord/Entities/Activities/ActivityType.cs index 3b7c44da4..97eaba84e 100644 --- a/Oxide.Ext.Discord/Entities/Activities/ActivityType.cs +++ b/Oxide.Ext.Discord/Entities/Activities/ActivityType.cs @@ -1,26 +1,31 @@ -namespace Oxide.Ext.Discord.Entities +using System; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Activity Types +/// +public enum ActivityType : byte { - /// - /// Represents Activity Types - /// - public enum ActivityType : byte - { - /// Playing {name} - Game = 0, + /// Playing {name} + [Obsolete("This field has been deprecated and will be removed in a future version. Use ActivityType.Playing instead.")] + Game = 0, - /// Streaming {name} - Streaming = 1, + /// Playing {name} + Playing = 0, - /// Listening {name} - Listening = 2, + /// Streaming {name} + Streaming = 1, - /// Watching {name} - Watching = 3, + /// Listening {name} + Listening = 2, - ///{emoji} {name} EX: ":smiley: I am cool" - Custom = 4, + /// Watching {name} + Watching = 3, - /// Competing in {name} - Competing = 5 - } -} + ///{emoji} {name} EX: ":smiley: I am cool" + Custom = 4, + + /// Competing in {name} + Competing = 5 +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Activities/DiscordActivity.cs b/Oxide.Ext.Discord/Entities/Activities/DiscordActivity.cs index 32f62479c..a482ac4a7 100644 --- a/Oxide.Ext.Discord/Entities/Activities/DiscordActivity.cs +++ b/Oxide.Ext.Discord/Entities/Activities/DiscordActivity.cs @@ -4,121 +4,120 @@ using Oxide.Ext.Discord.Helpers; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Activity Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordActivity { /// - /// Represents Activity Structure + /// The activity's name /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordActivity - { - /// - /// The activity's name - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Activity type - /// See - /// - [JsonProperty("type")] - public ActivityType Type { get; set; } + /// + /// Activity type + /// See + /// + [JsonProperty("type")] + public ActivityType Type { get; set; } - /// - /// Stream url is validated when type is 1 - /// - [JsonProperty("url")] - public string Url { get; set; } + /// + /// Stream url is validated when type is 1 + /// + [JsonProperty("url")] + public string Url { get; set; } - /// - /// Timestamp of when the activity was added to the user's session - /// - [JsonConverter(typeof(UnixDateTimeConverter))] - [JsonProperty("created_at")] - public DateTimeOffset CreatedAt { get; set; } + /// + /// Timestamp of when the activity was added to the user's session + /// + [JsonConverter(typeof(UnixDateTimeConverter))] + [JsonProperty("created_at")] + public DateTimeOffset CreatedAt { get; set; } - /// - /// Unix timestamps for start and/or end of the game - /// See - /// - [JsonProperty("timestamps")] - public ActivityTimestamps Timestamps { get; set; } + /// + /// Unix timestamps for start and/or end of the game + /// See + /// + [JsonProperty("timestamps")] + public ActivityTimestamps Timestamps { get; set; } - /// - /// Application id for the game - /// - [JsonProperty("application_id")] - public Snowflake? ApplicationId { get; set; } + /// + /// Application id for the game + /// + [JsonProperty("application_id")] + public Snowflake? ApplicationId { get; set; } - /// - /// What the player is currently doing - /// - [JsonProperty("details")] - public string Details { get; set; } + /// + /// What the player is currently doing + /// + [JsonProperty("details")] + public string Details { get; set; } - /// - /// The user's current party status - /// - [JsonProperty("state")] - public string State { get; set; } + /// + /// The user's current party status + /// + [JsonProperty("state")] + public string State { get; set; } - /// - /// The emoji used for a custom status - /// See - /// - [JsonProperty("emoji")] - public DiscordEmoji Emoji { get; set; } + /// + /// The emoji used for a custom status + /// See + /// + [JsonProperty("emoji")] + public DiscordEmoji Emoji { get; set; } - /// - /// Information for the current party of the player - /// See - /// - [JsonProperty("party")] - public ActivityParty Party { get; set; } + /// + /// Information for the current party of the player + /// See + /// + [JsonProperty("party")] + public ActivityParty Party { get; set; } - /// - /// Images for the presence and their hover texts - /// See - /// - [JsonProperty("assets")] - public ActivityAssets Assets { get; set; } + /// + /// Images for the presence and their hover texts + /// See + /// + [JsonProperty("assets")] + public ActivityAssets Assets { get; set; } - /// - /// Secrets for Rich Presence joining and spectating - /// See - /// - [JsonProperty("secrets")] - public ActivitySecrets Secrets { get; set; } + /// + /// Secrets for Rich Presence joining and spectating + /// See + /// + [JsonProperty("secrets")] + public ActivitySecrets Secrets { get; set; } - /// - /// Whether or not the activity is an instanced game session - /// - [JsonProperty("instance")] - public bool? Instance { get; set; } + /// + /// Whether or not the activity is an instanced game session + /// + [JsonProperty("instance")] + public bool? Instance { get; set; } - /// - /// Describes what the payload includes - /// See - /// - [JsonProperty("flags")] - public ActivityFlags? Flags { get; set; } + /// + /// Describes what the payload includes + /// See + /// + [JsonProperty("flags")] + public ActivityFlags? Flags { get; set; } - /// - /// The custom buttons shown in the Rich Presence (max 2) - /// See - /// - [JsonProperty("buttons")] - public List Buttons { get; set; } + /// + /// The custom buttons shown in the Rich Presence (max 2) + /// See + /// + [JsonProperty("buttons")] + public List Buttons { get; set; } - /// - /// Returns the large image url for the presence asset - /// - public string GetLargeImageUrl => ApplicationId.HasValue ? DiscordCdn.GetApplicationAssetUrl(ApplicationId.Value, Assets.LargeImage) : null; + /// + /// Returns the large image url for the presence asset + /// + public string GetLargeImageUrl => ApplicationId.HasValue ? DiscordCdn.GetApplicationAssetUrl(ApplicationId.Value, Assets.LargeImage) : null; - /// - /// Returns the small image url for the presence asset - /// - public string GetSmallImageUrl => ApplicationId.HasValue ? DiscordCdn.GetApplicationAssetUrl(ApplicationId.Value, Assets.SmallImage) : null; - } + /// + /// Returns the small image url for the presence asset + /// + public string GetSmallImageUrl => ApplicationId.HasValue ? DiscordCdn.GetApplicationAssetUrl(ApplicationId.Value, Assets.SmallImage) : null; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Api/DiscordHttpStatusCode.cs b/Oxide.Ext.Discord/Entities/Api/DiscordHttpStatusCode.cs index 42f408286..e5d8f7c6a 100644 --- a/Oxide.Ext.Discord/Entities/Api/DiscordHttpStatusCode.cs +++ b/Oxide.Ext.Discord/Entities/Api/DiscordHttpStatusCode.cs @@ -1,68 +1,67 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents possible HTTP Codes sent from discord +/// +public enum DiscordHttpStatusCode : ushort { /// - /// Represents possible HTTP Codes sent from discord + /// The request completed successfully. /// - public enum DiscordHttpStatusCode : ushort - { - /// - /// The request completed successfully. - /// - Ok = 200, + Ok = 200, - /// - /// The entity was created successfully. - /// - Created = 201, + /// + /// The entity was created successfully. + /// + Created = 201, - /// - /// The request completed successfully but returned no content. - /// - NoContent = 204, + /// + /// The request completed successfully but returned no content. + /// + NoContent = 204, - /// - /// The entity was not modified (no action was taken). - /// - NotModified = 304, + /// + /// The entity was not modified (no action was taken). + /// + NotModified = 304, - /// - /// The request was improperly formatted, or the server couldn't understand it. - /// - BadRequest = 400, + /// + /// The request was improperly formatted, or the server couldn't understand it. + /// + BadRequest = 400, - /// - /// The Authorization header was missing or invalid. - /// - Unauthorized = 401, + /// + /// The Authorization header was missing or invalid. + /// + Unauthorized = 401, - /// - /// The Authorization token you passed did not have permission to the resource. - /// - Forbidden = 403, + /// + /// The Authorization token you passed did not have permission to the resource. + /// + Forbidden = 403, - /// - /// The resource at the location specified doesn't exist. - /// - NotFound = 404, + /// + /// The resource at the location specified doesn't exist. + /// + NotFound = 404, - /// - /// The HTTP method used is not valid for the location specified. - /// - MethodNotAllowed = 405, + /// + /// The HTTP method used is not valid for the location specified. + /// + MethodNotAllowed = 405, - /// - /// You are being rate limited, see Rate Limits. - /// - TooManyRequests = 429, + /// + /// You are being rate limited, see Rate Limits. + /// + TooManyRequests = 429, - /// - /// Server Error - /// - InternalServerError = 500, + /// + /// Server Error + /// + InternalServerError = 500, - /// - /// There was not a gateway available to process your request. Wait a bit and retry. - /// - GatewayUnavailable = 502 - } + /// + /// There was not a gateway available to process your request. Wait a bit and retry. + /// + GatewayUnavailable = 502 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Api/RateLimitContent.cs b/Oxide.Ext.Discord/Entities/Api/RateLimitContent.cs index da884236d..873d8aab8 100644 --- a/Oxide.Ext.Discord/Entities/Api/RateLimitContent.cs +++ b/Oxide.Ext.Discord/Entities/Api/RateLimitContent.cs @@ -1,21 +1,20 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +internal class RateLimitContent : BasePoolable { - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - internal class RateLimitContent : BasePoolable - { - [JsonProperty("message")] - public string Message { get; set; } + [JsonProperty("message")] + public string Message { get; set; } - [JsonProperty("code")] - public int? Code { get; set; } + [JsonProperty("code")] + public int? Code { get; set; } - protected override void EnterPool() - { - Message = null; - Code = null; - } + protected override void EnterPool() + { + Message = null; + Code = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Api/RateLimitResponse.cs b/Oxide.Ext.Discord/Entities/Api/RateLimitResponse.cs index a01fe4999..d39512c3c 100644 --- a/Oxide.Ext.Discord/Entities/Api/RateLimitResponse.cs +++ b/Oxide.Ext.Discord/Entities/Api/RateLimitResponse.cs @@ -7,102 +7,101 @@ using Oxide.Ext.Discord.Rest; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a rate limit response from an API request +/// +public class RateLimitResponse : BasePoolable { /// - /// Represents a rate limit response from an API request + /// The Bucket ID of the rate limit /// - public class RateLimitResponse : BasePoolable - { - /// - /// The Bucket ID of the rate limit - /// - public BucketId BucketId; + public BucketId BucketId; - /// - /// If we hit the global rate limit with this request - /// - public bool IsGlobalRateLimit; + /// + /// If we hit the global rate limit with this request + /// + public bool IsGlobalRateLimit; - /// - /// The date time when this bucket will reset - /// - public DateTimeOffset ResetAt; + /// + /// The date time when this bucket will reset + /// + public DateTimeOffset ResetAt; - /// - /// The number of request for this bucket - /// - public int Limit; + /// + /// The number of request for this bucket + /// + public int Limit; - /// - /// The number of remaining requests for this bucket - /// - public int Remaining; + /// + /// The number of remaining requests for this bucket + /// + public int Remaining; - /// - /// The scope the rate limit is for - /// - public string Scope; + /// + /// The scope the rate limit is for + /// + public string Scope; - /// - /// Rate Limit Message - /// - public string Message; + /// + /// Rate Limit Message + /// + public string Message; - /// - /// Rate Limit Code - /// - public int? Code; + /// + /// Rate Limit Code + /// + public int? Code; - /// - /// Initialize the RateLimitResponse - /// - /// Headers for the rate limit - /// Http code for the request - /// Request response content - public void Init(HttpResponseHeaders headers, DiscordHttpStatusCode code, string content) + /// + /// Initialize the RateLimitResponse + /// + /// Headers for the rate limit + /// Http code for the request + /// Request response content + public void Init(HttpResponseHeaders headers, DiscordHttpStatusCode code, string content) + { + IsGlobalRateLimit = headers.GetBool(RateLimitHeaders.IsGlobal); + Scope = headers.Get(RateLimitHeaders.Scope); + if (IsGlobalRateLimit) { - IsGlobalRateLimit = headers.GetBool(RateLimitHeaders.IsGlobal); - Scope = headers.Get(RateLimitHeaders.Scope); - if (IsGlobalRateLimit) - { - ResetAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(headers.GetDouble(RateLimitHeaders.RetryAfter)); - return; - } - - BucketId = headers.GetBucketId(RateLimitHeaders.BucketId); - if (!BucketId.IsValid) - { - return; - } - - Limit = headers.GetInt(RateLimitHeaders.BucketLimit); - Remaining = headers.GetInt(RateLimitHeaders.BucketRemaining); - ResetAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(headers.GetDouble(RateLimitHeaders.BucketResetAfter)); - - if (code == DiscordHttpStatusCode.TooManyRequests && !string.IsNullOrEmpty(content) && content[0] == '{') - { - RateLimitContent rateContent = DiscordPool.Internal.Get(); - JsonConvert.PopulateObject(content, rateContent); - Message = rateContent.Message; - Code = rateContent.Code; - DiscordPool.Internal.Free(rateContent); - } + ResetAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(headers.GetDouble(RateLimitHeaders.RetryAfter)); + return; + } - //DiscordExtension.GlobalLogger.Debug("Headers:\n{0}", headers.ToString()); + BucketId = headers.GetBucketId(RateLimitHeaders.BucketId); + if (!BucketId.IsValid) + { + return; } + + Limit = headers.GetInt(RateLimitHeaders.BucketLimit); + Remaining = headers.GetInt(RateLimitHeaders.BucketRemaining); + ResetAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(headers.GetDouble(RateLimitHeaders.BucketResetAfter)); - /// - protected override void EnterPool() + if (code == DiscordHttpStatusCode.TooManyRequests && !string.IsNullOrEmpty(content) && content[0] == '{') { - BucketId = default(BucketId); - IsGlobalRateLimit = false; - ResetAt = default(DateTimeOffset); - Limit = 0; - Remaining = 0; - Scope = null; - Message = null; - Code = null; + RateLimitContent rateContent = DiscordPool.Internal.Get(); + JsonConvert.PopulateObject(content, rateContent); + Message = rateContent.Message; + Code = rateContent.Code; + DiscordPool.Internal.Free(rateContent); } + + //DiscordExtension.GlobalLogger.Debug("Headers:\n{0}", headers.ToString()); + } + + /// + protected override void EnterPool() + { + BucketId = default; + IsGlobalRateLimit = false; + ResetAt = default; + Limit = 0; + Remaining = 0; + Scope = null; + Message = null; + Code = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Api/RequestErrorType.cs b/Oxide.Ext.Discord/Entities/Api/RequestErrorType.cs index c2126fe51..0be828121 100644 --- a/Oxide.Ext.Discord/Entities/Api/RequestErrorType.cs +++ b/Oxide.Ext.Discord/Entities/Api/RequestErrorType.cs @@ -1,38 +1,37 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Request Error Type +/// +public enum RequestErrorType : byte { /// - /// Represents a Discord Request Error Type + /// A generic web error occured /// - public enum RequestErrorType : byte - { - /// - /// A generic web error occured - /// - GenericWeb, + GenericWeb, - /// - /// An Internal HTTP Error Occured - /// - Internal, + /// + /// An Internal HTTP Error Occured + /// + Internal, - /// - /// A Ratelimit Error Occured - /// - RateLimit, + /// + /// A Ratelimit Error Occured + /// + RateLimit, - /// - /// An Invalid request was passed to discord - /// - ApiError, + /// + /// An Invalid request was passed to discord + /// + ApiError, - /// - /// An error occured during JSON serialization - /// - Serialization, + /// + /// An error occured during JSON serialization + /// + Serialization, - /// - /// A non web error occured - /// - Generic - } + /// + /// A non web error occured + /// + Generic } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Api/RequestResponse.cs b/Oxide.Ext.Discord/Entities/Api/RequestResponse.cs index 7f49ee746..3080d177b 100644 --- a/Oxide.Ext.Discord/Entities/Api/RequestResponse.cs +++ b/Oxide.Ext.Discord/Entities/Api/RequestResponse.cs @@ -4,87 +4,86 @@ using Oxide.Ext.Discord.Rest; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a REST response from discord +/// +public class RequestResponse : BasePoolable { + internal RequestCompletedStatus Status; + internal RateLimitResponse RateLimit; + internal ResponseError Error; + internal DiscordHttpStatusCode Code; + internal string Content; + /// - /// Represents a REST response from discord + /// Create new REST response with the given data /// - public class RequestResponse : BasePoolable + /// The Web Response for the request + /// The status of the request indicating if it was successful + /// If the request had an error the error created from the request + private async ValueTask Init(HttpResponseMessage response, RequestCompletedStatus status, ResponseError error = null) { - internal RequestCompletedStatus Status; - internal RateLimitResponse RateLimit; - internal ResponseError Error; - internal DiscordHttpStatusCode Code; - internal string Content; + Status = status; + Error = error; - /// - /// Create new REST response with the given data - /// - /// The Web Response for the request - /// The status of the request indicating if it was successful - /// If the request had an error the error created from the request - private async ValueTask Init(HttpResponseMessage response, RequestCompletedStatus status, ResponseError error = null) + if (response != null) { - Status = status; - Error = error; - - if (response != null) - { - Code = (DiscordHttpStatusCode)response.StatusCode; - Content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - RateLimit = DiscordPool.Internal.Get(); - RateLimit.Init(response.Headers, Code, Content); - error?.SetResponse(Code, Content); - error?.SetRateLimitResponse(RateLimit.Message, RateLimit.Code); - } + Code = (DiscordHttpStatusCode)response.StatusCode; + Content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + RateLimit = DiscordPool.Internal.Get(); + RateLimit.Init(response.Headers, Code, Content); + error?.SetResponse(Code, Content); + error?.SetRateLimitResponse(RateLimit.Message, RateLimit.Code); } + } - /// - /// Creates a success REST API response - /// - /// The Web Response for the request - /// A success - public static async ValueTask CreateSuccessResponse(HttpResponseMessage httpResponse) - { - RequestResponse response = DiscordPool.Internal.Get(); - await response.Init(httpResponse, RequestCompletedStatus.Success).ConfigureAwait(false); - return response; - } + /// + /// Creates a success REST API response + /// + /// The Web Response for the request + /// A success + public static async ValueTask CreateSuccessResponse(HttpResponseMessage httpResponse) + { + RequestResponse response = DiscordPool.Internal.Get(); + await response.Init(httpResponse, RequestCompletedStatus.Success).ConfigureAwait(false); + return response; + } - /// - /// Creates a Web Exception REST API response - /// - /// Rest Error that occured - /// Web Response for the request - /// The request status containing the fail reason - /// A web exception - public static async ValueTask CreateExceptionResponse(ResponseError error, HttpResponseMessage httpResponse, RequestCompletedStatus status) - { - RequestResponse response = DiscordPool.Internal.Get(); - await response.Init(httpResponse, status, error).ConfigureAwait(false); - return response; - } + /// + /// Creates a Web Exception REST API response + /// + /// Rest Error that occured + /// Web Response for the request + /// The request status containing the fail reason + /// A web exception + public static async ValueTask CreateExceptionResponse(ResponseError error, HttpResponseMessage httpResponse, RequestCompletedStatus status) + { + RequestResponse response = DiscordPool.Internal.Get(); + await response.Init(httpResponse, status, error).ConfigureAwait(false); + return response; + } - /// - /// Creates a REST API response for a cancelled request - /// - /// A cancelled - public static async ValueTask CreateCancelledResponse() - { - RequestResponse response = DiscordPool.Internal.Get(); - await response.Init(null, RequestCompletedStatus.Cancelled).ConfigureAwait(false); - return response; - } + /// + /// Creates a REST API response for a cancelled request + /// + /// A cancelled + public static async ValueTask CreateCancelledResponse() + { + RequestResponse response = DiscordPool.Internal.Get(); + await response.Init(null, RequestCompletedStatus.Cancelled).ConfigureAwait(false); + return response; + } - /// - protected override void EnterPool() - { - RateLimit?.Dispose(); - Status = default(RequestCompletedStatus); - RateLimit = null; - Error = null; - Code = 0; - Content = null; - } + /// + protected override void EnterPool() + { + RateLimit?.Dispose(); + Status = default; + RateLimit = null; + Error = null; + Code = 0; + Content = null; } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Api/ResponseError.cs b/Oxide.Ext.Discord/Entities/Api/ResponseError.cs index 824f4c5fd..02a868587 100644 --- a/Oxide.Ext.Discord/Entities/Api/ResponseError.cs +++ b/Oxide.Ext.Discord/Entities/Api/ResponseError.cs @@ -10,219 +10,218 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Rest; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Error object that is returned to the caller when a request fails +/// +public class ResponseError : BaseDiscordException { /// - /// Error object that is returned to the caller when a request fails + /// ID of the request /// - public class ResponseError : BaseDiscordException - { - /// - /// ID of the request - /// - public readonly Snowflake RequestId; + public readonly Snowflake RequestId; - /// - /// The request method that was called - /// - public readonly RequestMethod RequestMethod; - - /// - /// The exception from the request - /// - public Exception Exception { get; private set; } - - /// - /// The URI that was called - /// - public readonly string Url; - - /// - /// What data was passed to the request - /// - public readonly object RequestData; - - /// - /// HTTP Content Type for the request - /// - public string ContentType { get; private set; } - - /// - /// when the error occured - /// - public readonly DateTimeOffset ErrorDate; - - /// - /// The string contents of the request - /// - public string StringContents { get; private set; } - - /// - /// HTTP Status code - /// - public DiscordHttpStatusCode HttpStatusCode { get; private set; } - - /// - /// If discord returned an error this will contain that error message - /// - public ResponseErrorMessage DiscordError { get; private set; } - - /// - /// Full string response if we received one - /// - public string ResponseMessage { get; private set; } + /// + /// The request method that was called + /// + public readonly RequestMethod RequestMethod; + + /// + /// The exception from the request + /// + public Exception Exception { get; private set; } + + /// + /// The URI that was called + /// + public readonly string Url; + + /// + /// What data was passed to the request + /// + public readonly object RequestData; + + /// + /// HTTP Content Type for the request + /// + public string ContentType { get; private set; } + + /// + /// when the error occured + /// + public readonly DateTimeOffset ErrorDate; + + /// + /// The string contents of the request + /// + public string StringContents { get; private set; } + + /// + /// HTTP Status code + /// + public DiscordHttpStatusCode HttpStatusCode { get; private set; } + + /// + /// If discord returned an error this will contain that error message + /// + public ResponseErrorMessage DiscordError { get; private set; } + + /// + /// Full string response if we received one + /// + public string ResponseMessage { get; private set; } - /// - /// If error was a rate limit the message from the rate limit - /// - public string RateLimitMessage { get; private set; } + /// + /// If error was a rate limit the message from the rate limit + /// + public string RateLimitMessage { get; private set; } - /// - /// If error was a rate limit the code from the rate limit - /// - public int? RateLimitCode { get; private set; } + /// + /// If error was a rate limit the code from the rate limit + /// + public int? RateLimitCode { get; private set; } - internal RequestErrorType ErrorType { get; private set; } - - private DiscordLogLevel _logLevel; - private readonly DiscordClient _client; - private readonly Bucket _bucket; - - /// - /// Should we display the error message - /// - private bool _showErrorMessage = true; - - /// - /// Creates a new rest error - /// - /// Request the error is for - /// of the error - /// log level of the error - internal ResponseError(BaseRequest request, RequestErrorType type, DiscordLogLevel log) - { - RequestId = request.Id; - _client = request.Client; - _bucket = request.Bucket; - Url = request.Route; - RequestMethod = request.Method; - RequestData = request.Data; - ErrorDate = DateTimeOffset.UtcNow; - ErrorType = type; - _logLevel = log; - } + internal RequestErrorType ErrorType { get; private set; } - internal async ValueTask WithRequest(HttpRequestMessage request) + private DiscordLogLevel _logLevel; + private readonly DiscordClient _client; + private readonly Bucket _bucket; + + /// + /// Should we display the error message + /// + private bool _showErrorMessage = true; + + /// + /// Creates a new rest error + /// + /// Request the error is for + /// of the error + /// log level of the error + internal ResponseError(BaseRequest request, RequestErrorType type, DiscordLogLevel log) + { + RequestId = request.Id; + _client = request.Client; + _bucket = request.Bucket; + Url = request.Route; + RequestMethod = request.Method; + RequestData = request.Data; + ErrorDate = DateTimeOffset.UtcNow; + ErrorType = type; + _logLevel = log; + } + + internal async ValueTask WithRequest(HttpRequestMessage request) + { + if (request.Content != null) { - if (request.Content != null) - { - ContentType = request.Content.Headers.ContentType.ToString(); - StringContents = await request.Content.ReadAsStringAsync().ConfigureAwait(false); - } - else - { - ContentType = "No Content"; - StringContents = "No Content"; - } - - return this; + ContentType = request.Content.Headers.ContentType.ToString(); + StringContents = await request.Content.ReadAsStringAsync().ConfigureAwait(false); } - - internal ResponseError WithException(Exception ex) + else { - Exception = ex; - return this; + ContentType = "No Content"; + StringContents = "No Content"; } - /// - /// Suppresses the error message from being logged - /// - public void SuppressErrorMessage() + return this; + } + + internal ResponseError WithException(Exception ex) + { + Exception = ex; + return this; + } + + /// + /// Suppresses the error message from being logged + /// + public void SuppressErrorMessage() + { + _showErrorMessage = false; + } + + /// + /// Sets the HTTP Response data + /// + /// HTTP Response Code + /// HTTP Response Body Stream + internal void SetResponse(DiscordHttpStatusCode code, string content) + { + HttpStatusCode = code; + if (content.Length == 0) { - _showErrorMessage = false; + return; } - /// - /// Sets the HTTP Response data - /// - /// HTTP Response Code - /// HTTP Response Body Stream - internal void SetResponse(DiscordHttpStatusCode code, string content) + ResponseMessage = content; + if (string.IsNullOrEmpty(ResponseMessage) || ResponseMessage[0] != '{') { - HttpStatusCode = code; - if (content.Length == 0) - { - return; - } - - ResponseMessage = content; - if (string.IsNullOrEmpty(ResponseMessage) || ResponseMessage[0] != '{') - { - return; - } + return; + } - DiscordError = JsonConvert.DeserializeObject(content, _client.Bot.JsonSettings); - if (DiscordError == null) - { - return; - } + DiscordError = JsonConvert.DeserializeObject(content, _client.JsonSettings); + if (DiscordError == null) + { + return; + } - ErrorType = RequestErrorType.ApiError; - _logLevel = DiscordLogLevel.Error; + ErrorType = RequestErrorType.ApiError; + _logLevel = DiscordLogLevel.Error; + } + + internal void SetRateLimitResponse(string message, int? code) + { + RateLimitMessage = message; + RateLimitCode = code; + } + + /// + /// Performs the error logging for the request + /// + internal void LogError() + { + if (!_client.Logger.IsLogging(_logLevel)) + { + return; } - internal void SetRateLimitResponse(string message, int? code) + if (DiscordError != null && DiscordConfig.Instance.Logging.HideDiscordErrorCodes.Contains(DiscordError.Code)) { - RateLimitMessage = message; - RateLimitCode = code; + return; } - /// - /// Performs the error logging for the request - /// - internal void LogError() + switch (ErrorType) { - if (!_client.Logger.IsLogging(_logLevel)) - { - return; - } - - if (DiscordError != null && DiscordConfig.Instance.Logging.HideDiscordErrorCodes.Contains(DiscordError.Code)) - { - return; - } - - switch (ErrorType) - { - case RequestErrorType.Internal: - _client.Logger.Error("Rest Request Exception (Internal Error) Plugin: {0} ID: {1} Request URL: [{2}] {3}", _client.PluginName, RequestId, RequestMethod, Url); - break; + case RequestErrorType.Internal: + _client.Logger.Error("Rest Request Exception (Internal Error) Plugin: {0} ID: {1} Request URL: [{2}] {3}", _client.PluginName, RequestId, RequestMethod, Url); + break; - case RequestErrorType.RateLimit: - _client.Logger.Warning("Rest Request Exception (Rate Limit) Plugin: {0} ID: {1} Request URL: [{2}] {3} Content-Type: {4} Remaining: {5} Limit: {6} Reset At: {7} Current Time: {8} Code: {9} Message: {10}", - _client.PluginName, RequestId, RequestMethod, Url, ContentType, _bucket.Remaining, _bucket.Limit, _bucket.ResetAt, ErrorDate, RateLimitCode, RateLimitMessage); - break; - - case RequestErrorType.ApiError: - if (_showErrorMessage) - { - _client.Logger.Error("Rest Request Exception (Discord API Error). Plugin: {0} ID: {1} Request URL: [{2}] {3} Content-Type: {4} Http Response Code: {5} Discord Error Code: {6} Discord Error: {7}\nDiscord Errors: {8}Request Body:\n{9}", - _client.PluginName, RequestId, RequestMethod, Url, ContentType, HttpStatusCode, DiscordError.Code, DiscordError.Message, DiscordError.Errors, StringContents ?? "No Contents"); - } - break; - - case RequestErrorType.GenericWeb: - _client.Logger.Error("Rest Request Exception (Web Error). Plugin: {0} ID: {1} Request URL: [{2}] {3} Content-Type: {4} Http Response Code: {5} Message: {6}", _client.PluginName, RequestId, RequestMethod, Url, ContentType, HttpStatusCode, ResponseMessage); - break; - - case RequestErrorType.Serialization: - _client.Logger.Exception("Rest Request Exception (JSON Serialization). Plugin: {0} ID: {1} Method: {2} URL: {3} Data Type: {4}", _client.PluginName, RequestId, RequestMethod, Url, RequestData?.GetType().GetRealTypeName() ?? "None", Exception); - break; - - case RequestErrorType.Generic: - _client.Logger.Exception("Rest Request Exception (Generic Error). Plugin: {0} ID: {1} Method: {2} URL: {3} Data Type: {4}", _client.PluginName, RequestId, RequestMethod, Url, RequestData?.GetType().GetRealTypeName() ?? "None", Exception); - break; - } + case RequestErrorType.RateLimit: + _client.Logger.Warning("Rest Request Exception (Rate Limit) Plugin: {0} ID: {1} Request URL: [{2}] {3} Content-Type: {4} Remaining: {5} Limit: {6} Reset At: {7} Current Time: {8} Code: {9} Message: {10}", + _client.PluginName, RequestId, RequestMethod, Url, ContentType, _bucket.Remaining, _bucket.Limit, _bucket.ResetAt, ErrorDate, RateLimitCode, RateLimitMessage); + break; + + case RequestErrorType.ApiError: + if (_showErrorMessage) + { + _client.Logger.Error("Rest Request Exception (Discord API Error). Plugin: {0} ID: {1} Request URL: [{2}] {3} Content-Type: {4} Http Response Code: {5} Discord Error Code: {6} Discord Error: {7}\nDiscord Errors: {8}Request Body:\n{9}", + _client.PluginName, RequestId, RequestMethod, Url, ContentType, HttpStatusCode, DiscordError.Code, DiscordError.Message, DiscordError.Errors, StringContents ?? "No Contents"); + } + break; + + case RequestErrorType.GenericWeb: + _client.Logger.Error("Rest Request Exception (Web Error). Plugin: {0} ID: {1} Request URL: [{2}] {3} Content-Type: {4} Http Response Code: {5} Message: {6}", _client.PluginName, RequestId, RequestMethod, Url, ContentType, HttpStatusCode, ResponseMessage); + break; + + case RequestErrorType.Serialization: + _client.Logger.Exception("Rest Request Exception (JSON Serialization). Plugin: {0} ID: {1} Method: {2} URL: {3} Data Type: {4}", _client.PluginName, RequestId, RequestMethod, Url, RequestData?.GetType().GetRealTypeName() ?? "None", Exception); + break; + + case RequestErrorType.Generic: + _client.Logger.Exception("Rest Request Exception (Generic Error). Plugin: {0} ID: {1} Method: {2} URL: {3} Data Type: {4}", _client.PluginName, RequestId, RequestMethod, Url, RequestData?.GetType().GetRealTypeName() ?? "None", Exception); + break; } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Api/ResponseErrorMessage.cs b/Oxide.Ext.Discord/Entities/Api/ResponseErrorMessage.cs index fba20990d..366dfc8f3 100644 --- a/Oxide.Ext.Discord/Entities/Api/ResponseErrorMessage.cs +++ b/Oxide.Ext.Discord/Entities/Api/ResponseErrorMessage.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents an error from the discord API +/// +public class ResponseErrorMessage { /// - /// Represents an error from the discord API + /// Error code from the discord API /// - public class ResponseErrorMessage - { - /// - /// Error code from the discord API - /// - [JsonProperty("code")] - public int Code { get; set; } + [JsonProperty("code")] + public int Code { get; set; } - /// - /// Error message from the discord API - /// - [JsonProperty("message")] - public string Message { get; set; } + /// + /// Error message from the discord API + /// + [JsonProperty("message")] + public string Message { get; set; } - /// - /// An JObject containing the errors that occured - /// - [JsonProperty("errors")] - public JObject Errors { get; set; } - } + /// + /// An JObject containing the errors that occured + /// + [JsonProperty("errors")] + public JObject Errors { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/ApplicationFlags.cs b/Oxide.Ext.Discord/Entities/Applications/ApplicationFlags.cs index 50fca975a..df9c1522e 100644 --- a/Oxide.Ext.Discord/Entities/Applications/ApplicationFlags.cs +++ b/Oxide.Ext.Discord/Entities/Applications/ApplicationFlags.cs @@ -1,68 +1,67 @@ using System; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Flags +/// +[Flags] +public enum ApplicationFlags { /// - /// Represents Application Flags + /// This application has no flags /// - [Flags] - public enum ApplicationFlags - { - /// - /// This application has no flags - /// - None = 0, + None = 0, - /// - /// Indicates if an app uses the Auto Moderation API - /// - ApplicationAutoModerationRuleCreateBadge = 1 << 6, + /// + /// Indicates if an app uses the Auto Moderation API + /// + ApplicationAutoModerationRuleCreateBadge = 1 << 6, - /// - /// Intent required for bots in 100 or more servers to receive presence_update events - /// - GatewayPresence = 1 << 12, + /// + /// Intent required for bots in 100 or more servers to receive presence_update events + /// + GatewayPresence = 1 << 12, - /// - /// Intent required for bots in under 100 servers to receive presence_update events, found in Bot Settings - /// - GatewayPresenceLimited = 1 << 13, + /// + /// Intent required for bots in under 100 servers to receive presence_update events, found in Bot Settings + /// + GatewayPresenceLimited = 1 << 13, - /// - /// Intent required for bots in 100 or more servers to receive member-related events like guild_member_add. - /// See list of member-related events under GUILD_MEMBERS - /// - GatewayGuildMembers = 1 << 14, + /// + /// Intent required for bots in 100 or more servers to receive member-related events like guild_member_add. + /// See list of member-related events under GUILD_MEMBERS + /// + GatewayGuildMembers = 1 << 14, - /// - /// Intent required for bots in under 100 servers to receive member-related events like guild_member_add, found in Bot Settings. - /// See list of member-related events under GUILD_MEMBERS - /// - GatewayGuildMembersLimited = 1 << 15, + /// + /// Intent required for bots in under 100 servers to receive member-related events like guild_member_add, found in Bot Settings. + /// See list of member-related events under GUILD_MEMBERS + /// + GatewayGuildMembersLimited = 1 << 15, - /// - /// Indicates unusual growth of an app that prevents verification - /// - VerificationPendingGuildLimit = 1 << 16, + /// + /// Indicates unusual growth of an app that prevents verification + /// + VerificationPendingGuildLimit = 1 << 16, - /// - /// Indicates if an app is embedded within the Discord client (currently unavailable publicly) - /// - Embedded = 1 << 17, + /// + /// Indicates if an app is embedded within the Discord client (currently unavailable publicly) + /// + Embedded = 1 << 17, - /// - /// Intent required for bots in 100 or more servers to receive message content - /// - GatewayMessageContent = 1 << 18, + /// + /// Intent required for bots in 100 or more servers to receive message content + /// + GatewayMessageContent = 1 << 18, - /// - /// Intent required for bots in under 100 servers to receive message content, found in Bot Settings - /// - GatewayMessageContentLimited = 1 << 19, + /// + /// Intent required for bots in under 100 servers to receive message content, found in Bot Settings + /// + GatewayMessageContentLimited = 1 << 19, - /// - /// Indicates if an app has registered global application commands - /// - ApplicationCommandBadge = 1 << 23, - } + /// + /// Indicates if an app has registered global application commands + /// + ApplicationCommandBadge = 1 << 23, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/ApplicationIntegrationType.cs b/Oxide.Ext.Discord/Entities/Applications/ApplicationIntegrationType.cs new file mode 100644 index 000000000..034c90eb5 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Applications/ApplicationIntegrationType.cs @@ -0,0 +1,17 @@ +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Application Integration Types +/// +public enum ApplicationIntegrationType +{ + /// + /// App is installable to servers + /// + GuildInstall = 0, + + /// + /// App is installable to users + /// + UserInstall = 1 +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/ApplicationIntegrationTypeConfiguration.cs b/Oxide.Ext.Discord/Entities/Applications/ApplicationIntegrationTypeConfiguration.cs new file mode 100644 index 000000000..51f6ead45 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Applications/ApplicationIntegrationTypeConfiguration.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Application Integration Type Configuration +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ApplicationIntegrationTypeConfiguration +{ + /// + /// Install params for each installation context's default in-app authorization link + /// + [JsonProperty("oauth2_install_params")] + public InstallParams Oauth2InstallParams { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/ApplicationUpdate.cs b/Oxide.Ext.Discord/Entities/Applications/ApplicationUpdate.cs index a0d0660ea..6ba456f83 100644 --- a/Oxide.Ext.Discord/Entities/Applications/ApplicationUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Applications/ApplicationUpdate.cs @@ -1,66 +1,72 @@ using System.Collections.Generic; using Newtonsoft.Json; +using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Edit Application Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ApplicationUpdate { /// - /// Represents Edit Application Structure + /// Default custom authorization URL for the app, if enabled /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ApplicationUpdate - { - /// - /// Default custom authorization URL for the app, if enabled - /// - [JsonProperty("custom_install_url")] - public string CustomInstallUrl { get; set; } + [JsonProperty("custom_install_url")] + public string CustomInstallUrl { get; set; } - /// - /// Description of the app - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of the app + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// Role connection verification URL for the app + /// + [JsonProperty("role_connections_verification_url")] + public string RoleConnectionsVerificationUrl { get; set; } - /// - /// Role connection verification URL for the app - /// - [JsonProperty("role_connections_verification_url")] - public string RoleConnectionsVerificationUrl { get; set; } + /// + /// Settings for the application's default in-app authorization link, if enabled + /// + [JsonProperty("install_params")] + public InstallParams InstallParams { get; set; } - /// - /// Settings for the application's default in-app authorization link, if enabled - /// - [JsonProperty("install_params")] - public InstallParams InstallParams { get; set; } + /// + /// Default scopes and permissions for each supported installation context. + /// + [JsonProperty("integration_types_config")] + public Hash IntegrationTypesConfig { get; set; } - /// - /// App's public flags - /// - [JsonProperty("flags")] - public ApplicationFlags? Flags { get; set; } + /// + /// App's public flags + /// + [JsonProperty("flags")] + public ApplicationFlags? Flags { get; set; } - /// - /// Icon for the app - /// - [JsonProperty("icon")] - public DiscordImageData? Icon { get; set; } + /// + /// Icon for the app + /// + [JsonProperty("icon")] + public DiscordImageData? Icon { get; set; } - /// - /// Default rich presence invite cover image for the app - /// - [JsonProperty("cover_image")] - public DiscordImageData? CoverImage { get; set; } + /// + /// Default rich presence invite cover image for the app + /// + [JsonProperty("cover_image")] + public DiscordImageData? CoverImage { get; set; } - /// - /// Interactions endpoint URL for the app - /// - [JsonProperty("interactions_endpoint_url")] - public string InteractionsEndpointUrl { get; set; } + /// + /// Interactions endpoint URL for the app + /// + [JsonProperty("interactions_endpoint_url")] + public string InteractionsEndpointUrl { get; set; } - /// - /// List of tags describing the content and functionality of the app (max of 20 characters per tag). Max of 5 tags. - /// - [JsonProperty("tags")] - public List Tags { get; set; } - } + /// + /// List of tags describing the content and functionality of the app (max of 20 characters per tag). Max of 5 tags. + /// + [JsonProperty("tags")] + public List Tags { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/DiscordApplication.cs b/Oxide.Ext.Discord/Entities/Applications/DiscordApplication.cs index a01f601bf..1f619c0fc 100644 --- a/Oxide.Ext.Discord/Entities/Applications/DiscordApplication.cs +++ b/Oxide.Ext.Discord/Entities/Applications/DiscordApplication.cs @@ -8,370 +8,431 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; +using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordApplication : IDebugLoggable { /// - /// Represents Application Structure + /// ID of the app /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordApplication : IDebugLoggable - { - /// - /// ID of the app - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Name of the app - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the app + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Icon hash of the app - /// - [JsonProperty("icon")] - public string Icon { get; set; } + /// + /// Icon hash of the app + /// + [JsonProperty("icon")] + public string Icon { get; set; } - /// - /// Description of the app - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of the app + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// List of RPC origin URLs, if RPC is enabled - /// - [JsonProperty("rpc_origins")] - public List RpcOrigins { get; set; } + /// + /// List of RPC origin URLs, if RPC is enabled + /// + [JsonProperty("rpc_origins")] + public List RpcOrigins { get; set; } - /// - /// When false only app owner can join the app's bot to guilds - /// - [JsonProperty("bot_public")] - public bool BotPublic { get; set; } + /// + /// When false only app owner can join the app's bot to guilds + /// + [JsonProperty("bot_public")] + public bool BotPublic { get; set; } - /// - /// When true the app's bot will only join upon completion of the full oauth2 code grant flow - /// - [JsonProperty("bot_require_code_grant")] - public bool BotRequireCodeGrant { get; set; } + /// + /// When true the app's bot will only join upon completion of the full oauth2 code grant flow + /// + [JsonProperty("bot_require_code_grant")] + public bool BotRequireCodeGrant { get; set; } - /// - /// Partial user object for the bot user associated with the app - /// - [JsonProperty("bot")] - public DiscordUser Bot { get; set; } + /// + /// Partial user object for the bot user associated with the app + /// + [JsonProperty("bot")] + public DiscordUser Bot { get; set; } - /// - /// URL of the app's terms of service - /// - [JsonProperty("terms_of_service_url")] - public string TermsOfServiceUrl { get; set; } + /// + /// URL of the app's terms of service + /// + [JsonProperty("terms_of_service_url")] + public string TermsOfServiceUrl { get; set; } - /// - /// URL of the app's privacy policy - /// - [JsonProperty("privacy_policy_url")] - public string PrivacyPolicyUrl { get; set; } + /// + /// URL of the app's privacy policy + /// + [JsonProperty("privacy_policy_url")] + public string PrivacyPolicyUrl { get; set; } - /// - /// Partial user object containing info on the owner of the application - /// - [JsonProperty("owner")] - public DiscordUser Owner { get; set; } + /// + /// Partial user object containing info on the owner of the application + /// + [JsonProperty("owner")] + public DiscordUser Owner { get; set; } - /// - /// Hex encoded key for verification in interactions and the GameSDK's GetTicket - /// - [JsonProperty("verify_key")] - public string Verify { get; set; } + /// + /// Hex encoded key for verification in interactions and the GameSDK's GetTicket + /// + [JsonProperty("verify_key")] + public string Verify { get; set; } - /// - /// If the application belongs to a team, this will be a list of the members of that team - /// - [JsonProperty("team")] - public DiscordTeam Team { get; set; } + /// + /// If the application belongs to a team, this will be a list of the members of that team + /// + [JsonProperty("team")] + public DiscordTeam Team { get; set; } - /// - /// Guild associated with the app. For example, a developer support server. - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// Guild associated with the app. For example, a developer support server. + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// Partial Guild for the application - /// - [JsonProperty("guild")] - public DiscordGuild Guild { get; set; } + /// + /// Partial Guild for the application + /// + [JsonProperty("guild")] + public DiscordGuild Guild { get; set; } - /// - /// If this application is a game sold on Discord, this field will be the id of the "Game SKU" that is created, if exists - /// - [JsonProperty("primary_sku_id")] - public string PrimarySkuId { get; set; } + /// + /// If this application is a game sold on Discord, this field will be the id of the "Game SKU" that is created, if exists + /// + [JsonProperty("primary_sku_id")] + public string PrimarySkuId { get; set; } - /// - /// If this application is a game sold on Discord, this field will be the URL slug that links to the store page - /// - [JsonProperty("slug")] - public string Slug { get; set; } + /// + /// If this application is a game sold on Discord, this field will be the URL slug that links to the store page + /// + [JsonProperty("slug")] + public string Slug { get; set; } - /// - /// If this application is a game sold on Discord, this field will be the hash of the image on store embeds - /// - [JsonProperty("cover_image")] - public string CoverImage { get; set; } + /// + /// If this application is a game sold on Discord, this field will be the hash of the image on store embeds + /// + [JsonProperty("cover_image")] + public string CoverImage { get; set; } - /// - /// App's public flags - /// - [JsonProperty("flags")] - public ApplicationFlags? Flags { get; set; } + /// + /// App's public flags + /// + [JsonProperty("flags")] + public ApplicationFlags? Flags { get; set; } - /// - /// An approximate count of the app's guild membership. - /// - [JsonProperty("approximate_guild_count")] - public int? ApproximateGuildCount { get; set; } + /// + /// An approximate count of the app's guild membership. + /// + [JsonProperty("approximate_guild_count")] + public int? ApproximateGuildCount { get; set; } - /// - /// Array of redirect URIs for the app - /// - [JsonProperty("redirect_uris")] - public List RedirectUris { get; set; } + /// + /// Array of redirect URIs for the app + /// + [JsonProperty("redirect_uris")] + public List RedirectUris { get; set; } - /// - /// Interactions endpoint URL for the app - /// - [JsonProperty("interactions_endpoint_url")] - public string InteractionsEndpointUrl { get; set; } + /// + /// Interactions endpoint URL for the app + /// + [JsonProperty("interactions_endpoint_url")] + public string InteractionsEndpointUrl { get; set; } + + /// + /// Role connection verification URL for the app + /// + [JsonProperty("role_connections_verification_url")] + public string RoleConnectionsVerificationUrl { get; set; } - /// - /// Role connection verification URL for the app - /// - [JsonProperty("role_connections_verification_url")] - public string RoleConnectionsVerificationUrl { get; set; } + /// + /// Up to 5 tags describing the content and functionality of the application + /// + [JsonProperty("tags")] + public List Tags { get; set; } - /// - /// Up to 5 tags describing the content and functionality of the application - /// - [JsonProperty("tags")] - public List Tags { get; set; } + /// + /// Settings for the application's default in-app authorization link, if enabled + /// + [JsonProperty("install_params")] + public InstallParams InstallParams { get; set; } - /// - /// Settings for the application's default in-app authorization link, if enabled - /// - [JsonProperty("install_params")] - public InstallParams InstallParams { get; set; } + /// + /// Default scopes and permissions for each supported installation context + /// + [JsonProperty("integration_types_config")] + public Hash IntegrationTypesConfig { get; set; } - /// - /// The application's default custom authorization link, if enabled - /// - [JsonProperty("custom_install_url")] - public string CustomInstallUrl { get; set; } + /// + /// The application's default custom authorization link, if enabled + /// + [JsonProperty("custom_install_url")] + public string CustomInstallUrl { get; set; } - /// - /// Returns the URL for the applications Icon - /// - public string GetApplicationIconUrl => DiscordCdn.GetApplicationIconUrl(Id, Icon); + /// + /// Returns the URL for the applications Icon + /// + public string GetApplicationIconUrl => DiscordCdn.GetApplicationIconUrl(Id, Icon); - /// - /// Returns the URL for the application cover - /// - public string GetApplicationCoverUrl => DiscordCdn.GetApplicationIconUrl(Id, CoverImage); + /// + /// Returns the URL for the application cover + /// + public string GetApplicationCoverUrl => DiscordCdn.GetApplicationIconUrl(Id, CoverImage); - /// - /// Returns if the given application has the passed in application flag - /// If is null false is returned - /// - /// Flag to compare against - /// True of application has flag; False Otherwise - public bool HasApplicationFlag(ApplicationFlags flag) - { - return Flags.HasValue && (Flags.Value & flag) == flag; - } + /// + /// Returns if the given application has the passed in application flag + /// If is null false is returned + /// + /// Flag to compare against + /// True of application has flag; False Otherwise + public bool HasApplicationFlag(ApplicationFlags flag) + { + return Flags.HasValue && (Flags.Value & flag) == flag; + } - /// - /// Returns if the given application has any of the passed in application flags - /// If is null false is returned - /// - /// Flag to compare against - /// True of application has flag; False Otherwise - public bool HasAnyApplicationFlags(ApplicationFlags flag) - { - return Flags.HasValue && (Flags.Value & flag) != 0; - } + /// + /// Returns if the given application has any of the passed in application flags + /// If is null false is returned + /// + /// Flag to compare against + /// True of application has flag; False Otherwise + public bool HasAnyApplicationFlags(ApplicationFlags flag) + { + return Flags.HasValue && (Flags.Value & flag) != 0; + } - /// - /// Returns the current users application - /// See Get Current Application - /// - public static IPromise Get(DiscordClient client) - { - return client.Bot.Rest.Get(client,"applications/@me"); - } + /// + /// Returns the current users application + /// See Get Current Application + /// + public static IPromise Get(DiscordClient client) + { + return client.Bot.Rest.Get(client,"applications/@me"); + } - /// - /// Edit properties of the app associated with the requesting bot user. Only properties that are passed will be updated. - /// - /// Client to use - /// Update to apply - public IPromise Edit(DiscordClient client, ApplicationUpdate update) - { - return client.Bot.Rest.Patch(client, "applications/@me", update); - } + /// + /// Edit properties of the app associated with the requesting bot user. Only properties that are passed will be updated. + /// + /// Client to use + /// Update to apply + public IPromise Edit(DiscordClient client, ApplicationUpdate update) + { + return client.Bot.Rest.Patch(client, "applications/@me", update); + } - /// - /// Fetch all of the global commands for your application. - /// Returns a list of ApplicationCommand. - /// See Get Global Application Commands - /// Client to use - /// Include Command Localizations - /// - public IPromise> GetGlobalCommands(DiscordClient client, bool withLocalizations = false) - { - return client.Bot.Rest.Get>(client,$"applications/{Id}/commands?with_localizations={withLocalizations}"); - } + /// + /// Fetch all of the global commands for your application. + /// Returns a list of ApplicationCommand. + /// See Get Global Application Commands + /// Client to use + /// Include Command Localizations + /// + public IPromise> GetGlobalCommands(DiscordClient client, bool withLocalizations = false) + { + return client.Bot.Rest.Get>(client,$"applications/{Id}/commands?with_localizations={withLocalizations}"); + } - /// - /// Fetch global command by ID - /// See Get Global Application Command - /// - /// Client to use - /// ID of command to get - public IPromise GetGlobalCommand(DiscordClient client, Snowflake commandId) - { - InvalidSnowflakeException.ThrowIfInvalid(commandId, nameof(commandId)); - return client.Bot.Rest.Get(client,$"applications/{Id}/commands/{commandId}"); - } + /// + /// Fetch global command by ID + /// See Get Global Application Command + /// + /// Client to use + /// ID of command to get + public IPromise GetGlobalCommand(DiscordClient client, Snowflake commandId) + { + InvalidSnowflakeException.ThrowIfInvalid(commandId); + return client.Bot.Rest.Get(client,$"applications/{Id}/commands/{commandId}"); + } - /// - /// Create a new global command. - /// New global commands will be available in all guilds after 1 hour. - /// Note: Creating a command with the same name as an existing command for your application will overwrite the old command. - /// See Create Global Application Command - /// - /// Client to use - /// Command to create - public IPromise CreateGlobalCommand(DiscordClient client, CommandCreate create) - { - if (create == null) throw new ArgumentNullException(nameof(create)); - return client.Bot.Rest.Post(client,$"applications/{Id}/commands", create); - } + /// + /// Create a new global command. + /// New global commands will be available in all guilds after 1 hour. + /// Note: Creating a command with the same name as an existing command for your application will overwrite the old command. + /// See Create Global Application Command + /// + /// Client to use + /// Command to create + public IPromise CreateGlobalCommand(DiscordClient client, CommandCreate create) + { + if (create == null) throw new ArgumentNullException(nameof(create)); + return client.Bot.Rest.Post(client,$"applications/{Id}/commands", create); + } - /// - /// Takes a list of application commands, overwriting existing commands that are registered globally for this application. Updates will be available in all guilds after 1 hour. - /// See Bulk Overwrite Global Application Commands - /// - /// Client to use - /// List of commands to overwrite - public IPromise> BulkOverwriteGlobalCommands(DiscordClient client, List commands) - { - if (commands == null) throw new ArgumentNullException(nameof(commands)); - return client.Bot.Rest.Put>(client,$"applications/{Id}/commands", commands); - } + /// + /// Takes a list of application commands, overwriting existing commands that are registered globally for this application. Updates will be available in all guilds after 1 hour. + /// See Bulk Overwrite Global Application Commands + /// + /// Client to use + /// List of commands to overwrite + public IPromise> BulkOverwriteGlobalCommands(DiscordClient client, List commands) + { + if (commands == null) throw new ArgumentNullException(nameof(commands)); + return client.Bot.Rest.Put>(client,$"applications/{Id}/commands", commands); + } - /// - /// Fetch all of the guild commands for your application for a specific guild. - /// See Get Guild Application Commands - /// - /// Client to use - /// ID of the guild to get commands for - /// Include Command Localizations - public IPromise> GetGuildCommands(DiscordClient client, Snowflake guildId, bool withLocalizations = false) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Get>(client,$"applications/{Id}/guilds/{guildId}/commands?with_localizations={withLocalizations}"); - } + /// + /// Fetch all of the guild commands for your application for a specific guild. + /// See Get Guild Application Commands + /// + /// Client to use + /// ID of the guild to get commands for + /// Include Command Localizations + public IPromise> GetGuildCommands(DiscordClient client, Snowflake guildId, bool withLocalizations = false) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Get>(client,$"applications/{Id}/guilds/{guildId}/commands?with_localizations={withLocalizations}"); + } - /// - /// Get guild command by Id - /// See Get Guild Application Command - /// - /// Client to use - /// ID of the guild to get commands for - /// ID of the command to get - public IPromise GetGuildCommand(DiscordClient client, Snowflake guildId, Snowflake commandId) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - InvalidSnowflakeException.ThrowIfInvalid(commandId, nameof(commandId)); - return client.Bot.Rest.Get(client,$"applications/{Id}/guilds/{guildId}/commands/{commandId}"); - } + /// + /// Get guild command by Id + /// See Get Guild Application Command + /// + /// Client to use + /// ID of the guild to get commands for + /// ID of the command to get + public IPromise GetGuildCommand(DiscordClient client, Snowflake guildId, Snowflake commandId) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + InvalidSnowflakeException.ThrowIfInvalid(commandId); + return client.Bot.Rest.Get(client,$"applications/{Id}/guilds/{guildId}/commands/{commandId}"); + } - /// - /// Create a new guild command. - /// New guild commands will be available in the guild immediately. - /// See Create Guild Application Command - /// - /// Client to use - /// Guild ID to create the command in - /// Command to create - public IPromise CreateGuildCommand(DiscordClient client, Snowflake guildId, CommandCreate create) - { - if (create == null) throw new ArgumentNullException(nameof(create)); - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Post(client,$"applications/{Id}/guilds/{guildId}/commands", create); - } + /// + /// Create a new guild command. + /// New guild commands will be available in the guild immediately. + /// See Create Guild Application Command + /// + /// Client to use + /// Guild ID to create the command in + /// Command to create + public IPromise CreateGuildCommand(DiscordClient client, Snowflake guildId, CommandCreate create) + { + if (create == null) throw new ArgumentNullException(nameof(create)); + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Post(client,$"applications/{Id}/guilds/{guildId}/commands", create); + } - /// - /// Fetches command permissions for all commands for your application in a guild. Returns an array of GuildApplicationCommandPermissions objects. - /// See Get Guild Application Command Permissions - /// - /// Client to use - /// Guild ID to get the permissions from - public IPromise> GetGuildCommandPermissions(DiscordClient client, Snowflake guildId) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Get>(client,$"applications/{Id}/guilds/{guildId}/commands/permissions"); - } + /// + /// Fetches command permissions for all commands for your application in a guild. Returns an array of GuildApplicationCommandPermissions objects. + /// See Get Guild Application Command Permissions + /// + /// Client to use + /// Guild ID to get the permissions from + public IPromise> GetGuildCommandPermissions(DiscordClient client, Snowflake guildId) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Get>(client,$"applications/{Id}/guilds/{guildId}/commands/permissions"); + } - /// - /// Returns all commands registered to this application - /// - /// Client to use - /// Should the response include localizations - public IPromise> GetAllCommands(DiscordClient client, bool withLocalizations = false) - { - List>> requests = new List>>(); - requests.Add(GetGlobalCommands(client, withLocalizations)); - requests.AddRange(client.Bot.Servers.Keys.Select(id => GetGuildCommands(client, id, withLocalizations))); + /// + /// Returns all commands registered to this application + /// + /// Client to use + /// Should the response include localizations + public IPromise> GetAllCommands(DiscordClient client, bool withLocalizations = false) + { + List>> requests = + [ + GetGlobalCommands(client, withLocalizations) + ]; + requests.AddRange(client.Bot.Servers.Keys.Select(id => GetGuildCommands(client, id, withLocalizations))); - return Promise>.All(requests) - .Then(commands => commands - .SelectMany(c => c).ToList()); - } + return Promise>.All(requests) + .Then(commands => commands + .SelectMany(c => c).ToList()); + } - /// - /// Returns a list of application role connection metadata objects for the given application. - /// See Get Application Role Connection Metadata Records - /// - /// Client to use - public IPromise> GetRoleConnectionMetadata(DiscordClient client) - { - return client.Bot.Rest.Get>(client,$"applications/{Id}/role-connections/metadata"); - } + /// + /// Returns a list of application role connection metadata objects for the given application. + /// See Get Application Role Connection Metadata Records + /// + /// Client to use + public IPromise> GetRoleConnectionMetadata(DiscordClient client) + { + return client.Bot.Rest.Get>(client,$"applications/{Id}/role-connections/metadata"); + } + + /// + /// Updates and returns a list of application role connection metadata objects for the given application. + /// See Update Application Role Connection Metadata Records + /// + /// Client to use + /// The records to update on the application + public IPromise> EditRoleConnectionMetadata(DiscordClient client, List records) + { + DiscordApplicationException.ThrowIfInvalidApplicationRoleConnectionMetadataLength(records); + return client.Bot.Rest.Put>(client,$"applications/{Id}/role-connections/metadata", records); + } + + /// + /// Returns the list of all application emojis + /// + /// Client to use + public IPromise GetApplicationEmojis(DiscordClient client) + { + return client.Bot.Rest.Get(client, $"applications/{Id}/emojis"); + } + + /// + /// Return an application emoji by ID + /// + /// Client to use + /// ID of the emoji + public IPromise GetApplicationEmoji(DiscordClient client, Snowflake emojiId) + { + InvalidSnowflakeException.ThrowIfInvalid(emojiId); + return client.Bot.Rest.Get(client, $"applications/{Id}/emojis/{emojiId}"); + } - /// - /// Updates and returns a list of application role connection metadata objects for the given application. - /// See Update Application Role Connection Metadata Records - /// - /// Client to use - /// The records to update on the application - public IPromise> EditRoleConnectionMetadata(DiscordClient client, List records) - { - DiscordApplicationException.ThrowIfInvalidApplicationRoleConnectionMetadataLength(records); - return client.Bot.Rest.Put>(client,$"applications/{Id}/role-connections/metadata", records); - } + /// + /// Creates a new application emoji + /// + /// Client to use + /// Emoji to create + public IPromise CreateApplicationEmoji(DiscordClient client, ApplicationEmojiCreate create) + { + return client.Bot.Rest.Post(client, $"applications/{Id}/emojis", create); + } + + /// + /// Updates an existing application emoji + /// + /// Client to use + /// ID of the emoji to update + /// Update to the application emoji + public IPromise UpdateApplicationEmoji(DiscordClient client, Snowflake emojiId, ApplicationEmojiUpdate update) + { + InvalidSnowflakeException.ThrowIfInvalid(emojiId); + return client.Bot.Rest.Patch(client, $"applications/{Id}/emojis/{emojiId}", update); + } + + /// + /// Deletes an application emoji + /// + /// Client to use + /// ID of the emoji to delete + public IPromise DeleteApplicationEmoji(DiscordClient client, Snowflake emojiId) + { + InvalidSnowflakeException.ThrowIfInvalid(emojiId); + return client.Bot.Rest.Delete(client, $"applications/{Id}/emojis/{emojiId}"); + } - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendField("ID", Id); - logger.AppendField("Name", Name); - logger.AppendFieldEnum("Flags", Flags ?? ApplicationFlags.None); - } + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("ID", Id); + logger.AppendField("Name", Name); + logger.AppendFieldEnum("Flags", Flags ?? ApplicationFlags.None); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/Emojis/ApplicationEmojiCreate.cs b/Oxide.Ext.Discord/Entities/Applications/Emojis/ApplicationEmojiCreate.cs new file mode 100644 index 000000000..5f6e50a05 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Applications/Emojis/ApplicationEmojiCreate.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json; +using Oxide.Ext.Discord.Exceptions; +using Oxide.Ext.Discord.Interfaces; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Emoji Create Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ApplicationEmojiCreate : IDiscordValidation +{ + /// + /// Emoji name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The 128x128 emoji image + /// Emojis and animated emojis have a maximum file size of 256kb. + /// Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request + /// + [JsonProperty("image")] + public DiscordImageData ImageData { get; set; } + + /// + public void Validate() + { + InvalidEmojiException.ThrowIfInvalidName(Name, false); + InvalidEmojiException.ThrowIfInvalidImageData(ImageData); + } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/Emojis/ApplicationEmojiUpdate.cs b/Oxide.Ext.Discord/Entities/Applications/Emojis/ApplicationEmojiUpdate.cs new file mode 100644 index 000000000..49e7c8c0b --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Applications/Emojis/ApplicationEmojiUpdate.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; +using Oxide.Ext.Discord.Exceptions; +using Oxide.Ext.Discord.Interfaces; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Emoji Update Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ApplicationEmojiUpdate : IDiscordValidation +{ + /// + /// Emoji name + /// + [JsonProperty("name")] + public string Name { get; set; } + + + /// + public void Validate() + { + InvalidEmojiException.ThrowIfInvalidName(Name, true); + } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/Emojis/ApplicationEmojis.cs b/Oxide.Ext.Discord/Entities/Applications/Emojis/ApplicationEmojis.cs new file mode 100644 index 000000000..d3484e732 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Applications/Emojis/ApplicationEmojis.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Emojis +/// +public class ApplicationEmojis +{ + /// + /// List of application emojis + /// + [JsonProperty("items")] + public List Items { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/InstallParams.cs b/Oxide.Ext.Discord/Entities/Applications/InstallParams.cs index a049fb1cc..92a2d45e7 100644 --- a/Oxide.Ext.Discord/Entities/Applications/InstallParams.cs +++ b/Oxide.Ext.Discord/Entities/Applications/InstallParams.cs @@ -1,23 +1,22 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Install Params Structure +/// +public class InstallParams { /// - /// Represents a Install Params Structure + /// Scopes to add the application to the server with /// - public class InstallParams - { - /// - /// Scopes to add the application to the server with - /// - [JsonProperty("scopes")] - public List Scopes { get; set; } + [JsonProperty("scopes")] + public List Scopes { get; set; } - /// - /// Permissions to request for the bot role - /// - [JsonProperty("permissions")] - public string Permissions { get; set; } - } + /// + /// Permissions to request for the bot role + /// + [JsonProperty("permissions")] + public string Permissions { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/RoleConnection/ApplicationRoleConnectionMetadata.cs b/Oxide.Ext.Discord/Entities/Applications/RoleConnection/ApplicationRoleConnectionMetadata.cs index f9434044a..e05598d37 100644 --- a/Oxide.Ext.Discord/Entities/Applications/RoleConnection/ApplicationRoleConnectionMetadata.cs +++ b/Oxide.Ext.Discord/Entities/Applications/RoleConnection/ApplicationRoleConnectionMetadata.cs @@ -3,56 +3,55 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Role Connection Metadata Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ApplicationRoleConnectionMetadata : IDiscordValidation { /// - /// Represents Application Role Connection Metadata Structure + /// Type of metadata value /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ApplicationRoleConnectionMetadata : IDiscordValidation - { - /// - /// Type of metadata value - /// - [JsonProperty("type")] - public ApplicationRoleConnectionMetadataType Type { get; set; } + [JsonProperty("type")] + public ApplicationRoleConnectionMetadataType Type { get; set; } - /// - /// Dictionary key for the metadata field (must be a-z, 0-9, or _ characters; 1-50 characters) - /// - [JsonProperty("key")] - public string Key { get; set; } + /// + /// Dictionary key for the metadata field (must be a-z, 0-9, or _ characters; 1-50 characters) + /// + [JsonProperty("key")] + public string Key { get; set; } - /// - /// Name of the metadata field (1-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the metadata field (1-100 characters) + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Translations of the name - /// - [JsonProperty("name_localizations")] - public Hash NameLocalizations { get; set; } + /// + /// Translations of the name + /// + [JsonProperty("name_localizations")] + public Hash NameLocalizations { get; set; } - /// - /// Description of the metadata field (1-200 characters) - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of the metadata field (1-200 characters) + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Translations of the description - /// - [JsonProperty("description_localizations")] - public Hash DescriptionLocalizations { get; set; } + /// + /// Translations of the description + /// + [JsonProperty("description_localizations")] + public Hash DescriptionLocalizations { get; set; } - /// - public void Validate() - { - ApplicationRoleConnectionMetadataException.ThrowIfInvalidKeyException(Key); - ApplicationRoleConnectionMetadataException.ThrowIfInvalidNameException(Name); - ApplicationRoleConnectionMetadataException.ThrowIfInvalidDescriptionException(Description); - } + /// + public void Validate() + { + ApplicationRoleConnectionMetadataException.ThrowIfInvalidKeyException(Key); + ApplicationRoleConnectionMetadataException.ThrowIfInvalidNameException(Name); + ApplicationRoleConnectionMetadataException.ThrowIfInvalidDescriptionException(Description); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Applications/RoleConnection/ApplicationRoleConnectionMetadataType.cs b/Oxide.Ext.Discord/Entities/Applications/RoleConnection/ApplicationRoleConnectionMetadataType.cs index 3933058e4..c9bb2be10 100644 --- a/Oxide.Ext.Discord/Entities/Applications/RoleConnection/ApplicationRoleConnectionMetadataType.cs +++ b/Oxide.Ext.Discord/Entities/Applications/RoleConnection/ApplicationRoleConnectionMetadataType.cs @@ -1,48 +1,47 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Role Connection Metadata Type +/// +public enum ApplicationRoleConnectionMetadataType : byte { /// - /// Represents Application Role Connection Metadata Type + /// The metadata value (integer) is less than or equal to the guild's configured value (integer) /// - public enum ApplicationRoleConnectionMetadataType : byte - { - /// - /// The metadata value (integer) is less than or equal to the guild's configured value (integer) - /// - IntegerLessThanOrEqual = 1, + IntegerLessThanOrEqual = 1, - /// - /// The metadata value (integer) is greater than or equal to the guild's configured value (integer) - /// - IntegerGreaterThanOrEqual = 2, + /// + /// The metadata value (integer) is greater than or equal to the guild's configured value (integer) + /// + IntegerGreaterThanOrEqual = 2, - /// - /// The metadata value (integer) is equal to the guild's configured value (integer) - /// - IntegerEqual = 3, + /// + /// The metadata value (integer) is equal to the guild's configured value (integer) + /// + IntegerEqual = 3, - /// - /// The metadata value (integer) is not equal to the guild's configured value (integer) - /// - IntegerNotEqual = 4, + /// + /// The metadata value (integer) is not equal to the guild's configured value (integer) + /// + IntegerNotEqual = 4, - /// - /// The metadata value (ISO8601 string) is less than or equal to the guild's configured value (integer; days before current date) - /// - DatetimeLessThanOrEqual = 5, + /// + /// The metadata value (ISO8601 string) is less than or equal to the guild's configured value (integer; days before current date) + /// + DatetimeLessThanOrEqual = 5, - /// - /// The metadata value (ISO8601 string) is greater than or equal to the guild's configured value (integer; days before current date) - /// - DatetimeGreaterThanOrEqual = 6, + /// + /// The metadata value (ISO8601 string) is greater than or equal to the guild's configured value (integer; days before current date) + /// + DatetimeGreaterThanOrEqual = 6, - /// - /// The metadata value (integer) is equal to the guild's configured value (integer; 1) - /// - BooleanEqual = 7, + /// + /// The metadata value (integer) is equal to the guild's configured value (integer; 1) + /// + BooleanEqual = 7, - /// - /// The metadata value (integer) is not equal to the guild's configured value (integer; 1) - /// - BooleanNotEqual = 8, - } + /// + /// The metadata value (integer) is not equal to the guild's configured value (integer; 1) + /// + BooleanNotEqual = 8, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/AutoMod/AutoModAction.cs b/Oxide.Ext.Discord/Entities/AutoMod/AutoModAction.cs index 351d63c44..807264865 100644 --- a/Oxide.Ext.Discord/Entities/AutoMod/AutoModAction.cs +++ b/Oxide.Ext.Discord/Entities/AutoMod/AutoModAction.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Mod Action +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class AutoModAction { /// - /// Represents Auto Mod Action + /// Type of /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class AutoModAction - { - /// - /// Type of - /// - [JsonProperty("type")] - public AutoModActionType Type { get; set; } + [JsonProperty("type")] + public AutoModActionType Type { get; set; } - /// - /// Additional metadata needed during execution for this specific action type - /// - [JsonProperty("metadata")] - public AutoModActionMetadata Metadata { get; set; } - } + /// + /// Additional metadata needed during execution for this specific action type + /// + [JsonProperty("metadata")] + public AutoModActionMetadata Metadata { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/AutoMod/AutoModActionMetadata.cs b/Oxide.Ext.Discord/Entities/AutoMod/AutoModActionMetadata.cs index 5b83ad3aa..4e1315312 100644 --- a/Oxide.Ext.Discord/Entities/AutoMod/AutoModActionMetadata.cs +++ b/Oxide.Ext.Discord/Entities/AutoMod/AutoModActionMetadata.cs @@ -1,33 +1,32 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Mod Action Metadata +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class AutoModActionMetadata { /// - /// Represents Auto Mod Action Metadata + /// Associated Action Type: + /// Channel to which user content should be logged /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class AutoModActionMetadata - { - /// - /// Associated Action Type: - /// Channel to which user content should be logged - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// Associated Action Type: - /// Timeout duration in seconds - /// - [JsonProperty("duration_seconds")] - public int DurationSeconds { get; set; } + /// + /// Associated Action Type: + /// Timeout duration in seconds + /// + [JsonProperty("duration_seconds")] + public int DurationSeconds { get; set; } - /// - /// Associated Action Type: - /// Additional explanation that will be shown to members whenever their message is blocked - /// Max 150 characters - /// - [JsonProperty("custom_message")] - public int CustomMessage { get; set; } - } + /// + /// Associated Action Type: + /// Additional explanation that will be shown to members whenever their message is blocked + /// Max 150 characters + /// + [JsonProperty("custom_message")] + public int CustomMessage { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/AutoMod/AutoModActionType.cs b/Oxide.Ext.Discord/Entities/AutoMod/AutoModActionType.cs index 6708df746..b42706d1d 100644 --- a/Oxide.Ext.Discord/Entities/AutoMod/AutoModActionType.cs +++ b/Oxide.Ext.Discord/Entities/AutoMod/AutoModActionType.cs @@ -1,25 +1,29 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Mod Action Types +/// +public enum AutoModActionType : byte { /// - /// Represents Auto Mod Action Types + /// Blocks the content of a message according to the rule /// - public enum AutoModActionType : byte - { - /// - /// Blocks the content of a message according to the rule - /// - BlockMessage = 1, + BlockMessage = 1, - /// - /// Logs user content to a specified channel - /// - SendAlertMessage = 2, + /// + /// Logs user content to a specified channel + /// + SendAlertMessage = 2, - /// - /// Timeout user for a specified duration - /// A TIMEOUT action can only be setup for KEYWORD rules. - /// MODERATE_MEMBERS permission is required to use the TIMEOUT action type. - /// - Timeout = 3, - } + /// + /// Timeout user for a specified duration + /// A TIMEOUT action can only be setup for KEYWORD rules. + /// MODERATE_MEMBERS permission is required to use the TIMEOUT action type. + /// + Timeout = 3, + + /// + /// Prevents a member from using text, voice, or other interactions + /// + BlockMemberInteraction = 4, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/AutoMod/AutoModEventType.cs b/Oxide.Ext.Discord/Entities/AutoMod/AutoModEventType.cs index 121d41bbe..d7c5a5fab 100644 --- a/Oxide.Ext.Discord/Entities/AutoMod/AutoModEventType.cs +++ b/Oxide.Ext.Discord/Entities/AutoMod/AutoModEventType.cs @@ -1,13 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Mod Event Type +/// +public enum AutoModEventType : byte { /// - /// Represents Auto Mod Event Type + /// When a member sends or edits a message in the guild /// - public enum AutoModEventType : byte - { - /// - /// When a member sends or edits a message in the guild - /// - MessageSend = 1 - } + MessageSend = 1, + + /// + /// When a member edits their profile + /// + MemberUpdate = 1 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/AutoMod/AutoModKeywordPresetType.cs b/Oxide.Ext.Discord/Entities/AutoMod/AutoModKeywordPresetType.cs index 1bc41050b..7aa017e8d 100644 --- a/Oxide.Ext.Discord/Entities/AutoMod/AutoModKeywordPresetType.cs +++ b/Oxide.Ext.Discord/Entities/AutoMod/AutoModKeywordPresetType.cs @@ -1,23 +1,22 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Mod Keyword Preset Types +/// +public enum AutoModKeywordPresetType : byte { /// - /// Represents Auto Mod Keyword Preset Types + /// Words that may be considered forms of swearing or cursing /// - public enum AutoModKeywordPresetType : byte - { - /// - /// Words that may be considered forms of swearing or cursing - /// - Profanity = 1, + Profanity = 1, - /// - /// Words that refer to sexually explicit behavior or activity - /// - SexualContent = 2, + /// + /// Words that refer to sexually explicit behavior or activity + /// + SexualContent = 2, - /// - /// Personal insults or words that may be considered hate speech - /// - Slurs = 3, - } + /// + /// Personal insults or words that may be considered hate speech + /// + Slurs = 3, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/AutoMod/AutoModRule.cs b/Oxide.Ext.Discord/Entities/AutoMod/AutoModRule.cs index f11549f20..1cc299b0d 100644 --- a/Oxide.Ext.Discord/Entities/AutoMod/AutoModRule.cs +++ b/Oxide.Ext.Discord/Entities/AutoMod/AutoModRule.cs @@ -3,139 +3,138 @@ using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Mod Rule +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class AutoModRule { /// - /// Represents Auto Mod Rule + /// Id of this rule /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class AutoModRule - { - /// - /// Id of this rule - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// ID of the Guild which this rule belongs to - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + /// + /// ID of the Guild which this rule belongs to + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// Rule name - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Rule name + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// User which first created this rule - /// - [JsonProperty("creator_id")] - public Snowflake CreatorId { get; set; } + /// + /// User which first created this rule + /// + [JsonProperty("creator_id")] + public Snowflake CreatorId { get; set; } - /// - /// Rule - /// - [JsonProperty("event_type")] - public AutoModEventType EventType { get; set; } + /// + /// Rule + /// + [JsonProperty("event_type")] + public AutoModEventType EventType { get; set; } - /// - /// Rule - /// - [JsonProperty("trigger_type")] - public AutoModTriggerType TriggerType { get; set; } + /// + /// Rule + /// + [JsonProperty("trigger_type")] + public AutoModTriggerType TriggerType { get; set; } - /// - /// Rule - /// - [JsonProperty("trigger_metadata")] - public AutoModTriggerMetadata TriggerMetadata { get; set; } + /// + /// Rule + /// + [JsonProperty("trigger_metadata")] + public AutoModTriggerMetadata TriggerMetadata { get; set; } - /// - /// Actions which will execute when the rule is triggered - /// - [JsonProperty("actions")] - public List Actions { get; set; } + /// + /// Actions which will execute when the rule is triggered + /// + [JsonProperty("actions")] + public List Actions { get; set; } - /// - /// Whether the rule is enabled - /// - [JsonProperty("enabled")] - public bool Enabled { get; set; } + /// + /// Whether the rule is enabled + /// + [JsonProperty("enabled")] + public bool Enabled { get; set; } - /// - /// Role ids that should not be affected by the rule (Maximum of 20) - /// - [JsonProperty("exempt_roles")] - public List ExemptRoles { get; set; } + /// + /// Role ids that should not be affected by the rule (Maximum of 20) + /// + [JsonProperty("exempt_roles")] + public List ExemptRoles { get; set; } - /// - /// Channel ids that should not be affected by the rule (Maximum of 50) - /// - [JsonProperty("exempt_channels")] - public List ExemptChannels { get; set; } + /// + /// Channel ids that should not be affected by the rule (Maximum of 50) + /// + [JsonProperty("exempt_channels")] + public List ExemptChannels { get; set; } - /// - /// Modify an existing rule - /// Requires permissions. - /// See List Auto Moderation Rules for Guild - /// - /// Client to use - /// Guild ID to list the rules for - public static IPromise> GetAll(DiscordClient client, Snowflake guildId) - { - return client.Bot.Rest.Get>(client,$"guilds/{guildId}/auto-moderation/rules"); - } + /// + /// Modify an existing rule + /// Requires permissions. + /// See List Auto Moderation Rules for Guild + /// + /// Client to use + /// Guild ID to list the rules for + public static IPromise> GetAll(DiscordClient client, Snowflake guildId) + { + return client.Bot.Rest.Get>(client,$"guilds/{guildId}/auto-moderation/rules"); + } - /// - /// Get a single rule - /// Requires permissions. - /// See Get Auto Moderation Rule - /// - /// Client to use - /// Guild ID of the rule - /// Rule ID to get the rule for - public static IPromise Get(DiscordClient client, Snowflake guildId, Snowflake ruleId) - { - return client.Bot.Rest.Get(client,$"guilds/{guildId}/auto-moderation/rules/{ruleId}"); - } + /// + /// Get a single rule + /// Requires permissions. + /// See Get Auto Moderation Rule + /// + /// Client to use + /// Guild ID of the rule + /// Rule ID to get the rule for + public static IPromise Get(DiscordClient client, Snowflake guildId, Snowflake ruleId) + { + return client.Bot.Rest.Get(client,$"guilds/{guildId}/auto-moderation/rules/{ruleId}"); + } - /// - /// Create a new rule - /// Requires permissions. - /// See Create Auto Moderation Rule - /// - /// Client to use - /// Guild ID of the rule - /// Rule to be created - public static IPromise Create(DiscordClient client, Snowflake guildId, AutoModRuleCreate create) - { - return client.Bot.Rest.Post(client,$"guilds/{guildId}/auto-moderation/rules", create); - } + /// + /// Create a new rule + /// Requires permissions. + /// See Create Auto Moderation Rule + /// + /// Client to use + /// Guild ID of the rule + /// Rule to be created + public static IPromise Create(DiscordClient client, Snowflake guildId, AutoModRuleCreate create) + { + return client.Bot.Rest.Post(client,$"guilds/{guildId}/auto-moderation/rules", create); + } - /// - /// Modify an existing rule - /// Requires permissions. - /// See Modify Auto Moderation Rule - /// - /// Client to use - /// - public IPromise Edit(DiscordClient client, AutoModRuleModify modify) - { - return client.Bot.Rest.Patch(client,$"guilds/{GuildId}/auto-moderation/rules/{Id}", modify); - } + /// + /// Modify an existing rule + /// Requires permissions. + /// See Modify Auto Moderation Rule + /// + /// Client to use + /// + public IPromise Edit(DiscordClient client, AutoModRuleModify modify) + { + return client.Bot.Rest.Patch(client,$"guilds/{GuildId}/auto-moderation/rules/{Id}", modify); + } - /// - /// Delete a rule - /// Requires permissions. - /// See Delete Auto Moderation Rule - /// - /// Client to use - public IPromise Delete(DiscordClient client) - { - return client.Bot.Rest.Delete(client,$"guilds/{GuildId}/auto-moderation/rules/{Id}"); - } + /// + /// Delete a rule + /// Requires permissions. + /// See Delete Auto Moderation Rule + /// + /// Client to use + public IPromise Delete(DiscordClient client) + { + return client.Bot.Rest.Delete(client,$"guilds/{GuildId}/auto-moderation/rules/{Id}"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/AutoMod/AutoModRuleCreate.cs b/Oxide.Ext.Discord/Entities/AutoMod/AutoModRuleCreate.cs index 7e9ec653e..ffdfb8e7a 100644 --- a/Oxide.Ext.Discord/Entities/AutoMod/AutoModRuleCreate.cs +++ b/Oxide.Ext.Discord/Entities/AutoMod/AutoModRuleCreate.cs @@ -2,66 +2,65 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Mod Rule Create +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class AutoModRuleCreate : IDiscordValidation { /// - /// Represents Auto Mod Rule Create + /// Rule name /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class AutoModRuleCreate : IDiscordValidation - { - /// - /// Rule name - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Rule - /// - [JsonProperty("event_type")] - public AutoModEventType EventType { get; set; } + /// + /// Rule + /// + [JsonProperty("event_type")] + public AutoModEventType EventType { get; set; } - /// - /// Rule - /// - [JsonProperty("trigger_type")] - public AutoModTriggerType TriggerType { get; set; } + /// + /// Rule + /// + [JsonProperty("trigger_type")] + public AutoModTriggerType TriggerType { get; set; } - /// - /// Rule - /// - [JsonProperty("trigger_metadata")] - public AutoModTriggerMetadata TriggerMetadata { get; set; } + /// + /// Rule + /// + [JsonProperty("trigger_metadata")] + public AutoModTriggerMetadata TriggerMetadata { get; set; } - /// - /// Actions which will execute when the rule is triggered - /// - [JsonProperty("actions")] - public List Actions { get; set; } + /// + /// Actions which will execute when the rule is triggered + /// + [JsonProperty("actions")] + public List Actions { get; set; } - /// - /// Whether the rule is enabled - /// - [JsonProperty("enabled")] - public bool Enabled { get; set; } + /// + /// Whether the rule is enabled + /// + [JsonProperty("enabled")] + public bool Enabled { get; set; } - /// - /// Role ids that should not be affected by the rule (Maximum of 20) - /// - [JsonProperty("exempt_roles")] - public List ExemptRoles { get; set; } + /// + /// Role ids that should not be affected by the rule (Maximum of 20) + /// + [JsonProperty("exempt_roles")] + public List ExemptRoles { get; set; } - /// - /// Channel ids that should not be affected by the rule (Maximum of 50) - /// - [JsonProperty("exempt_channels")] - public List ExemptChannels { get; set; } + /// + /// Channel ids that should not be affected by the rule (Maximum of 50) + /// + [JsonProperty("exempt_channels")] + public List ExemptChannels { get; set; } - /// - public void Validate() - { - TriggerMetadata?.Validate(TriggerType); - } + /// + public void Validate() + { + TriggerMetadata?.Validate(TriggerType); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/AutoMod/AutoModRuleModify.cs b/Oxide.Ext.Discord/Entities/AutoMod/AutoModRuleModify.cs index a30c3fcc4..6e121c41a 100644 --- a/Oxide.Ext.Discord/Entities/AutoMod/AutoModRuleModify.cs +++ b/Oxide.Ext.Discord/Entities/AutoMod/AutoModRuleModify.cs @@ -2,75 +2,74 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Mod Rule Modify +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class AutoModRuleModify : IDiscordValidation { /// - /// Represents Auto Mod Rule Modify + /// Rule name /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class AutoModRuleModify : IDiscordValidation - { - /// - /// Rule name - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Rule - /// - [JsonProperty("event_type")] - public AutoModEventType EventType { get; set; } + /// + /// Rule + /// + [JsonProperty("event_type")] + public AutoModEventType EventType { get; set; } - /// - /// Rule - /// - [JsonProperty("trigger_metadata")] - public AutoModTriggerMetadata TriggerMetadata { get; set; } + /// + /// Rule + /// + [JsonProperty("trigger_metadata")] + public AutoModTriggerMetadata TriggerMetadata { get; set; } - /// - /// Actions which will execute when the rule is triggered - /// - [JsonProperty("actions")] - public List Actions { get; set; } + /// + /// Actions which will execute when the rule is triggered + /// + [JsonProperty("actions")] + public List Actions { get; set; } - /// - /// Whether the rule is enabled - /// - [JsonProperty("enabled")] - public bool Enabled { get; set; } + /// + /// Whether the rule is enabled + /// + [JsonProperty("enabled")] + public bool Enabled { get; set; } - /// - /// Role ids that should not be affected by the rule (Maximum of 20) - /// - [JsonProperty("exempt_roles")] - public List ExemptRoles { get; set; } + /// + /// Role ids that should not be affected by the rule (Maximum of 20) + /// + [JsonProperty("exempt_roles")] + public List ExemptRoles { get; set; } - /// - /// Channel ids that should not be affected by the rule (Maximum of 50) - /// - [JsonProperty("exempt_channels")] - public List ExemptChannels { get; set; } + /// + /// Channel ids that should not be affected by the rule (Maximum of 50) + /// + [JsonProperty("exempt_channels")] + public List ExemptChannels { get; set; } - /// - /// Rule - /// - [JsonIgnore] - public AutoModTriggerType TriggerType { get; private set; } + /// + /// Rule + /// + [JsonIgnore] + public AutoModTriggerType TriggerType { get; private set; } - /// - /// Constructor - /// - /// Trigger type being modified - public AutoModRuleModify(AutoModTriggerType triggerType) - { - TriggerType = triggerType; - } + /// + /// Constructor + /// + /// Trigger type being modified + public AutoModRuleModify(AutoModTriggerType triggerType) + { + TriggerType = triggerType; + } - /// - public void Validate() - { - TriggerMetadata?.Validate(TriggerType); - } + /// + public void Validate() + { + TriggerMetadata?.Validate(TriggerType); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/AutoMod/AutoModTriggerMetadata.cs b/Oxide.Ext.Discord/Entities/AutoMod/AutoModTriggerMetadata.cs index 84bdf9677..6153fae30 100644 --- a/Oxide.Ext.Discord/Entities/AutoMod/AutoModTriggerMetadata.cs +++ b/Oxide.Ext.Discord/Entities/AutoMod/AutoModTriggerMetadata.cs @@ -2,64 +2,63 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Mod Trigger Metadata +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class AutoModTriggerMetadata { /// - /// Represents Auto Mod Trigger Metadata + /// Associated Trigger Types: + /// Substrings which will be searched for in content /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class AutoModTriggerMetadata - { - /// - /// Associated Trigger Types: - /// Substrings which will be searched for in content - /// - [JsonProperty("keyword_filter")] - public List KeywordFilter { get; set; } + [JsonProperty("keyword_filter")] + public List KeywordFilter { get; set; } - /// - /// Associated Trigger Types: - /// Regular expression patterns which will be matched against content (Maximum of 10) - /// * Only Rust flavored regex is currently supported, which can be tested in online editors such as Rustexp. Each regex pattern must be 260 characters or less. - /// - [JsonProperty("regex_patterns")] - public List RegexPatterns { get; set; } + /// + /// Associated Trigger Types: + /// Regular expression patterns which will be matched against content (Maximum of 10) + /// * Only Rust flavored regex is currently supported, which can be tested in online editors such as Rustexp. Each regex pattern must be 260 characters or less. + /// + [JsonProperty("regex_patterns")] + public List RegexPatterns { get; set; } - /// - /// Associated Trigger Types: - /// The internally pre-defined wordsets which will be searched for in content - /// - [JsonProperty("presets")] - public List Presets { get; set; } + /// + /// Associated Trigger Types: + /// The internally pre-defined wordsets which will be searched for in content + /// + [JsonProperty("presets")] + public List Presets { get; set; } - /// - /// Associated Trigger Types: and - /// Substrings which should not trigger the rule (Maximum of 100 or 1000) - /// - [JsonProperty("allow_list")] - public List AllowList { get; set; } + /// + /// Associated Trigger Types: and + /// Substrings which should not trigger the rule (Maximum of 100 or 1000) + /// + [JsonProperty("allow_list")] + public List AllowList { get; set; } - /// - /// Associated Trigger Types: - /// Total number of unique role and user mentions allowed per message - /// Maximum of 50 - /// - [JsonProperty("mention_total_limit")] - public int MentionTotalLimit { get; set; } + /// + /// Associated Trigger Types: + /// Total number of unique role and user mentions allowed per message + /// Maximum of 50 + /// + [JsonProperty("mention_total_limit")] + public int MentionTotalLimit { get; set; } - /// - /// Associated Trigger Types: - /// Whether to automatically detect mention raids - /// - [JsonProperty("mention_raid_protection_enabled")] - public bool MentionRaidProtectionEnabled { get; set; } + /// + /// Associated Trigger Types: + /// Whether to automatically detect mention raids + /// + [JsonProperty("mention_raid_protection_enabled")] + public bool MentionRaidProtectionEnabled { get; set; } - internal void Validate(AutoModTriggerType type) - { - AutoModTriggerMetadataException.ThrowIfKeywordFilterInvalid(KeywordFilter); - AutoModTriggerMetadataException.ThrowIfRegexPatternsInvalid(RegexPatterns); - AutoModTriggerMetadataException.ThrowIfAllowListInvalid(RegexPatterns, type); - AutoModTriggerMetadataException.ThrowIfInvalidMentionTotalLimit(MentionTotalLimit); - } + internal void Validate(AutoModTriggerType type) + { + AutoModTriggerMetadataException.ThrowIfKeywordFilterInvalid(KeywordFilter); + AutoModTriggerMetadataException.ThrowIfRegexPatternsInvalid(RegexPatterns); + AutoModTriggerMetadataException.ThrowIfAllowListInvalid(RegexPatterns, type); + AutoModTriggerMetadataException.ThrowIfInvalidMentionTotalLimit(MentionTotalLimit); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/AutoMod/AutoModTriggerType.cs b/Oxide.Ext.Discord/Entities/AutoMod/AutoModTriggerType.cs index 7e9af0ff5..89e27c8bb 100644 --- a/Oxide.Ext.Discord/Entities/AutoMod/AutoModTriggerType.cs +++ b/Oxide.Ext.Discord/Entities/AutoMod/AutoModTriggerType.cs @@ -1,28 +1,32 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Mod Trigger Types +/// +public enum AutoModTriggerType : byte { /// - /// Represents Auto Mod Trigger Types + /// Check if content contains words from a user defined list of keywords /// - public enum AutoModTriggerType : byte - { - /// - /// Check if content contains words from a user defined list of keywords - /// - Keyword = 1, + Keyword = 1, - /// - /// Check if content represents generic spam - /// - Spam = 3, + /// + /// Check if content represents generic spam + /// + Spam = 3, + + /// + /// Check if content contains words from internal pre-defined wordsets + /// + KeywordPreset = 4, - /// - /// Check if content contains words from internal pre-defined wordsets - /// - KeywordPreset = 4, + /// + /// Check if content contains more unique mentions than allowed + /// + MentionSpam = 5, - /// - /// Check if content contains more unique mentions than allowed - /// - MentionSpam = 5, - } + /// + /// Check if member profile contains words from a user defined list of keywords + /// + MemberProfile = 6, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/ChannelCreate.cs b/Oxide.Ext.Discord/Entities/Channels/ChannelCreate.cs index 697a34c04..5824bf3c9 100644 --- a/Oxide.Ext.Discord/Entities/Channels/ChannelCreate.cs +++ b/Oxide.Ext.Discord/Entities/Channels/ChannelCreate.cs @@ -3,125 +3,124 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Guild Channel Create Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ChannelCreate : IDiscordValidation { /// - /// Represents a Guild Channel Create Structure + /// The name of the channel (1-100 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ChannelCreate : IDiscordValidation - { - /// - /// The name of the channel (1-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// the type of channel - /// - [JsonProperty("type")] - public ChannelType Type { get; set; } + /// + /// the type of channel + /// + [JsonProperty("type")] + public ChannelType Type { get; set; } - /// - /// The channel topic - /// (0-4096 characters for GUILD_FORUM & GUILD_MEDIA Channels) - /// (0-1024 characters for all others) - /// - [JsonProperty("topic")] - public string Topic { get; set; } + /// + /// The channel topic + /// (0-4096 characters for GUILD_FORUM & GUILD_MEDIA Channels) + /// (0-1024 characters for all others) + /// + [JsonProperty("topic")] + public string Topic { get; set; } - /// - /// The bitrate (in bits) of the voice channel - /// 8000 to 96000 (128000 for VIP servers) - /// - [JsonProperty("bitrate")] - public int? Bitrate { get; set; } + /// + /// The bitrate (in bits) of the voice channel + /// 8000 to 96000 (128000 for VIP servers) + /// + [JsonProperty("bitrate")] + public int? Bitrate { get; set; } - /// - /// The user limit of the voice channel - /// 0 refers to no limit, 1 to 99 refers to a user limit - /// - [JsonProperty("user_limit")] - public int? UserLimit { get; set; } + /// + /// The user limit of the voice channel + /// 0 refers to no limit, 1 to 99 refers to a user limit + /// + [JsonProperty("user_limit")] + public int? UserLimit { get; set; } - /// - /// Amount of seconds a user has to wait before sending another message (0-21600); - /// bots, as well as users with the permission manage_messages or manage_channel, are unaffected - /// - [JsonProperty("rate_limit_per_user")] - public int? RateLimitPerUser { get; set; } + /// + /// Amount of seconds a user has to wait before sending another message (0-21600); + /// bots, as well as users with the permission manage_messages or manage_channel, are unaffected + /// + [JsonProperty("rate_limit_per_user")] + public int? RateLimitPerUser { get; set; } - /// - /// Sorting position of the channel - /// - [JsonProperty("position")] - public int? Position { get; set; } + /// + /// Sorting position of the channel + /// + [JsonProperty("position")] + public int? Position { get; set; } - /// - /// Explicit permission overwrites for members and roles - /// - [JsonProperty("permission_overwrites")] - public List PermissionOverwrites { get; set; } + /// + /// Explicit permission overwrites for members and roles + /// + [JsonProperty("permission_overwrites")] + public List PermissionOverwrites { get; set; } - /// - /// ID of the parent category for a channel (each parent category can contain up to 50 channels) - /// - [JsonProperty("parent_id")] - public Snowflake? ParentId { get; set; } + /// + /// ID of the parent category for a channel (each parent category can contain up to 50 channels) + /// + [JsonProperty("parent_id")] + public Snowflake? ParentId { get; set; } - /// - /// Whether the channel is nsfw - /// - [JsonProperty("nsfw")] - public bool? Nsfw { get; set; } + /// + /// Whether the channel is nsfw + /// + [JsonProperty("nsfw")] + public bool? Nsfw { get; set; } - /// - /// The default duration that the clients use (not the API) for newly created threads in the channel, in minutes, to automatically archive the thread after recent activity - /// - [JsonProperty("default_auto_archive_duration")] - public int DefaultAutoArchiveDuration { get; set; } + /// + /// The default duration that the clients use (not the API) for newly created threads in the channel, in minutes, to automatically archive the thread after recent activity + /// + [JsonProperty("default_auto_archive_duration")] + public int DefaultAutoArchiveDuration { get; set; } - /// - /// Emoji to show in the add reaction button on a thread in a `GUILD_FORUM` or `GUILD_MEDIA` channel - /// - [JsonProperty("default_reaction_emoji")] - public DefaultReaction DefaultReactionEmoji { get; set; } + /// + /// Emoji to show in the add reaction button on a thread in a `GUILD_FORUM` or `GUILD_MEDIA` channel + /// + [JsonProperty("default_reaction_emoji")] + public DefaultReaction DefaultReactionEmoji { get; set; } - /// - /// Set of tags that can be used in a `GUILD_FORUM` or GUILD_MEDIA channel - /// - [JsonProperty("available_tags")] - public List AvailableTags { get; set; } + /// + /// Set of tags that can be used in a `GUILD_FORUM` or GUILD_MEDIA channel + /// + [JsonProperty("available_tags")] + public List AvailableTags { get; set; } - /// - /// The default used to order posts in `GUILD_FORUM` or `GUILD_MEDIA` channels - /// - [JsonProperty("default_sort_order")] - public SortOrderType? DefaultSortOrder { get; set; } + /// + /// The default used to order posts in `GUILD_FORUM` or `GUILD_MEDIA` channels + /// + [JsonProperty("default_sort_order")] + public SortOrderType? DefaultSortOrder { get; set; } - /// - /// The default used to display posts in GUILD_FORUM channels. - /// Defaults to , which indicates a layout view has not been set by a channel admin - /// - [JsonProperty("default_forum_layout")] - public ForumLayoutTypes? DefaultForumLayout { get; set; } + /// + /// The default used to display posts in GUILD_FORUM channels. + /// Defaults to , which indicates a layout view has not been set by a channel admin + /// + [JsonProperty("default_forum_layout")] + public ForumLayoutTypes? DefaultForumLayout { get; set; } - /// - /// The initial rate_limit_per_user to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. - /// - [JsonProperty("default_thread_rate_limit_per_user")] - public int? DefaultThreadRateLimitPerUser { get; set; } + /// + /// The initial rate_limit_per_user to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. + /// + [JsonProperty("default_thread_rate_limit_per_user")] + public int? DefaultThreadRateLimitPerUser { get; set; } - /// - public void Validate() - { - InvalidChannelException.ThrowIfInvalidName(Name, false); - InvalidChannelException.ThrowIfInvalidTopic(Topic, Type, true); - InvalidChannelException.ThrowIfInvalidUserLimit(UserLimit); - InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); - InvalidChannelException.ThrowIfInvalidBitRate(Bitrate); - InvalidChannelException.ThrowIfInvalidParentId(ParentId); - } + /// + public void Validate() + { + InvalidChannelException.ThrowIfInvalidName(Name, false); + InvalidChannelException.ThrowIfInvalidTopic(Topic, Type, true); + InvalidChannelException.ThrowIfInvalidUserLimit(UserLimit); + InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); + InvalidChannelException.ThrowIfInvalidBitRate(Bitrate); + InvalidChannelException.ThrowIfInvalidParentId(ParentId); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/ChannelFlags.cs b/Oxide.Ext.Discord/Entities/Channels/ChannelFlags.cs index 71a858279..e4ef2b6dc 100644 --- a/Oxide.Ext.Discord/Entities/Channels/ChannelFlags.cs +++ b/Oxide.Ext.Discord/Entities/Channels/ChannelFlags.cs @@ -1,31 +1,30 @@ using System; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Channel Flags +/// +[Flags] +public enum ChannelFlags { /// - /// Represents Channel Flags + /// Represents no channel flags /// - [Flags] - public enum ChannelFlags - { - /// - /// Represents no channel flags - /// - None = 0, + None = 0, - /// - /// This thread is pinned to the top of its parent GUILD_FORUM channel - /// - Pinned = 1 << 1, + /// + /// This thread is pinned to the top of its parent GUILD_FORUM channel + /// + Pinned = 1 << 1, - /// - /// Whether a tag is required to be specified when creating a thread in a GUILD_FORUM channel. Tags are specified in the applied_tags field. - /// - RequireTag = 1 << 4, + /// + /// Whether a tag is required to be specified when creating a thread in a GUILD_FORUM channel. Tags are specified in the applied_tags field. + /// + RequireTag = 1 << 4, - /// - /// When set hides the embedded media download options. Available only for media channels - /// - HideMediaDownloadOptions = 1 << 15, - } + /// + /// When set hides the embedded media download options. Available only for media channels + /// + HideMediaDownloadOptions = 1 << 15, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/ChannelInvite.cs b/Oxide.Ext.Discord/Entities/Channels/ChannelInvite.cs index 4a2c5a713..6433cc768 100644 --- a/Oxide.Ext.Discord/Entities/Channels/ChannelInvite.cs +++ b/Oxide.Ext.Discord/Entities/Channels/ChannelInvite.cs @@ -2,63 +2,62 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Channel Invite Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ChannelInvite : IDiscordValidation { /// - /// Represents a Channel Invite Structure + /// Duration of invite in seconds before expiry, or 0 for never /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ChannelInvite : IDiscordValidation - { - /// - /// Duration of invite in seconds before expiry, or 0 for never - /// - [JsonProperty("max_age")] - public int? MaxAge { get; set; } + [JsonProperty("max_age")] + public int? MaxAge { get; set; } - /// - /// Max number of uses or 0 for unlimited - /// - [JsonProperty("max_uses")] - public int? MaxUses { get; set; } + /// + /// Max number of uses or 0 for unlimited + /// + [JsonProperty("max_uses")] + public int? MaxUses { get; set; } - /// - /// Whether this invite only grants temporary membership - /// - [JsonProperty("temporary")] - public bool? Temporary { get; set; } + /// + /// Whether this invite only grants temporary membership + /// + [JsonProperty("temporary")] + public bool? Temporary { get; set; } - /// - /// If true, don't try to reuse a similar invite (useful for creating many unique one time use invites) - /// - [JsonProperty("unique")] - public bool? Unique { get; set; } + /// + /// If true, don't try to reuse a similar invite (useful for creating many unique one time use invites) + /// + [JsonProperty("unique")] + public bool? Unique { get; set; } - /// - /// The type of target user for this invite - /// - [JsonProperty("target_user_type")] - public TargetUserType? TargetUserType { get; set; } + /// + /// The type of target user for this invite + /// + [JsonProperty("target_user_type")] + public TargetUserType? TargetUserType { get; set; } - /// - /// The target user id for this invite - /// - [JsonProperty("target_user_id")] - public Snowflake? TargetUser { get; set; } + /// + /// The target user id for this invite + /// + [JsonProperty("target_user_id")] + public Snowflake? TargetUser { get; set; } - /// - /// The id of the embedded application to open for this invite, - /// Required if TargetUserType is EMBEDDED_APPLICATION, the application must have the EMBEDDED flag - /// - [JsonProperty("target_application_id")] - public Snowflake? TargetApplicationId { get; set; } + /// + /// The id of the embedded application to open for this invite, + /// Required if TargetUserType is EMBEDDED_APPLICATION, the application must have the EMBEDDED flag + /// + [JsonProperty("target_application_id")] + public Snowflake? TargetApplicationId { get; set; } - /// - public void Validate() - { - InvalidChannelInviteException.ThrowIfInvalidMaxAge(MaxAge); - InvalidChannelInviteException.ThrowIfInvalidMaxUses(MaxUses); - InvalidChannelInviteException.ThrowIfInvalidTargetUser(TargetUser); - } + /// + public void Validate() + { + InvalidChannelInviteException.ThrowIfInvalidMaxAge(MaxAge); + InvalidChannelInviteException.ThrowIfInvalidMaxUses(MaxUses); + InvalidChannelInviteException.ThrowIfInvalidTargetUser(TargetUser); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/ChannelMention.cs b/Oxide.Ext.Discord/Entities/Channels/ChannelMention.cs index f7777e105..01accc1e4 100644 --- a/Oxide.Ext.Discord/Entities/Channels/ChannelMention.cs +++ b/Oxide.Ext.Discord/Entities/Channels/ChannelMention.cs @@ -1,37 +1,36 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Channel Mention Structure in a message +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ChannelMention : ISnowflakeEntity { /// - /// Represents a Channel Mention Structure in a message + /// ID of the channel /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ChannelMention : ISnowflakeEntity - { - /// - /// ID of the channel - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// ID of the guild containing the channel - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + /// + /// ID of the guild containing the channel + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The type of channel - /// - /// - [JsonProperty("type")] - public ChannelType Type { get; set; } + /// + /// The type of channel + /// + /// + [JsonProperty("type")] + public ChannelType Type { get; set; } - /// - /// The name of the channel - /// - [JsonProperty("name")] - public string Name { get; set; } - } + /// + /// The name of the channel + /// + [JsonProperty("name")] + public string Name { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/ChannelMessagesRequest.cs b/Oxide.Ext.Discord/Entities/Channels/ChannelMessagesRequest.cs index b448f9f2f..51f5d152d 100644 --- a/Oxide.Ext.Discord/Entities/Channels/ChannelMessagesRequest.cs +++ b/Oxide.Ext.Discord/Entities/Channels/ChannelMessagesRequest.cs @@ -1,64 +1,62 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Get Channel Messages Request +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ChannelMessagesRequest : IDiscordQueryString { /// - /// Represents Get Channel Messages Request + /// Get messages around this message ID + /// Before, after, and around keys are mutually exclusive, only one may be passed at a time /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ChannelMessagesRequest : IDiscordQueryString - { - /// - /// Get messages around this message ID - /// Before, after, and around keys are mutually exclusive, only one may be passed at a time - /// - public Snowflake? Around { get; set; } + public Snowflake? Around { get; set; } - /// - /// Get messages before this message ID - /// Before, after, and around keys are mutually exclusive, only one may be passed at a time - /// - public Snowflake? Before { get; set; } + /// + /// Get messages before this message ID + /// Before, after, and around keys are mutually exclusive, only one may be passed at a time + /// + public Snowflake? Before { get; set; } - /// - /// Get messages after this message ID - /// Before, after, and around keys are mutually exclusive, only one may be passed at a time - /// - public Snowflake? After { get; set; } + /// + /// Get messages after this message ID + /// Before, after, and around keys are mutually exclusive, only one may be passed at a time + /// + public Snowflake? After { get; set; } - /// - /// Max number of messages to return (1-100) - /// - public int? Limit { get; set; } + /// + /// Max number of messages to return (1-100) + /// + public int? Limit { get; set; } - /// - public string ToQueryString() - { - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); + /// + public string ToQueryString() + { + QueryStringBuilder builder = new(); - //Per Documentation "The before, after, and around keys are mutually exclusive, only one may be passed at a time." - if (Around.HasValue) - { - builder.Add("around", Around.Value.ToString()); - } - else if (Before.HasValue) - { - builder.Add("before", Before.Value.ToString()); - } - else if (After.HasValue) - { - builder.Add("after", After.Value.ToString()); - } + //Per Documentation "The before, after, and around keys are mutually exclusive, only one may be passed at a time." + if (Around.HasValue) + { + builder.Add("around", Around.Value.ToString()); + } + else if (Before.HasValue) + { + builder.Add("before", Before.Value.ToString()); + } + else if (After.HasValue) + { + builder.Add("after", After.Value.ToString()); + } - if (Limit.HasValue) - { - builder.Add("limit", Limit.Value.ToString()); - } - - return builder.ToStringAndFree(); + if (Limit.HasValue) + { + builder.Add("limit", Limit.Value.ToString()); } + + return builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/ChannelType.cs b/Oxide.Ext.Discord/Entities/Channels/ChannelType.cs index f3d09b075..b18fbb515 100644 --- a/Oxide.Ext.Discord/Entities/Channels/ChannelType.cs +++ b/Oxide.Ext.Discord/Entities/Channels/ChannelType.cs @@ -1,73 +1,72 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Types of Channels +/// +public enum ChannelType : byte { /// - /// Represents a Types of Channels + /// A text channel within a server /// - public enum ChannelType : byte - { - /// - /// A text channel within a server - /// - GuildText = 0, + GuildText = 0, - /// - /// A direct message between users - /// - Dm = 1, + /// + /// A direct message between users + /// + Dm = 1, - /// - /// A voice channel within a server - /// - GuildVoice = 2, + /// + /// A voice channel within a server + /// + GuildVoice = 2, - /// - /// A direct message between multiple users - /// - GroupDm = 3, + /// + /// A direct message between multiple users + /// + GroupDm = 3, - /// - /// An organizational category that contains up to 50 channels - /// - GuildCategory = 4, + /// + /// An organizational category that contains up to 50 channels + /// + GuildCategory = 4, - /// - /// A channel that users can follow and crosspost into their own server - /// - GuildNews = 5, + /// + /// A channel that users can follow and crosspost into their own server + /// + GuildNews = 5, - /// - /// A temporary sub-channel within a GUILD_NEWS channel - /// - GuildNewsThread = 10, + /// + /// A temporary sub-channel within a GUILD_NEWS channel + /// + GuildNewsThread = 10, - /// - /// A temporary sub-channel within a GUILD_TEXT or GUILD_FORUM channel - /// - GuildPublicThread = 11, + /// + /// A temporary sub-channel within a GUILD_TEXT or GUILD_FORUM channel + /// + GuildPublicThread = 11, - /// - /// A temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission - /// - GuildPrivateThread = 12, + /// + /// A temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission + /// + GuildPrivateThread = 12, - /// - /// A voice channel for hosting events with an audience - /// - GuildStageVoice = 13, + /// + /// A voice channel for hosting events with an audience + /// + GuildStageVoice = 13, - /// - /// The channel in a hub - /// - GuildDirectory = 14, + /// + /// The channel in a hub + /// + GuildDirectory = 14, - /// - /// A channel that can only contain threads - /// - GuildForum = 15, + /// + /// A channel that can only contain threads + /// + GuildForum = 15, - /// - /// Channel that can only contain threads, similar to `GUILD_FORUM` channels - /// - GuildMedia = 16, - } -} + /// + /// Channel that can only contain threads, similar to `GUILD_FORUM` channels + /// + GuildMedia = 16, +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/DiscordChannel.cs b/Oxide.Ext.Discord/Entities/Channels/DiscordChannel.cs index edb8d80ac..88a00996c 100644 --- a/Oxide.Ext.Discord/Entities/Channels/DiscordChannel.cs +++ b/Oxide.Ext.Discord/Entities/Channels/DiscordChannel.cs @@ -12,908 +12,907 @@ using Oxide.Plugins; using UserData = Oxide.Ext.Discord.Data.UserData; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a guild or DM Channel Structure within Discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordChannel : ISnowflakeEntity, IDebugLoggable { /// - /// Represents a guild or DM Channel Structure within Discord. - /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordChannel : ISnowflakeEntity, IDebugLoggable - { - /// - /// The ID of this channel - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } - - /// - /// the type of channel - /// - [JsonProperty("type")] - public ChannelType Type { get; set; } - - /// - /// the ID of the guild - /// Warning: May be missing for some channel objects received over gateway guild dispatches - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } - - /// - /// Sorting position of the channel - /// - [JsonProperty("position")] - public int? Position { get; set; } - - /// - /// Explicit permission overwrites for members and roles - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("permission_overwrites")] - public Hash PermissionOverwrites { get; set; } - - /// - /// The name of the channel (1-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// The channel topic (0-1024 characters) - /// - [JsonProperty("topic")] - public string Topic { get; set; } - - /// - /// Whether the channel is nsfw - /// - [JsonProperty("nsfw")] - public bool? Nsfw { get; set; } - - /// - /// The id of the last message sent in this channel (or thread for GUILD_FORUM or GUILD_MEDIA channels) - /// May not point to an existing or valid message or thread - /// - [JsonProperty("last_message_id")] - public Snowflake? LastMessageId { get; set; } - - /// - /// The bitrate (in bits) of the voice channel - /// - [JsonProperty("bitrate")] - public int? Bitrate { get; set; } - - /// - /// The user limit of the voice channel - /// - [JsonProperty("user_limit")] - public int? UserLimit { get; set; } - - /// - /// Amount of seconds a user has to wait before sending another message (0-21600); - /// bots, as well as users with the permission manage_messages or manage_channel, are unaffected - /// - [JsonProperty("rate_limit_per_user")] - public int? RateLimitPerUser { get; set; } - - /// - /// The recipients of the DM - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("recipients")] - public Hash Recipients { get; set; } - - /// - /// icon hash of the group DM - /// - [JsonProperty("icon")] - public string Icon { get; set; } - - /// - /// ID of the DM creator - /// - [JsonProperty("owner_id")] - public Snowflake? OwnerId { get; set; } - - /// - /// Application id of the group DM creator if it is bot-created - /// - [JsonProperty("application_id")] - public Snowflake? ApplicationId { get; set; } - - /// - /// For group DM channels: whether the channel is managed by an application via the `gdm.join` OAuth2 scope - /// - [JsonProperty("managed")] - public bool? Managed { get; set; } - - /// - /// ID of the parent category for a channel (each parent category can contain up to 50 channels) - /// - [JsonProperty("parent_id")] - public Snowflake? ParentId { get; set; } - - /// - /// When the last pinned message was pinned. - /// This may be null in events such as GUILD_CREATE when a message is not pinned. - /// - [JsonProperty("last_pin_timestamp")] - public DateTime? LastPinTimestamp { get; set; } - - /// - /// Voice region id for the voice channel, automatic when set to null - /// - [JsonProperty("rtc_region")] - public string RtcRegion { get; set; } - - /// - /// The camera video quality mode of the voice channel - /// 1 when not present - /// - [JsonProperty("video_quality_mode")] - public VideoQualityMode? VideoQualityMode { get; set; } - - /// - /// umber of messages (not including the initial messages or deleted messages) in a thread (if the thread was created before July 1, 2022, it stops counting at 50) - /// - [JsonProperty("message_count")] - public int? MessageCount { get; set; } - - /// - /// An approximate count of users in a thread, stops counting at 50 - /// - [JsonProperty("member_count")] - public int? MemberCount { get; set; } - - /// - /// Thread-specific fields not needed by other channels - /// - [JsonProperty("thread_metadata")] - public ThreadMetadata ThreadMetadata { get; set; } - - /// - /// Thread member object for the current user, if they have joined the thread, only included on certain API endpoints - /// - [JsonProperty("member")] - public ThreadMember Member { get; set; } - - /// - /// Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 - /// - [JsonProperty("default_auto_archive_duration")] - public int? DefaultAutoArchiveDuration { get; set; } - - /// - /// Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 - /// - [JsonProperty("permissions")] - public string Permissions { get; set; } - - /// - /// Flags for this channel - /// - [JsonProperty("flags")] - public ChannelFlags? Flags { get; set; } - - /// - /// Number of messages ever sent in a thread, it's similar to message_count on message creation, but will not decrement the number when a message is deleted - /// - [JsonProperty("total_message_sent")] - public int? TotalMessageSent { get; set; } - - private Hash _threadMembers; - - /// - /// The set of tags that can be used in a GUILD_FORUM or GUILD_MEDIA channel - /// Limited to 20 - /// - [JsonProperty("available_tags")] - public List AvailableTags { get; set; } - - /// - /// The IDs of the set of tags that have been applied to a thread in a GUILD_FORUM or GUILD_MEDIA channel - /// - [JsonProperty("applied_tags")] - public List AppliedTags { get; set; } - - /// - /// The emoji to show in the add reaction button on a thread in a GUILD_FORUM or GUILD_MEDIA channel - /// - [JsonProperty("default_reaction_emoji")] - public DefaultReaction DefaultReactionEmoji { get; set; } - - /// - /// The initial rate_limit_per_user to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. - /// - [JsonProperty("default_thread_rate_limit_per_user")] - public int? DefaultThreadRateLimitPerUser { get; set; } - - /// - /// The default used to order posts in `GUILD_FORUM` or `GUILD_MEDIA` channels - /// - [JsonProperty("default_sort_order")] - public SortOrderType? DefaultSortOrder { get; set; } - - /// - /// The default used to display posts in GUILD_FORUM channels. - /// Defaults to , which indicates a layout view has not been set by a channel admin - /// - [JsonProperty("default_forum_layout")] - public ForumLayoutTypes? DefaultForumLayout { get; set; } - - /// - /// List of thread members if channel is thread; Null Otherwise. - /// - public Hash ThreadMembers + /// The ID of this channel + /// + [JsonProperty("id")] + public Snowflake Id { get; set; } + + /// + /// the type of channel + /// + [JsonProperty("type")] + public ChannelType Type { get; set; } + + /// + /// the ID of the guild + /// Warning: May be missing for some channel objects received over gateway guild dispatches + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } + + /// + /// Sorting position of the channel + /// + [JsonProperty("position")] + public int? Position { get; set; } + + /// + /// Explicit permission overwrites for members and roles + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("permission_overwrites")] + public Hash PermissionOverwrites { get; set; } + + /// + /// The name of the channel (1-100 characters) + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The channel topic (0-1024 characters) + /// + [JsonProperty("topic")] + public string Topic { get; set; } + + /// + /// Whether the channel is nsfw + /// + [JsonProperty("nsfw")] + public bool? Nsfw { get; set; } + + /// + /// The id of the last message sent in this channel (or thread for GUILD_FORUM or GUILD_MEDIA channels) + /// May not point to an existing or valid message or thread + /// + [JsonProperty("last_message_id")] + public Snowflake? LastMessageId { get; set; } + + /// + /// The bitrate (in bits) of the voice channel + /// + [JsonProperty("bitrate")] + public int? Bitrate { get; set; } + + /// + /// The user limit of the voice channel + /// + [JsonProperty("user_limit")] + public int? UserLimit { get; set; } + + /// + /// Amount of seconds a user has to wait before sending another message (0-21600); + /// bots, as well as users with the permission manage_messages or manage_channel, are unaffected + /// + [JsonProperty("rate_limit_per_user")] + public int? RateLimitPerUser { get; set; } + + /// + /// The recipients of the DM + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("recipients")] + public Hash Recipients { get; set; } + + /// + /// icon hash of the group DM + /// + [JsonProperty("icon")] + public string Icon { get; set; } + + /// + /// ID of the DM creator + /// + [JsonProperty("owner_id")] + public Snowflake? OwnerId { get; set; } + + /// + /// Application id of the group DM creator if it is bot-created + /// + [JsonProperty("application_id")] + public Snowflake? ApplicationId { get; set; } + + /// + /// For group DM channels: whether the channel is managed by an application via the `gdm.join` OAuth2 scope + /// + [JsonProperty("managed")] + public bool? Managed { get; set; } + + /// + /// ID of the parent category for a channel (each parent category can contain up to 50 channels) + /// + [JsonProperty("parent_id")] + public Snowflake? ParentId { get; set; } + + /// + /// When the last pinned message was pinned. + /// This may be null in events such as GUILD_CREATE when a message is not pinned. + /// + [JsonProperty("last_pin_timestamp")] + public DateTime? LastPinTimestamp { get; set; } + + /// + /// Voice region id for the voice channel, automatic when set to null + /// + [JsonProperty("rtc_region")] + public string RtcRegion { get; set; } + + /// + /// The camera video quality mode of the voice channel + /// 1 when not present + /// + [JsonProperty("video_quality_mode")] + public VideoQualityMode? VideoQualityMode { get; set; } + + /// + /// umber of messages (not including the initial messages or deleted messages) in a thread (if the thread was created before July 1, 2022, it stops counting at 50) + /// + [JsonProperty("message_count")] + public int? MessageCount { get; set; } + + /// + /// An approximate count of users in a thread, stops counting at 50 + /// + [JsonProperty("member_count")] + public int? MemberCount { get; set; } + + /// + /// Thread-specific fields not needed by other channels + /// + [JsonProperty("thread_metadata")] + public ThreadMetadata ThreadMetadata { get; set; } + + /// + /// Thread member object for the current user, if they have joined the thread, only included on certain API endpoints + /// + [JsonProperty("member")] + public ThreadMember Member { get; set; } + + /// + /// Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 + /// + [JsonProperty("default_auto_archive_duration")] + public int? DefaultAutoArchiveDuration { get; set; } + + /// + /// Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 + /// + [JsonProperty("permissions")] + public string Permissions { get; set; } + + /// + /// Flags for this channel + /// + [JsonProperty("flags")] + public ChannelFlags? Flags { get; set; } + + /// + /// Number of messages ever sent in a thread, it's similar to message_count on message creation, but will not decrement the number when a message is deleted + /// + [JsonProperty("total_message_sent")] + public int? TotalMessageSent { get; set; } + + private Hash _threadMembers; + + /// + /// The set of tags that can be used in a GUILD_FORUM or GUILD_MEDIA channel + /// Limited to 20 + /// + [JsonProperty("available_tags")] + public List AvailableTags { get; set; } + + /// + /// The IDs of the set of tags that have been applied to a thread in a GUILD_FORUM or GUILD_MEDIA channel + /// + [JsonProperty("applied_tags")] + public List AppliedTags { get; set; } + + /// + /// The emoji to show in the add reaction button on a thread in a GUILD_FORUM or GUILD_MEDIA channel + /// + [JsonProperty("default_reaction_emoji")] + public DefaultReaction DefaultReactionEmoji { get; set; } + + /// + /// The initial rate_limit_per_user to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. + /// + [JsonProperty("default_thread_rate_limit_per_user")] + public int? DefaultThreadRateLimitPerUser { get; set; } + + /// + /// The default used to order posts in `GUILD_FORUM` or `GUILD_MEDIA` channels + /// + [JsonProperty("default_sort_order")] + public SortOrderType? DefaultSortOrder { get; set; } + + /// + /// The default used to display posts in GUILD_FORUM channels. + /// Defaults to , which indicates a layout view has not been set by a channel admin + /// + [JsonProperty("default_forum_layout")] + public ForumLayoutTypes? DefaultForumLayout { get; set; } + + /// + /// List of thread members if channel is thread; Null Otherwise. + /// + public Hash ThreadMembers + { + get { - get + if (_threadMembers != null) { - if (_threadMembers != null) - { - return _threadMembers; - } + return _threadMembers; + } - InvalidChannelException.ThrowIfNotThread(this, "Cannot get ThreadMembers for a non thread channel"); + InvalidChannelException.ThrowIfNotThread(this, "Cannot get ThreadMembers for a non thread channel"); - return _threadMembers = new Hash(); - } + return _threadMembers = new Hash(); } + } - internal UserData UserData { get; set; } + internal UserData UserData { get; set; } - /// - /// Returns a string to mention this channel in a message - /// - public string Mention => DiscordFormatting.MentionChannel(Id); + /// + /// Returns a string to mention this channel in a message + /// + public string Mention => DiscordFormatting.MentionChannel(Id); - /// - /// Returns the Icon URL for the given channel - /// - public string IconUrl => !string.IsNullOrEmpty(Icon) ? DiscordCdn.GetChannelIcon(Id, Icon) : null; + /// + /// Returns the Icon URL for the given channel + /// + public string IconUrl => !string.IsNullOrEmpty(Icon) ? DiscordCdn.GetChannelIcon(Id, Icon) : null; - /// - /// Returns if the channel is a guild channel - /// - /// - public bool IsGuildChannel() - { - return Type == ChannelType.GuildCategory - || Type == ChannelType.GuildDirectory - || Type == ChannelType.GuildForum - || Type == ChannelType.GuildNews - || Type == ChannelType.GuildText - || Type == ChannelType.GuildVoice - || Type == ChannelType.GuildNewsThread - || Type == ChannelType.GuildPrivateThread - || Type == ChannelType.GuildPublicThread - || Type == ChannelType.GuildStageVoice; - } + /// + /// Returns if the channel is a guild channel + /// + /// + public bool IsGuildChannel() + { + return Type == ChannelType.GuildCategory + || Type == ChannelType.GuildDirectory + || Type == ChannelType.GuildForum + || Type == ChannelType.GuildNews + || Type == ChannelType.GuildText + || Type == ChannelType.GuildVoice + || Type == ChannelType.GuildNewsThread + || Type == ChannelType.GuildPrivateThread + || Type == ChannelType.GuildPublicThread + || Type == ChannelType.GuildStageVoice; + } - /// - /// Returns if a channel is a DM channel - /// - /// - public bool IsDmChannel() - { - return Type == ChannelType.Dm || Type == ChannelType.GroupDm; - } + /// + /// Returns if a channel is a DM channel + /// + /// + public bool IsDmChannel() + { + return Type == ChannelType.Dm || Type == ChannelType.GroupDm; + } - /// - /// Returns if a channel is a thread channel - /// - /// - public bool IsThreadChannel() - { - return Type == ChannelType.GuildNewsThread || Type == ChannelType.GuildPrivateThread || Type == ChannelType.GuildPublicThread; - } + /// + /// Returns if a channel is a thread channel + /// + /// + public bool IsThreadChannel() + { + return Type == ChannelType.GuildNewsThread || Type == ChannelType.GuildPrivateThread || Type == ChannelType.GuildPublicThread; + } - /// - /// Create a new channel object for the guild. - /// Requires the MANAGE_CHANNELS permission. - /// See Create Guild Channel - /// - /// Client to use - /// Guild to create the channel in - /// Channel to create - public static IPromise Create(DiscordClient client, Snowflake guildId, ChannelCreate channel) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Post(client,$"guilds/{guildId}/channels", channel); - } + /// + /// Create a new channel object for the guild. + /// Requires the MANAGE_CHANNELS permission. + /// See Create Guild Channel + /// + /// Client to use + /// Guild to create the channel in + /// Channel to create + public static IPromise Create(DiscordClient client, Snowflake guildId, ChannelCreate channel) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Post(client,$"guilds/{guildId}/channels", channel); + } - /// - /// Get a channel by ID - /// See Get Channel - /// If the channel is a thread, a thread member object is included in the returned result. - /// - /// Client to use - /// ID of the channel to get - public static IPromise Get(DiscordClient client, Snowflake channelId) - { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - return client.Bot.Rest.Get(client,$"channels/{channelId}"); - } + /// + /// Get a channel by ID + /// See Get Channel + /// If the channel is a thread, a thread member object is included in the returned result. + /// + /// Client to use + /// ID of the channel to get + public static IPromise Get(DiscordClient client, Snowflake channelId) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + return client.Bot.Rest.Get(client,$"channels/{channelId}"); + } - /// - /// Update a group dm channel's settings. - /// See Modify Channel - /// - /// Client to use - /// Update to be made to the channel. All fields are optional - public IPromise EditGroupDmChannel(DiscordClient client, GroupDmChannelUpdate update) - { - if (update == null) throw new ArgumentNullException(nameof(update)); - return client.Bot.Rest.Patch(client,$"channels/{Id}", update); - } + /// + /// Update a group dm channel's settings. + /// See Modify Channel + /// + /// Client to use + /// Update to be made to the channel. All fields are optional + public IPromise EditGroupDmChannel(DiscordClient client, GroupDmChannelUpdate update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + return client.Bot.Rest.Patch(client,$"channels/{Id}", update); + } - /// - /// Update a guild channel's settings. - /// Requires the MANAGE_CHANNELS permission for the guild. - /// See Modify Channel - /// - /// Client to use - /// Update to be made to the channel. All fields are optional - public IPromise EditGuildChannel(DiscordClient client, GuildChannelUpdate update) - { - if (update == null) throw new ArgumentNullException(nameof(update)); - return client.Bot.Rest.Patch(client,$"channels/{Id}", update); - } + /// + /// Update a guild channel's settings. + /// Requires the MANAGE_CHANNELS permission for the guild. + /// See Modify Channel + /// + /// Client to use + /// Update to be made to the channel. All fields are optional + public IPromise EditGuildChannel(DiscordClient client, GuildChannelUpdate update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + return client.Bot.Rest.Patch(client,$"channels/{Id}", update); + } - /// - /// Update a thread channel's settings. - /// Requires the MANAGE_THREADS permission for the guild. - /// See Modify Channel - /// - /// Client to use - /// Update to be made to the channel. All fields are optional - public IPromise EditThreadChannel(DiscordClient client, ThreadChannelUpdate update) - { - if (update == null) throw new ArgumentNullException(nameof(update)); - return client.Bot.Rest.Patch(client,$"channels/{Id}", update); - } + /// + /// Update a thread channel's settings. + /// Requires the MANAGE_THREADS permission for the guild. + /// See Modify Channel + /// + /// Client to use + /// Update to be made to the channel. All fields are optional + public IPromise EditThreadChannel(DiscordClient client, ThreadChannelUpdate update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + return client.Bot.Rest.Patch(client,$"channels/{Id}", update); + } - /// - /// Delete a channel, or close a private message. - /// Requires the MANAGE_CHANNELS or MANAGE_THREADS permission for the guild depending on the channel type. - /// See Delete/Close Channel - /// - /// Client to use - public IPromise Delete(DiscordClient client) - { - return client.Bot.Rest.Delete(client,$"channels/{Id}"); - } + /// + /// Delete a channel, or close a private message. + /// Requires the MANAGE_CHANNELS or MANAGE_THREADS permission for the guild depending on the channel type. + /// See Delete/Close Channel + /// + /// Client to use + public IPromise Delete(DiscordClient client) + { + return client.Bot.Rest.Delete(client,$"channels/{Id}"); + } - /// - /// Returns the messages for a channel. - /// If operating on a guild channel, this endpoint requires the VIEW_CHANNEL permission to be present on the current user. - /// If the current user is missing the 'READ_MESSAGE_HISTORY' permission in the channel then this will return no messages (since they cannot read the message history). - /// See Get Channel Messages - /// - /// Client to use - /// Optional request filters - public IPromise> GetMessages(DiscordClient client, ChannelMessagesRequest request = null) - { - return client.Bot.Rest.Get>(client,$"channels/{Id}/messages{request?.ToQueryString()}"); - } + /// + /// Returns the messages for a channel. + /// If operating on a guild channel, this endpoint requires the VIEW_CHANNEL permission to be present on the current user. + /// If the current user is missing the 'READ_MESSAGE_HISTORY' permission in the channel then this will return no messages (since they cannot read the message history). + /// See Get Channel Messages + /// + /// Client to use + /// Optional request filters + public IPromise> GetMessages(DiscordClient client, ChannelMessagesRequest request = null) + { + return client.Bot.Rest.Get>(client,$"channels/{Id}/messages{request?.ToQueryString()}"); + } - /// - /// Returns a specific message in the channel. - /// If operating on a guild channel, this endpoint requires the 'READ_MESSAGE_HISTORY' permission to be present on the current user. - /// See Get Channel Messages - /// - /// Client to use - /// Message ID of the message - public IPromise GetMessage(DiscordClient client, Snowflake messageId) - { - InvalidSnowflakeException.ThrowIfInvalid(messageId, nameof(messageId)); - return client.Bot.Rest.Get(client,$"channels/{Id}/messages/{messageId}"); - } + /// + /// Returns a specific message in the channel. + /// If operating on a guild channel, this endpoint requires the 'READ_MESSAGE_HISTORY' permission to be present on the current user. + /// See Get Channel Messages + /// + /// Client to use + /// Message ID of the message + public IPromise GetMessage(DiscordClient client, Snowflake messageId) + { + InvalidSnowflakeException.ThrowIfInvalid(messageId); + return client.Bot.Rest.Get(client,$"channels/{Id}/messages/{messageId}"); + } - /// - /// Post a message to a guild text or DM channel. - /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. - /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. - /// See Create Message - /// - /// Client to use - /// Message to be created - public IPromise CreateMessage(DiscordClient client, MessageCreate message) + /// + /// Post a message to a guild text or DM channel. + /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. + /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. + /// See Create Message + /// + /// Client to use + /// Message to be created + public IPromise CreateMessage(DiscordClient client, MessageCreate message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + DateTime? blockedUntil = UserData?.GetBlockedUntil(); + if (!blockedUntil.HasValue) { - if (message == null) throw new ArgumentNullException(nameof(message)); - DateTime? blockedUntil = UserData?.GetBlockedUntil(); - if (!blockedUntil.HasValue) + IPromise response = client.Bot.Rest.Post(client, $"channels/{Id}/messages", message); + if (UserData != null) { - IPromise response = client.Bot.Rest.Post(client, $"channels/{Id}/messages", message); - if (UserData != null) - { - response.Catch(ex => UserData.ProcessError(client, ex)); - } - return response; + response.Catch(ex => UserData.ProcessError(client, ex)); } - - DiscordUser user = UserData.GetUser(); - client.Logger.Debug("Blocking CreateMessage. User {0} ({1}) is DM blocked until {2}.", user.FullUserName, user.Id, blockedUntil.Value); - return Promise.Rejected(new BlockedUserException(user, blockedUntil.Value)); + return response; } + + DiscordUser user = UserData.GetUser(); + client.Logger.Debug("Blocking CreateMessage. User {0} ({1}) is DM blocked until {2}.", user.FullUserName, user.Id, blockedUntil.Value); + return Promise.Rejected(new BlockedUserException(user, blockedUntil.Value)); + } - /// - /// Post a message to a guild text or DM channel. - /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. - /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. - /// See Create Message - /// - /// Client to use - /// Content of the message - public IPromise CreateMessage(DiscordClient client, string message) + /// + /// Post a message to a guild text or DM channel. + /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. + /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. + /// See Create Message + /// + /// Client to use + /// Content of the message + public IPromise CreateMessage(DiscordClient client, string message) + { + MessageCreate createMessage = new() { - MessageCreate createMessage = new MessageCreate - { - Content = message - }; + Content = message + }; - return CreateMessage(client, createMessage); - } + return CreateMessage(client, createMessage); + } - /// - /// Post a message to a guild text or DM channel. - /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. - /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. - /// See Create Message - /// - /// Client to use - /// Embed to be send in the message - public IPromise CreateMessage(DiscordClient client, DiscordEmbed embed) + /// + /// Post a message to a guild text or DM channel. + /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. + /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. + /// See Create Message + /// + /// Client to use + /// Embed to be send in the message + public IPromise CreateMessage(DiscordClient client, DiscordEmbed embed) + { + MessageCreate createMessage = new() { - MessageCreate createMessage = new MessageCreate - { - Embeds = new List {embed} - }; + Embeds = [embed] + }; - return CreateMessage(client, createMessage); - } + return CreateMessage(client, createMessage); + } - /// - /// Post a message to a guild text or DM channel. - /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. - /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. - /// See Create Message - /// - /// Client to use - /// Embeds to be send in the message - public IPromise CreateMessage(DiscordClient client, List embeds) + /// + /// Post a message to a guild text or DM channel. + /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. + /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. + /// See Create Message + /// + /// Client to use + /// Embeds to be send in the message + public IPromise CreateMessage(DiscordClient client, List embeds) + { + MessageCreate createMessage = new() { - MessageCreate createMessage = new MessageCreate - { - Embeds = embeds - }; + Embeds = embeds + }; - return CreateMessage(client, createMessage); - } + return CreateMessage(client, createMessage); + } - /// - /// Creates a message in a text channel using a global message template - /// - /// Client to use - /// Template name - /// message to use (optional) - /// Placeholders to apply (optional) - public IPromise CreateGlobalTemplateMessage(DiscordClient client, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) - { - MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(client.Plugin, templateName).ToMessage(placeholders, message); - return CreateMessage(client, template); - } + /// + /// Creates a message in a text channel using a global message template + /// + /// Client to use + /// Template name + /// message to use (optional) + /// Placeholders to apply (optional) + public IPromise CreateGlobalTemplateMessage(DiscordClient client, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) + { + MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(client.Plugin, templateName).ToMessage(placeholders, message); + return CreateMessage(client, template); + } - /// - /// Creates a message in a text channel using a localized message template - /// - /// Client to use - /// Template name - /// Oxide language for the template - /// message to use (optional) - /// Placeholders to apply (optional) - public IPromise CreateTemplateMessage(DiscordClient client, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, MessageCreate message = null, PlaceholderData placeholders = null) - { - MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, language).ToMessage(placeholders, message); - return CreateMessage(client, template); - } + /// + /// Creates a message in a text channel using a localized message template + /// + /// Client to use + /// Template name + /// Oxide language for the template + /// message to use (optional) + /// Placeholders to apply (optional) + public IPromise CreateTemplateMessage(DiscordClient client, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, MessageCreate message = null, PlaceholderData placeholders = null) + { + MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, language).ToMessage(placeholders, message); + return CreateMessage(client, template); + } - /// - /// Delete multiple messages in a single request. - /// This endpoint can only be used on guild channels and requires the MANAGE_MESSAGES permission. - /// See Bulk Delete Messages - /// - /// Client to use - /// Collect of message ids to delete (Between 2 - 100) - public IPromise BulkDeleteMessages(DiscordClient client, ICollection messageIds) + /// + /// Delete multiple messages in a single request. + /// This endpoint can only be used on guild channels and requires the MANAGE_MESSAGES permission. + /// See Bulk Delete Messages + /// + /// Client to use + /// Collect of message ids to delete (Between 2 - 100) + public IPromise BulkDeleteMessages(DiscordClient client, ICollection messageIds) + { + if (messageIds.Count < 2) throw new ArgumentOutOfRangeException(nameof(messageIds), "Cannot delete less than 2 messages"); + if (messageIds.Count > 100) throw new ArgumentOutOfRangeException(nameof(messageIds), "Cannot delete more than 100 messages"); + + Dictionary> data = new() { - if (messageIds.Count < 2) throw new ArgumentOutOfRangeException(nameof(messageIds), "Cannot delete less than 2 messages"); - if (messageIds.Count > 100) throw new ArgumentOutOfRangeException(nameof(messageIds), "Cannot delete more than 100 messages"); + ["messages"] = messageIds + }; - Dictionary> data = new Dictionary> - { - ["messages"] = messageIds - }; + return client.Bot.Rest.Post(client,$"channels/{Id}/messages/bulk-delete", data); + } - return client.Bot.Rest.Post(client,$"channels/{Id}/messages/bulk-delete", data); - } + /// + /// Edit the channel permission overwrites for a user or role in a channel. + /// Only usable for guild channels. + /// Requires the MANAGE_ROLES permission. + /// See Edit Channel Permissions + /// + /// Client to use + /// Overwrite to edit with changes + public IPromise EditPermissions(DiscordClient client, Overwrite overwrite) + { + if (overwrite == null) throw new ArgumentNullException(nameof(overwrite)); + InvalidSnowflakeException.ThrowIfInvalid(overwrite.Id); + return client.Bot.Rest.Put(client,$"channels/{Id}/permissions/{overwrite.Id}", overwrite); + } - /// - /// Edit the channel permission overwrites for a user or role in a channel. - /// Only usable for guild channels. - /// Requires the MANAGE_ROLES permission. - /// See Edit Channel Permissions - /// - /// Client to use - /// Overwrite to edit with changes - public IPromise EditPermissions(DiscordClient client, Overwrite overwrite) - { - if (overwrite == null) throw new ArgumentNullException(nameof(overwrite)); - InvalidSnowflakeException.ThrowIfInvalid(overwrite.Id, nameof(overwrite.Id)); - return client.Bot.Rest.Put(client,$"channels/{Id}/permissions/{overwrite.Id}", overwrite); - } + /// + /// Delete a channel permission overwrite for a user or role in a channel. + /// Only usable for guild channels. + /// Requires the MANAGE_ROLES permission. + /// See Delete Channel Permission + /// + /// Client to use + /// Overwrite to delete + public IPromise DeletePermission(DiscordClient client, Overwrite overwrite) => DeletePermission(client, overwrite.Id); - /// - /// Delete a channel permission overwrite for a user or role in a channel. - /// Only usable for guild channels. - /// Requires the MANAGE_ROLES permission. - /// See Delete Channel Permission - /// - /// Client to use - /// Overwrite to delete - public IPromise DeletePermission(DiscordClient client, Overwrite overwrite) => DeletePermission(client, overwrite.Id); - - /// - /// Delete a channel permission overwrite for a user or role in a channel. - /// Only usable for guild channels. - /// Requires the MANAGE_ROLES permission. - /// See Delete Channel Permission - /// - /// Client to use - /// Overwrite ID to delete - public IPromise DeletePermission(DiscordClient client, Snowflake overwriteId) - { - InvalidSnowflakeException.ThrowIfInvalid(overwriteId, nameof(overwriteId)); - return client.Bot.Rest.Delete(client,$"channels/{Id}/permissions/{overwriteId}"); - } + /// + /// Delete a channel permission overwrite for a user or role in a channel. + /// Only usable for guild channels. + /// Requires the MANAGE_ROLES permission. + /// See Delete Channel Permission + /// + /// Client to use + /// Overwrite ID to delete + public IPromise DeletePermission(DiscordClient client, Snowflake overwriteId) + { + InvalidSnowflakeException.ThrowIfInvalid(overwriteId); + return client.Bot.Rest.Delete(client,$"channels/{Id}/permissions/{overwriteId}"); + } - /// - /// Returns a list of invite objects (with invite metadata) for the channel. - /// Only usable for guild channels. - /// Requires the MANAGE_CHANNELS permission. - /// See Get Channel Invites - /// - /// Client to use - /// Thrown when the channel type is Dm or GroupDm - public IPromise> GetInvites(DiscordClient client) - { - InvalidChannelException.ThrowIfNotGuildChannel(this, "You can only get channel invites for guild channels"); - return client.Bot.Rest.Get>(client,$"channels/{Id}/invites"); - } + /// + /// Returns a list of invite objects (with invite metadata) for the channel. + /// Only usable for guild channels. + /// Requires the MANAGE_CHANNELS permission. + /// See Get Channel Invites + /// + /// Client to use + /// Thrown when the channel type is Dm or GroupDm + public IPromise> GetInvites(DiscordClient client) + { + InvalidChannelException.ThrowIfNotGuildChannel(this, "You can only get channel invites for guild channels"); + return client.Bot.Rest.Get>(client,$"channels/{Id}/invites"); + } - /// - /// Create a new invite object for the channel. - /// Only usable for guild channels. - /// Requires the CREATE_INSTANT_INVITE permission. - /// See Create Channel Invite - /// - /// Client to use - /// Invite to create - public IPromise CreateInvite(DiscordClient client, ChannelInvite invite) - { - if (invite == null) throw new ArgumentNullException(nameof(invite)); - return client.Bot.Rest.Post(client,$"channels/{Id}/invites", invite); - } + /// + /// Create a new invite object for the channel. + /// Only usable for guild channels. + /// Requires the CREATE_INSTANT_INVITE permission. + /// See Create Channel Invite + /// + /// Client to use + /// Invite to create + public IPromise CreateInvite(DiscordClient client, ChannelInvite invite) + { + if (invite == null) throw new ArgumentNullException(nameof(invite)); + return client.Bot.Rest.Post(client,$"channels/{Id}/invites", invite); + } - /// - /// Follow a News Channel to send messages to a target channel. - /// Requires the MANAGE_WEBHOOKS permission in the target channel. - /// See Follow Announcement Channel - /// - /// Client to use - /// ID of target channel - public IPromise FollowNewsChannel(DiscordClient client, Snowflake webhookChannelId) - { - InvalidSnowflakeException.ThrowIfInvalid(webhookChannelId, nameof(webhookChannelId)); - return client.Bot.Rest.Post(client,$"channels/{Id}/followers?webhook_channel_id={webhookChannelId}", null); - } + /// + /// Follow a News Channel to send messages to a target channel. + /// Requires the MANAGE_WEBHOOKS permission in the target channel. + /// See Follow Announcement Channel + /// + /// Client to use + /// ID of target channel + public IPromise FollowNewsChannel(DiscordClient client, Snowflake webhookChannelId) + { + InvalidSnowflakeException.ThrowIfInvalid(webhookChannelId); + return client.Bot.Rest.Post(client,$"channels/{Id}/followers?webhook_channel_id={webhookChannelId}", null); + } - /// - /// Post a typing indicator for the specified channel. - /// Generally bots should not implement this route. However, if a bot is responding to a command and expects the computation to take a few seconds, this endpoint may be called to let the user know that the bot is processing their message. - /// See Trigger Typing Indicator - /// - /// Client to use - public IPromise TriggerTypingIndicator(DiscordClient client) - { - return client.Bot.Rest.Post(client,$"channels/{Id}/typing", null); - } + /// + /// Post a typing indicator for the specified channel. + /// Generally bots should not implement this route. However, if a bot is responding to a command and expects the computation to take a few seconds, this endpoint may be called to let the user know that the bot is processing their message. + /// See Trigger Typing Indicator + /// + /// Client to use + public IPromise TriggerTypingIndicator(DiscordClient client) + { + return client.Bot.Rest.Post(client,$"channels/{Id}/typing", null); + } - /// - /// Returns all pinned messages in the channel - /// See Get Pinned Messages - /// - /// Client to use - public IPromise> GetPinnedMessages(DiscordClient client) - { - return client.Bot.Rest.Get>(client,$"channels/{Id}/pins"); - } + /// + /// Returns all pinned messages in the channel + /// See Get Pinned Messages + /// + /// Client to use + public IPromise> GetPinnedMessages(DiscordClient client) + { + return client.Bot.Rest.Get>(client,$"channels/{Id}/pins"); + } - /// - /// Adds a recipient to a Group DM using their access token - /// See Group DM Add Recipient - /// - /// Client to use - /// User to add - /// Users access token - public IPromise GroupDmAddRecipient(DiscordClient client, DiscordUser user, string accessToken) => GroupDmAddRecipient(client, user.Id, accessToken, user.Username); - - /// - /// Adds a recipient to a Group DM using their access token - /// See Group DM Add Recipient - /// - /// Client to use - /// User to add - /// Users access token - /// User nickname - public IPromise GroupDmAddRecipient(DiscordClient client, Snowflake userId, string accessToken, string nick) + /// + /// Adds a recipient to a Group DM using their access token + /// See Group DM Add Recipient + /// + /// Client to use + /// User to add + /// Users access token + public IPromise GroupDmAddRecipient(DiscordClient client, DiscordUser user, string accessToken) => GroupDmAddRecipient(client, user.Id, accessToken, user.Username); + + /// + /// Adds a recipient to a Group DM using their access token + /// See Group DM Add Recipient + /// + /// Client to use + /// User to add + /// Users access token + /// User nickname + public IPromise GroupDmAddRecipient(DiscordClient client, Snowflake userId, string accessToken, string nick) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + Dictionary data = new() { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - Dictionary data = new Dictionary() - { - ["access_token"] = accessToken, - ["nick"] = nick - }; + ["access_token"] = accessToken, + ["nick"] = nick + }; - return client.Bot.Rest.Put(client,$"channels/{Id}/recipients/{userId}", data); - } + return client.Bot.Rest.Put(client,$"channels/{Id}/recipients/{userId}", data); + } - /// - /// Removes a recipient from a Group DM - /// See Group DM Remove Recipient - /// - /// Client to use - /// User ID to remove - public IPromise GroupDmRemoveRecipient(DiscordClient client, Snowflake userId) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Delete(client,$"channels/{Id}/recipients/{userId}"); - } + /// + /// Removes a recipient from a Group DM + /// See Group DM Remove Recipient + /// + /// Client to use + /// User ID to remove + public IPromise GroupDmRemoveRecipient(DiscordClient client, Snowflake userId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Delete(client,$"channels/{Id}/recipients/{userId}"); + } - /// - /// Creates a new public thread from a message - /// See Start Thread with Message - /// - /// Client to use - /// ID of the message to start the thread from - /// Data to use when creating the thread - public IPromise StartThreadFromMessage(DiscordClient client, Snowflake messageId, ThreadCreateFromMessage create) - { - InvalidSnowflakeException.ThrowIfInvalid(messageId, nameof(messageId)); - return client.Bot.Rest.Post(client,$"channels/{Id}/messages/{messageId}/threads", create); - } + /// + /// Creates a new public thread from a message + /// See Start Thread with Message + /// + /// Client to use + /// ID of the message to start the thread from + /// Data to use when creating the thread + public IPromise StartThreadFromMessage(DiscordClient client, Snowflake messageId, ThreadCreateFromMessage create) + { + InvalidSnowflakeException.ThrowIfInvalid(messageId); + return client.Bot.Rest.Post(client,$"channels/{Id}/messages/{messageId}/threads", create); + } - /// - /// Creates a new thread that is not connected to an existing message. The created thread is always a GUILD_PRIVATE_THREAD - /// See Start Thread without Message - /// - /// Client to use - /// Data to use when creating the thread - public IPromise StartThreadWithoutMessage(DiscordClient client, ThreadCreate create) - { - if (create == null) throw new ArgumentNullException(nameof(create)); - return client.Bot.Rest.Post(client,$"channels/{Id}/threads", create); - } + /// + /// Creates a new thread that is not connected to an existing message. The created thread is always a GUILD_PRIVATE_THREAD + /// See Start Thread without Message + /// + /// Client to use + /// Data to use when creating the thread + public IPromise StartThreadWithoutMessage(DiscordClient client, ThreadCreate create) + { + if (create == null) throw new ArgumentNullException(nameof(create)); + return client.Bot.Rest.Post(client,$"channels/{Id}/threads", create); + } - /// - /// Creates a new thread in a forum channel, and sends a message within the created thread. Returns a channel, with a nested message object - /// See Start Thread in Forum Channel - /// - /// Client to use - /// Data to use when creating the thread - public IPromise StartThreadInForumChannel(DiscordClient client, ThreadForumCreate create) - { - if (create == null) throw new ArgumentNullException(nameof(create)); - return client.Bot.Rest.Post(client,$"channels/{Id}/threads", create); - } + /// + /// Creates a new thread in a forum channel, and sends a message within the created thread. Returns a channel, with a nested message object + /// See Start Thread in Forum Channel + /// + /// Client to use + /// Data to use when creating the thread + public IPromise StartThreadInForumChannel(DiscordClient client, ThreadForumCreate create) + { + if (create == null) throw new ArgumentNullException(nameof(create)); + return client.Bot.Rest.Post(client,$"channels/{Id}/threads", create); + } - /// - /// Adds the bot to the thread. Also requires the thread is not archived. - /// See Join Thread - /// - /// Client to use - public IPromise JoinThread(DiscordClient client) - { - return client.Bot.Rest.Put(client,$"channels/{Id}/thread-members/@me", null); - } + /// + /// Adds the bot to the thread. Also requires the thread is not archived. + /// See Join Thread + /// + /// Client to use + public IPromise JoinThread(DiscordClient client) + { + return client.Bot.Rest.Put(client,$"channels/{Id}/thread-members/@me", null); + } - /// - /// Adds another user to a thread. - /// Requires the ability to send messages in the thread. Also requires the thread is not archived. - /// See Add Thread Member - /// - /// Client to use - /// ID of the user to thread - public IPromise AddThreadMember(DiscordClient client, Snowflake userId) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Put(client, $"channels/{Id}/thread-members/{userId}", null); - } + /// + /// Adds another user to a thread. + /// Requires the ability to send messages in the thread. Also requires the thread is not archived. + /// See Add Thread Member + /// + /// Client to use + /// ID of the user to thread + public IPromise AddThreadMember(DiscordClient client, Snowflake userId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Put(client, $"channels/{Id}/thread-members/{userId}", null); + } - /// - /// Removes the bot from the thread. Also requires the thread is not archived. - /// See Leave Thread - /// - /// Client to use - public IPromise LeaveThread(DiscordClient client) - { - return client.Bot.Rest.Delete(client,$"channels/{Id}/thread-members/@me"); - } + /// + /// Removes the bot from the thread. Also requires the thread is not archived. + /// See Leave Thread + /// + /// Client to use + public IPromise LeaveThread(DiscordClient client) + { + return client.Bot.Rest.Delete(client,$"channels/{Id}/thread-members/@me"); + } - /// - /// Removes another user from a thread. - /// Requires the MANAGE_THREADS permission or that you are the creator of the thread. Also requires the thread is not archived. - /// See Remove Thread Member - /// - /// Client to use - /// ID of the user to thread - public IPromise RemoveThreadMember(DiscordClient client, Snowflake userId) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Delete(client, $"channels/{Id}/thread-members/{userId}"); - } + /// + /// Removes another user from a thread. + /// Requires the MANAGE_THREADS permission or that you are the creator of the thread. Also requires the thread is not archived. + /// See Remove Thread Member + /// + /// Client to use + /// ID of the user to thread + public IPromise RemoveThreadMember(DiscordClient client, Snowflake userId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Delete(client, $"channels/{Id}/thread-members/{userId}"); + } - /// - /// Returns a thread member object for the specified user if they are a member of the thread - /// returns a 404 response otherwise. - /// See Remove Thread Member - /// - /// Client to use - /// ID of the user to thread - /// Query String Arguments - public IPromise GetThreadMember(DiscordClient client, Snowflake userId, GetThreadMember request = null) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Get(client,$"channels/{Id}/thread-members/{userId}{request?.ToQueryString()}"); - } + /// + /// Returns a thread member object for the specified user if they are a member of the thread + /// returns a 404 response otherwise. + /// See Remove Thread Member + /// + /// Client to use + /// ID of the user to thread + /// Query String Arguments + public IPromise GetThreadMember(DiscordClient client, Snowflake userId, GetThreadMember request = null) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Get(client,$"channels/{Id}/thread-members/{userId}{request?.ToQueryString()}"); + } - /// - /// Returns array of thread members objects that are members of the thread. - /// This endpoint is restricted according to whether the GUILD_MEMBERS Privileged Intent is enabled for your application. - /// See List Thread Members - /// - /// Client to use - /// Query string for the List Thread Members - public IPromise> ListThreadMembers(DiscordClient client, ListThreadMembers request = null) - { - return client.Bot.Rest.Get>(client,$"channels/{Id}/thread-members{request?.ToQueryString()}"); - } + /// + /// Returns array of thread members objects that are members of the thread. + /// This endpoint is restricted according to whether the GUILD_MEMBERS Privileged Intent is enabled for your application. + /// See List Thread Members + /// + /// Client to use + /// Query string for the List Thread Members + public IPromise> ListThreadMembers(DiscordClient client, ListThreadMembers request = null) + { + return client.Bot.Rest.Get>(client,$"channels/{Id}/thread-members{request?.ToQueryString()}"); + } - /// - /// Returns archived threads in the channel that are public. - /// When called on a GUILD_TEXT channel, returns threads of type GUILD_PUBLIC_THREAD. When called on a GUILD_NEWS channel returns threads of type GUILD_NEWS_THREAD. Threads are ordered by archive_timestamp, in descending order. - /// Requires the READ_MESSAGE_HISTORY permission. - /// See List Public Archived Threads - /// - /// Client to use - /// The options to use when looking up the archived threads - public IPromise ListPublicArchivedThreads(DiscordClient client, ThreadArchivedLookup request = null) - { - return client.Bot.Rest.Get(client,$"channels/{Id}/threads/archived/public{request?.ToQueryString()}"); - } + /// + /// Returns archived threads in the channel that are public. + /// When called on a GUILD_TEXT channel, returns threads of type GUILD_PUBLIC_THREAD. When called on a GUILD_NEWS channel returns threads of type GUILD_NEWS_THREAD. Threads are ordered by archive_timestamp, in descending order. + /// Requires the READ_MESSAGE_HISTORY permission. + /// See List Public Archived Threads + /// + /// Client to use + /// The options to use when looking up the archived threads + public IPromise ListPublicArchivedThreads(DiscordClient client, ThreadArchivedLookup request = null) + { + return client.Bot.Rest.Get(client,$"channels/{Id}/threads/archived/public{request?.ToQueryString()}"); + } - /// - /// Returns archived threads in the channel that are of type GUILD_PRIVATE_THREAD. - /// Threads are ordered by archive_timestamp, in descending order. - /// Requires both the READ_MESSAGE_HISTORY and MANAGE_THREADS permissions. - /// See List Private Archived Threads - /// - /// Client to use - /// The options to use when looking up the archived threads - public IPromise ListPrivateArchivedThreads(DiscordClient client, ThreadArchivedLookup request = null) - { - return client.Bot.Rest.Get(client,$"channels/{Id}/threads/archived/public{request?.ToQueryString()}"); - } + /// + /// Returns archived threads in the channel that are of type GUILD_PRIVATE_THREAD. + /// Threads are ordered by archive_timestamp, in descending order. + /// Requires both the READ_MESSAGE_HISTORY and MANAGE_THREADS permissions. + /// See List Private Archived Threads + /// + /// Client to use + /// The options to use when looking up the archived threads + public IPromise ListPrivateArchivedThreads(DiscordClient client, ThreadArchivedLookup request = null) + { + return client.Bot.Rest.Get(client,$"channels/{Id}/threads/archived/public{request?.ToQueryString()}"); + } - /// - /// Returns archived threads in the channel that are of type GUILD_PRIVATE_THREAD, and the user has joined. - /// Threads are ordered by their id, in descending order. - /// Requires the READ_MESSAGE_HISTORY permission. - /// See List Joined Private Archived Threads - /// - /// Client to use - /// The options to use when looking up the archived threads - public IPromise ListJoinedPrivateArchivedThreads(DiscordClient client, ThreadArchivedLookup lookup = null) - { - return client.Bot.Rest.Get(client,$"channels/{Id}/users/@me/threads/archived/private{lookup?.ToQueryString()}"); - } + /// + /// Returns archived threads in the channel that are of type GUILD_PRIVATE_THREAD, and the user has joined. + /// Threads are ordered by their id, in descending order. + /// Requires the READ_MESSAGE_HISTORY permission. + /// See List Joined Private Archived Threads + /// + /// Client to use + /// The options to use when looking up the archived threads + public IPromise ListJoinedPrivateArchivedThreads(DiscordClient client, ThreadArchivedLookup lookup = null) + { + return client.Bot.Rest.Get(client,$"channels/{Id}/users/@me/threads/archived/private{lookup?.ToQueryString()}"); + } - /// - /// Gets the stage instance associated with the Stage channel, if it exists. - /// See Get Stage Instance - /// - /// Client to use - public IPromise GetStageInstance(DiscordClient client) - { - return client.Bot.Rest.Get(client,$"stage-instances/{Id}"); - } + /// + /// Gets the stage instance associated with the Stage channel, if it exists. + /// See Get Stage Instance + /// + /// Client to use + public IPromise GetStageInstance(DiscordClient client) + { + return client.Bot.Rest.Get(client,$"stage-instances/{Id}"); + } - internal DiscordChannel Update(DiscordChannel channel) - { - DiscordChannel previous = (DiscordChannel)MemberwiseClone(); + internal DiscordChannel Update(DiscordChannel channel) + { + DiscordChannel previous = (DiscordChannel)MemberwiseClone(); - Type = channel.Type; + Type = channel.Type; - if (channel.Position != null) - Position = channel.Position; + if (channel.Position != null) + Position = channel.Position; - if (channel.PermissionOverwrites != null) - PermissionOverwrites = channel.PermissionOverwrites; + if (channel.PermissionOverwrites != null) + PermissionOverwrites = channel.PermissionOverwrites; - if (channel.Name != null) - Name = channel.Name; + if (channel.Name != null) + Name = channel.Name; - if (channel.Topic != null) - Topic = channel.Topic; + if (channel.Topic != null) + Topic = channel.Topic; - if (channel.Nsfw != null) - Nsfw = channel.Nsfw; + if (channel.Nsfw != null) + Nsfw = channel.Nsfw; - if (channel.Bitrate != null) - Bitrate = channel.Bitrate; + if (channel.Bitrate != null) + Bitrate = channel.Bitrate; - if (channel.UserLimit != null) - UserLimit = channel.UserLimit; + if (channel.UserLimit != null) + UserLimit = channel.UserLimit; - if (channel.RateLimitPerUser != null) - RateLimitPerUser = channel.RateLimitPerUser; + if (channel.RateLimitPerUser != null) + RateLimitPerUser = channel.RateLimitPerUser; - if (channel.Icon != null) - Icon = channel.Icon; + if (channel.Icon != null) + Icon = channel.Icon; - if (channel.OwnerId != null) - OwnerId = channel.OwnerId; + if (channel.OwnerId != null) + OwnerId = channel.OwnerId; - if (channel.ApplicationId != null) - ApplicationId = channel.ApplicationId; + if (channel.ApplicationId != null) + ApplicationId = channel.ApplicationId; - if (channel.LastPinTimestamp != null) - LastPinTimestamp = channel.LastPinTimestamp; + if (channel.LastPinTimestamp != null) + LastPinTimestamp = channel.LastPinTimestamp; - if (channel.VideoQualityMode != null) - VideoQualityMode = channel.VideoQualityMode; + if (channel.VideoQualityMode != null) + VideoQualityMode = channel.VideoQualityMode; - if (channel.MessageCount != null) - MessageCount = channel.MessageCount; + if (channel.MessageCount != null) + MessageCount = channel.MessageCount; - if (channel.MemberCount != null) - MemberCount = channel.MemberCount; + if (channel.MemberCount != null) + MemberCount = channel.MemberCount; - if (channel.ThreadMetadata != null) - ThreadMetadata = channel.ThreadMetadata; + if (channel.ThreadMetadata != null) + ThreadMetadata = channel.ThreadMetadata; - if (channel.Member != null) - Member = channel.Member; + if (channel.Member != null) + Member = channel.Member; - if (channel.DefaultAutoArchiveDuration != null) - DefaultAutoArchiveDuration = channel.DefaultAutoArchiveDuration; + if (channel.DefaultAutoArchiveDuration != null) + DefaultAutoArchiveDuration = channel.DefaultAutoArchiveDuration; - if (channel.Permissions != null) - Permissions = channel.Permissions; + if (channel.Permissions != null) + Permissions = channel.Permissions; - ParentId = channel.ParentId; + ParentId = channel.ParentId; - if (channel.Flags.HasValue) - Flags = Flags; + if (channel.Flags.HasValue) + Flags = Flags; - return previous; - } + return previous; + } - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendField("ID", Id); - logger.AppendField("Name", Name); - logger.AppendFieldEnum("Type", Type); - } + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("ID", Id); + logger.AppendField("Name", Name); + logger.AppendFieldEnum("Type", Type); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/FollowedChannel.cs b/Oxide.Ext.Discord/Entities/Channels/FollowedChannel.cs index 8b3b63079..4a2d64e14 100644 --- a/Oxide.Ext.Discord/Entities/Channels/FollowedChannel.cs +++ b/Oxide.Ext.Discord/Entities/Channels/FollowedChannel.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Followed Channel Structure from an API response +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class FollowedChannel { /// - /// Represents a Followed Channel Structure from an API response + /// Source channel ID /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class FollowedChannel - { - /// - /// Source channel ID - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// Created target webhook ID - /// - [JsonProperty("webhook_id")] - public Snowflake WebhookId { get; set; } - } + /// + /// Created target webhook ID + /// + [JsonProperty("webhook_id")] + public Snowflake WebhookId { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/ForumLayoutTypes.cs b/Oxide.Ext.Discord/Entities/Channels/ForumLayoutTypes.cs index 635712965..1df719337 100644 --- a/Oxide.Ext.Discord/Entities/Channels/ForumLayoutTypes.cs +++ b/Oxide.Ext.Discord/Entities/Channels/ForumLayoutTypes.cs @@ -1,23 +1,22 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Forum Layout Types +/// +public enum ForumLayoutTypes : byte { /// - /// Represents a Forum Layout Types + /// No default has been set for forum channel /// - public enum ForumLayoutTypes : byte - { - /// - /// No default has been set for forum channel - /// - NotSet = 0, + NotSet = 0, - /// - /// Display posts as a list - /// - ListView = 1, + /// + /// Display posts as a list + /// + ListView = 1, - /// - /// Display posts as a collection of tiles - /// - GalleryView = 2, - } + /// + /// Display posts as a collection of tiles + /// + GalleryView = 2, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/FourmTag.cs b/Oxide.Ext.Discord/Entities/Channels/FourmTag.cs index c29ccf0bb..5aebc93c2 100644 --- a/Oxide.Ext.Discord/Entities/Channels/FourmTag.cs +++ b/Oxide.Ext.Discord/Entities/Channels/FourmTag.cs @@ -2,49 +2,48 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Forum Tag Structure +/// An object that represents a tag that is able to be applied to a thread in a `GUILD_FORUM` or `GUILD_MEDIA` channel. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ForumTag : ISnowflakeEntity, IDiscordValidation { /// - /// Represents a Forum Tag Structure - /// An object that represents a tag that is able to be applied to a thread in a `GUILD_FORUM` or `GUILD_MEDIA` channel. + /// The id of the tag /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ForumTag : ISnowflakeEntity, IDiscordValidation - { - /// - /// The id of the tag - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The name of the tag (0-20 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// The name of the tag (0-20 characters) + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Whether this tag can only be added to or removed from threads by a member with the MANAGE_THREADS permission - /// - [JsonProperty("moderated")] - public bool Moderated { get; set; } + /// + /// Whether this tag can only be added to or removed from threads by a member with the MANAGE_THREADS permission + /// + [JsonProperty("moderated")] + public bool Moderated { get; set; } - /// - /// The id of a guild's custom emoji - /// - [JsonProperty("emoji_id")] - public Snowflake? EmojiId { get; set; } + /// + /// The id of a guild's custom emoji + /// + [JsonProperty("emoji_id")] + public Snowflake? EmojiId { get; set; } - /// - /// The unicode character of the emoji - /// - [JsonProperty("emoji_name")] - public string EmojiName { get; set; } + /// + /// The unicode character of the emoji + /// + [JsonProperty("emoji_name")] + public string EmojiName { get; set; } - /// - public void Validate() - { - InvalidForumTagException.ThrowIfInvalidName(Name); - } + /// + public void Validate() + { + InvalidForumTagException.ThrowIfInvalidName(Name); } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/GroupDmChannelUpdate.cs b/Oxide.Ext.Discord/Entities/Channels/GroupDmChannelUpdate.cs index 2f000aaa6..66dcd9edd 100644 --- a/Oxide.Ext.Discord/Entities/Channels/GroupDmChannelUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Channels/GroupDmChannelUpdate.cs @@ -2,30 +2,29 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Group DM Channel Update Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GroupDmChannelUpdate : IDiscordValidation { /// - /// Represents a Group DM Channel Update Structure + /// The name of the channel (1-100 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GroupDmChannelUpdate : IDiscordValidation - { - /// - /// The name of the channel (1-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Base64 encoded icon - /// - [JsonProperty("icon")] - public DiscordImageData? Icon { get; set; } + /// + /// Base64 encoded icon + /// + [JsonProperty("icon")] + public DiscordImageData? Icon { get; set; } - /// - public void Validate() - { - InvalidChannelException.ThrowIfInvalidName(Name, true); - } + /// + public void Validate() + { + InvalidChannelException.ThrowIfInvalidName(Name, true); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/GuildChannelUpdate.cs b/Oxide.Ext.Discord/Entities/Channels/GuildChannelUpdate.cs index 05beedcff..af1fe1c97 100644 --- a/Oxide.Ext.Discord/Entities/Channels/GuildChannelUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Channels/GuildChannelUpdate.cs @@ -3,121 +3,120 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Guild Channel Update Structure +/// +public class GuildChannelUpdate : IDiscordValidation { /// - /// Represents a Guild Channel Update Structure + /// The name of the channel (1-100 characters) /// - public class GuildChannelUpdate : IDiscordValidation - { - /// - /// The name of the channel (1-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// the type of channel - /// See - /// - [JsonProperty("type")] - public ChannelType Type { get; set; } + /// + /// the type of channel + /// See + /// + [JsonProperty("type")] + public ChannelType Type { get; set; } - /// - /// The position of the channel in the left-hand listing - /// - [JsonProperty("position")] - public int? Position { get; set; } + /// + /// The position of the channel in the left-hand listing + /// + [JsonProperty("position")] + public int? Position { get; set; } - /// - /// The channel topic (0-1024 characters) - /// - [JsonProperty("topic")] - public string Topic { get; set; } + /// + /// The channel topic (0-1024 characters) + /// + [JsonProperty("topic")] + public string Topic { get; set; } - /// - /// Whether the channel is nsfw - /// - [JsonProperty("nsfw")] - public bool? Nsfw { get; set; } + /// + /// Whether the channel is nsfw + /// + [JsonProperty("nsfw")] + public bool? Nsfw { get; set; } - /// - /// Amount of seconds a user has to wait before sending another message (0-21600); - /// bots, as well as users with the permission manage_messages or manage_channel, are unaffected - /// - [JsonProperty("rate_limit_per_user")] - public int? RateLimitPerUser { get; set; } + /// + /// Amount of seconds a user has to wait before sending another message (0-21600); + /// bots, as well as users with the permission manage_messages or manage_channel, are unaffected + /// + [JsonProperty("rate_limit_per_user")] + public int? RateLimitPerUser { get; set; } - /// - /// The bitrate (in bits) of the voice channel - /// 8000 to 96000 (128000 for VIP servers) - /// - [JsonProperty("bitrate")] - public int? Bitrate { get; set; } + /// + /// The bitrate (in bits) of the voice channel + /// 8000 to 96000 (128000 for VIP servers) + /// + [JsonProperty("bitrate")] + public int? Bitrate { get; set; } - /// - /// The user limit of the voice channel - /// - [JsonProperty("user_limit")] - public int? UserLimit { get; set; } + /// + /// The user limit of the voice channel + /// + [JsonProperty("user_limit")] + public int? UserLimit { get; set; } - /// - /// Explicit permission overwrites for members and roles - /// - [JsonProperty("permission_overwrites")] - public List PermissionOverwrites { get; set; } + /// + /// Explicit permission overwrites for members and roles + /// + [JsonProperty("permission_overwrites")] + public List PermissionOverwrites { get; set; } - /// - /// ID of the parent category for a channel (each parent category can contain up to 50 channels) - /// - [JsonProperty("parent_id")] - public Snowflake? ParentId { get; set; } + /// + /// ID of the parent category for a channel (each parent category can contain up to 50 channels) + /// + [JsonProperty("parent_id")] + public Snowflake? ParentId { get; set; } - /// - /// Channel voice region id, automatic when set to null - /// - [JsonProperty("rtc_region")] - public string RtcRegion { get; set; } + /// + /// Channel voice region id, automatic when set to null + /// + [JsonProperty("rtc_region")] + public string RtcRegion { get; set; } - /// - /// The camera video quality mode of the voice channel - /// - [JsonProperty("video_quality_mode")] - public VideoQualityMode? VideoQualityMode { get; set; } + /// + /// The camera video quality mode of the voice channel + /// + [JsonProperty("video_quality_mode")] + public VideoQualityMode? VideoQualityMode { get; set; } - /// - /// The default duration for newly created threads in the channel, in minutes, to automatically archive the thread after recent activity - /// - [JsonProperty("default_auto_archive_duration")] - public int? DefaultAutoArchiveDuration { get; set; } + /// + /// The default duration for newly created threads in the channel, in minutes, to automatically archive the thread after recent activity + /// + [JsonProperty("default_auto_archive_duration")] + public int? DefaultAutoArchiveDuration { get; set; } - /// - /// The set of tags that can be used in a GUILD_FORUM or GUILD_MEDIA channel - /// - [JsonProperty("available_tags")] - public List AvailableTags { get; set; } + /// + /// The set of tags that can be used in a GUILD_FORUM or GUILD_MEDIA channel + /// + [JsonProperty("available_tags")] + public List AvailableTags { get; set; } - /// - /// The emoji to show in the add reaction button on a thread in a GUILD_FORUM or GUILD_MEDIA channel - /// - [JsonProperty("default_reaction_emoji")] - public DefaultReaction DefaultReactionEmoji { get; set; } + /// + /// The emoji to show in the add reaction button on a thread in a GUILD_FORUM or GUILD_MEDIA channel + /// + [JsonProperty("default_reaction_emoji")] + public DefaultReaction DefaultReactionEmoji { get; set; } - /// - /// The initial rate_limit_per_user to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. - /// - [JsonProperty("default_thread_rate_limit_per_user")] - public int? DefaultThreadRateLimitPerUser { get; set; } + /// + /// The initial rate_limit_per_user to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. + /// + [JsonProperty("default_thread_rate_limit_per_user")] + public int? DefaultThreadRateLimitPerUser { get; set; } - /// - public void Validate() - { - InvalidChannelException.ThrowIfInvalidName(Name, true); - InvalidChannelException.ThrowIfInvalidTopic(Topic, Type, true); - InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); - InvalidChannelException.ThrowIfInvalidBitRate(Bitrate); - InvalidChannelException.ThrowIfInvalidUserLimit(UserLimit); - InvalidChannelException.ThrowIfInvalidParentId(ParentId); - } + /// + public void Validate() + { + InvalidChannelException.ThrowIfInvalidName(Name, true); + InvalidChannelException.ThrowIfInvalidTopic(Topic, Type, true); + InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); + InvalidChannelException.ThrowIfInvalidBitRate(Bitrate); + InvalidChannelException.ThrowIfInvalidUserLimit(UserLimit); + InvalidChannelException.ThrowIfInvalidParentId(ParentId); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Overwrite.cs b/Oxide.Ext.Discord/Entities/Channels/Overwrite.cs index d3ebd5cba..d6766b17b 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Overwrite.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Overwrite.cs @@ -1,36 +1,35 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Overwrite Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class Overwrite : ISnowflakeEntity { /// - /// Represents a Overwrite Structure + /// Role or user ID /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class Overwrite : ISnowflakeEntity - { - /// - /// Role or user ID - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Permission Type - /// - [JsonProperty("type")] - public PermissionType Type { get; set; } + /// + /// Permission Type + /// + [JsonProperty("type")] + public PermissionType Type { get; set; } - /// - /// Permissions allowed - /// - [JsonProperty("allow")] - public PermissionFlags? Allow { get; set; } + /// + /// Permissions allowed + /// + [JsonProperty("allow")] + public PermissionFlags? Allow { get; set; } - /// - /// Permissions denied - /// - [JsonProperty("deny")] - public PermissionFlags? Deny { get; set; } - } -} + /// + /// Permissions denied + /// + [JsonProperty("deny")] + public PermissionFlags? Deny { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/PermissionType.cs b/Oxide.Ext.Discord/Entities/Channels/PermissionType.cs index 1fadca95e..71a128e49 100644 --- a/Oxide.Ext.Discord/Entities/Channels/PermissionType.cs +++ b/Oxide.Ext.Discord/Entities/Channels/PermissionType.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents the type of permission +/// +public enum PermissionType : byte { /// - /// Represents the type of a permission + /// This permission belongs to a role /// - public enum PermissionType : byte - { - /// - /// This permission belongs to a role - /// - Role = 0, + Role = 0, - /// - /// This permission belongs to a member - /// - Member = 1 - } + /// + /// This permission belongs to a member + /// + Member = 1 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/SortOrderType.cs b/Oxide.Ext.Discord/Entities/Channels/SortOrderType.cs index 8795c87f9..18e8cbb68 100644 --- a/Oxide.Ext.Discord/Entities/Channels/SortOrderType.cs +++ b/Oxide.Ext.Discord/Entities/Channels/SortOrderType.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Sort Order Types in Discord +/// +public enum SortOrderType : byte { /// - /// Represents Sort Order Types in Discord + /// Sort forum posts by activity /// - public enum SortOrderType : byte - { - /// - /// Sort forum posts by activity - /// - LatestActivity = 0, + LatestActivity = 0, - /// - /// Sort forum posts by creation time (from most recent to oldest) - /// - CreationDate = 1 - } + /// + /// Sort forum posts by creation time (from most recent to oldest) + /// + CreationDate = 1 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Stages/PrivacyLevel.cs b/Oxide.Ext.Discord/Entities/Channels/Stages/PrivacyLevel.cs index cdb88c7aa..581c4d580 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Stages/PrivacyLevel.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Stages/PrivacyLevel.cs @@ -1,24 +1,23 @@ using System; using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Stage Privacy Level within Discord. +/// +public enum PrivacyLevel : byte { /// - /// Represents a Stage Privacy Level within Discord. + /// The Stage instance is visible publicly. (deprecated) /// - public enum PrivacyLevel : byte - { - /// - /// The Stage instance is visible publicly. (deprecated) - /// - [Obsolete("Deprecated by Discord")] - [DiscordEnum("PUBLIC")] - Public = 1, + [Obsolete("Deprecated by Discord")] + [DiscordEnum("PUBLIC")] + Public = 1, - /// - /// The Stage instance is visible to only guild members. - /// - [DiscordEnum("GUILD_ONLY")] - GuildOnly = 2 - } + /// + /// The Stage instance is visible to only guild members. + /// + [DiscordEnum("GUILD_ONLY")] + GuildOnly = 2 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstance.cs b/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstance.cs index 6b210d2ed..d77774a50 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstance.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstance.cs @@ -4,116 +4,115 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a channel Stage Instance within Discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class StageInstance : ISnowflakeEntity { /// - /// Represents a channel Stage Instance within Discord. + /// The ID of this Stage instance /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class StageInstance : ISnowflakeEntity - { - /// - /// The ID of this Stage instance - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The guild ID of the associated Stage channel - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + /// + /// The guild ID of the associated Stage channel + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The ID of the associated Stage channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + /// + /// The ID of the associated Stage channel + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The topic of the Stage instance (1-120 characters) - /// - [JsonProperty("topic")] - public string Topic { get; set; } + /// + /// The topic of the Stage instance (1-120 characters) + /// + [JsonProperty("topic")] + public string Topic { get; set; } - /// - /// The privacy level of the Stage instance - /// - [JsonProperty("privacy_level")] - public PrivacyLevel PrivacyLevel { get; set; } + /// + /// The privacy level of the Stage instance + /// + [JsonProperty("privacy_level")] + public PrivacyLevel PrivacyLevel { get; set; } - /// - /// Whether or not Stage discovery is disabled (deprecated) - /// - [Obsolete("Deprecated by discord")] - [JsonProperty("discoverable_disabled")] - public bool DiscoverableDisabled { get; set; } + /// + /// Whether or not Stage discovery is disabled (deprecated) + /// + [Obsolete("Deprecated by discord")] + [JsonProperty("discoverable_disabled")] + public bool DiscoverableDisabled { get; set; } - /// - /// The id of the scheduled event for this Stage instance - /// - [JsonProperty("guild_scheduled_event_id")] - public Snowflake? GuildScheduledEventId { get; set; } + /// + /// The id of the scheduled event for this Stage instance + /// + [JsonProperty("guild_scheduled_event_id")] + public Snowflake? GuildScheduledEventId { get; set; } - /// - /// Creates a new Stage instance associated to a Stage channel. - /// Requires the user to be a moderator of the Stage channel. - /// See Create Stage Instance - /// - /// Client to use - /// Create Stage Instance Object - public static IPromise Create(DiscordClient client, StageInstanceCreate create) - { - if (create == null) throw new ArgumentNullException(nameof(create)); - InvalidSnowflakeException.ThrowIfInvalid(create.ChannelId, nameof(create.ChannelId)); - return client.Bot.Rest.Post(client,"stage-instances", create); - } + /// + /// Creates a new Stage instance associated to a Stage channel. + /// Requires the user to be a moderator of the Stage channel. + /// See Create Stage Instance + /// + /// Client to use + /// Create Stage Instance Object + public static IPromise Create(DiscordClient client, StageInstanceCreate create) + { + if (create == null) throw new ArgumentNullException(nameof(create)); + InvalidSnowflakeException.ThrowIfInvalid(create.ChannelId); + return client.Bot.Rest.Post(client,"stage-instances", create); + } - /// - /// Gets the stage instance associated with the Stage channel, if it exists. - /// See Get Stage Instance - /// - /// Client to use - /// Channel ID to get the stage instance for - public static IPromise Get(DiscordClient client, Snowflake channelId) - { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - return client.Bot.Rest.Get(client,$"stage-instances/{channelId}"); - } + /// + /// Gets the stage instance associated with the Stage channel, if it exists. + /// See Get Stage Instance + /// + /// Client to use + /// Channel ID to get the stage instance for + public static IPromise Get(DiscordClient client, Snowflake channelId) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + return client.Bot.Rest.Get(client,$"stage-instances/{channelId}"); + } - /// - /// Modifies fields of an existing Stage instance. - /// Requires the user to be a moderator of the Stage channel. - /// See Update Stage Instance - /// - /// Client to use - /// Update for the stage instance - public IPromise Edit(DiscordClient client, StageInstanceUpdate update) - { - if (update == null) throw new ArgumentNullException(nameof(update)); - return client.Bot.Rest.Patch(client,$"stage-instances/{ChannelId}", update); - } + /// + /// Modifies fields of an existing Stage instance. + /// Requires the user to be a moderator of the Stage channel. + /// See Update Stage Instance + /// + /// Client to use + /// Update for the stage instance + public IPromise Edit(DiscordClient client, StageInstanceUpdate update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + return client.Bot.Rest.Patch(client,$"stage-instances/{ChannelId}", update); + } - /// - /// Deletes the Stage instance. - /// Requires the user to be a moderator of the Stage channel. - /// See Delete Stage Instance - /// - /// Client to use - public IPromise Delete(DiscordClient client) - { - return client.Bot.Rest.Delete(client,$"stage-instances/{ChannelId}"); - } + /// + /// Deletes the Stage instance. + /// Requires the user to be a moderator of the Stage channel. + /// See Delete Stage Instance + /// + /// Client to use + public IPromise Delete(DiscordClient client) + { + return client.Bot.Rest.Delete(client,$"stage-instances/{ChannelId}"); + } - internal StageInstance Edit(StageInstance stage) - { - StageInstance previous = (StageInstance)MemberwiseClone(); - if (stage.Topic != null) - Topic = stage.Topic; + internal StageInstance Edit(StageInstance stage) + { + StageInstance previous = (StageInstance)MemberwiseClone(); + if (stage.Topic != null) + Topic = stage.Topic; - PrivacyLevel = stage.PrivacyLevel; + PrivacyLevel = stage.PrivacyLevel; - return previous; - } + return previous; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstanceCreate.cs b/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstanceCreate.cs index e59368b42..21da4a60b 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstanceCreate.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstanceCreate.cs @@ -1,41 +1,40 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a href="https://discord.com/developers/docs/resources/stage-instance#create-stage-instance-json-params">Stage Instance Create Structure +/// +public class StageInstanceCreate { /// - /// Represents a href="https://discord.com/developers/docs/resources/stage-instance#create-stage-instance-json-params">Stage Instance Create Structure + /// The id of the Stage channel /// - public class StageInstanceCreate - { - /// - /// The id of the Stage channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The topic of the Stage instance (1-120 characters) - /// - [JsonProperty("topic")] - public string Topic { get; set; } + /// + /// The topic of the Stage instance (1-120 characters) + /// + [JsonProperty("topic")] + public string Topic { get; set; } - /// - /// The privacy level of the Stage instance (default GUILD_ONLY) - /// - [JsonProperty("privacy_level")] - public PrivacyLevel PrivacyLevel { get; set; } + /// + /// The privacy level of the Stage instance (default GUILD_ONLY) + /// + [JsonProperty("privacy_level")] + public PrivacyLevel PrivacyLevel { get; set; } - /// - /// Notify @everyone that a Stage instance has started - /// The stage moderator must have the MENTION_EVERYONE permission for this notification to be sent. - /// - [JsonProperty("send_start_notification")] - public bool SendStartNotification { get; set; } + /// + /// Notify @everyone that a Stage instance has started + /// The stage moderator must have the MENTION_EVERYONE permission for this notification to be sent. + /// + [JsonProperty("send_start_notification")] + public bool SendStartNotification { get; set; } - /// - /// The guild scheduled event associated with this Stage instance - /// - [JsonProperty("guild_scheduled_event_id")] - public Snowflake GuildScheduledEventId { get; set; } - } + /// + /// The guild scheduled event associated with this Stage instance + /// + [JsonProperty("guild_scheduled_event_id")] + public Snowflake GuildScheduledEventId { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstanceUpdate.cs b/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstanceUpdate.cs index 191dc7a0c..58b39bdf6 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstanceUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Stages/StageInstanceUpdate.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Modify Stage Instance Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class StageInstanceUpdate { /// - /// Represents a Modify Stage Instance Structure + /// The topic of the Stage instance (1-120 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class StageInstanceUpdate - { - /// - /// The topic of the Stage instance (1-120 characters) - /// - [JsonProperty("topic")] - public string Topic { get; set; } + [JsonProperty("topic")] + public string Topic { get; set; } - /// - /// The privacy level of the Stage instance - /// - [JsonProperty("privacy_level")] - public PrivacyLevel PrivacyLevel { get; set; } - } + /// + /// The privacy level of the Stage instance + /// + [JsonProperty("privacy_level")] + public PrivacyLevel PrivacyLevel { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Threads/GetThreadMember.cs b/Oxide.Ext.Discord/Entities/Channels/Threads/GetThreadMember.cs index 12dff9316..69f683125 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Threads/GetThreadMember.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Threads/GetThreadMember.cs @@ -1,31 +1,29 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Get Thread Member Query String Params +/// +public class GetThreadMember : IDiscordQueryString { /// - /// Represents Get Thread Member Query String Params + /// Whether to include a guild member object for the thread member /// - public class GetThreadMember : IDiscordQueryString - { - /// - /// Whether to include a guild member object for the thread member - /// - public bool WithMember { get; set; } + public bool WithMember { get; set; } - /// - public string ToQueryString() + /// + public string ToQueryString() + { + if (!WithMember) { - if (!WithMember) - { - return string.Empty; - } - - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); - builder.Add("with_member", StringCache.Instance.ToString(WithMember)); - return builder.ToStringAndFree(); + return string.Empty; } + + QueryStringBuilder builder = new(); + builder.Add("with_member", StringCache.Instance.ToString(WithMember)); + return builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Threads/ListThreadMembers.cs b/Oxide.Ext.Discord/Entities/Channels/Threads/ListThreadMembers.cs index 3c6fc7e3e..908591266 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Threads/ListThreadMembers.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Threads/ListThreadMembers.cs @@ -2,51 +2,49 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents List Thread Member Query String Params +/// +public class ListThreadMembers : IDiscordQueryString { /// - /// Represents List Thread Member Query String Params + /// Whether to include a guild member object for the thread member /// - public class ListThreadMembers : IDiscordQueryString - { - /// - /// Whether to include a guild member object for the thread member - /// - public bool WithMember { get; set; } + public bool WithMember { get; set; } - /// - /// Get thread members after this user ID - /// - public Snowflake? After { get; set; } + /// + /// Get thread members after this user ID + /// + public Snowflake? After { get; set; } - /// - /// Max number of thread members to return (1-100). Defaults to 100. - /// - public int? Limit { get; set; } + /// + /// Max number of thread members to return (1-100). Defaults to 100. + /// + public int? Limit { get; set; } - /// - public string ToQueryString() - { - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); + /// + public string ToQueryString() + { + QueryStringBuilder builder = new(); - if (WithMember) - { - builder.Add("with_member", StringCache.Instance.ToString(WithMember)); - } + if (WithMember) + { + builder.Add("with_member", StringCache.Instance.ToString(WithMember)); + } - if (After.HasValue) - { - builder.Add("after", After.Value.ToString()); - } + if (After.HasValue) + { + builder.Add("after", After.Value.ToString()); + } - if (Limit.HasValue) - { - builder.Add("limit", StringCache.Instance.ToString(Math.Clamp(Limit.Value, 1, 100))); - } - - return builder.ToStringAndFree(); + if (Limit.HasValue) + { + builder.Add("limit", StringCache.Instance.ToString(Math.Clamp(Limit.Value, 1, 100))); } + + return builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadArchivedLookup.cs b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadArchivedLookup.cs index 19d313278..4fa7f03e5 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadArchivedLookup.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadArchivedLookup.cs @@ -2,45 +2,43 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Thread Archive Lookup Structure within Discord. +/// Represents a Thread Archive Lookup Structure within Discord. +/// Represents a Thread Archive Lookup Structure within Discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ThreadArchivedLookup : IDiscordQueryString { /// - /// Represents a Thread Archive Lookup Structure within Discord. - /// Represents a Thread Archive Lookup Structure within Discord. - /// Represents a Thread Archive Lookup Structure within Discord. + /// Returns threads before this timestamp /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ThreadArchivedLookup : IDiscordQueryString - { - /// - /// Returns threads before this timestamp - /// - [JsonProperty("before")] - public DateTime? Before { get; set; } + [JsonProperty("before")] + public DateTime? Before { get; set; } - /// - /// Optional maximum number of threads to return - /// - [JsonProperty("limit")] - public int? Limit { get; set; } + /// + /// Optional maximum number of threads to return + /// + [JsonProperty("limit")] + public int? Limit { get; set; } - /// - public string ToQueryString() + /// + public string ToQueryString() + { + QueryStringBuilder builder = new(); + if (Before.HasValue) { - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); - if (Before.HasValue) - { - builder.Add("before", Before.Value.ToString("o")); - } + builder.Add("before", Before.Value.ToString("o")); + } - if (Limit.HasValue) - { - builder.Add("limit", Limit.Value.ToString()); - } - - return builder.ToStringAndFree(); + if (Limit.HasValue) + { + builder.Add("limit", Limit.Value.ToString()); } + + return builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadChannelUpdate.cs b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadChannelUpdate.cs index 50dec7479..2dbc6885a 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadChannelUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadChannelUpdate.cs @@ -3,72 +3,71 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Thread Channel Update Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ThreadChannelUpdate : IDiscordValidation { /// - /// Represents a Thread Channel Update Structure + /// The name of the channel (1-100 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ThreadChannelUpdate : IDiscordValidation - { - /// - /// The name of the channel (1-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Whether the channel is archived - /// - [JsonProperty("archived")] - public bool Archived { get; set; } + /// + /// Whether the channel is archived + /// + [JsonProperty("archived")] + public bool Archived { get; set; } - /// - /// Duration in minutes to automatically archive the thread after recent activity - /// Can be set to: 60, 1440, 4320, 10080 - /// - [JsonProperty("auto_archive_duration")] - public int AutoArchiveDuration { get; set; } + /// + /// Duration in minutes to automatically archive the thread after recent activity + /// Can be set to: 60, 1440, 4320, 10080 + /// + [JsonProperty("auto_archive_duration")] + public int AutoArchiveDuration { get; set; } - /// - /// Whether the thread is locked - /// When a thread is locked, only users with MANAGE_THREADS can unarchive it - /// - [JsonProperty("locked")] - public bool Locked { get; set; } + /// + /// Whether the thread is locked + /// When a thread is locked, only users with MANAGE_THREADS can unarchive it + /// + [JsonProperty("locked")] + public bool Locked { get; set; } - /// - /// Whether non-moderators can add other non-moderators to a thread - /// Only available on private threads - /// - [JsonProperty("invitable")] - public bool Invitable { get; set; } + /// + /// Whether non-moderators can add other non-moderators to a thread + /// Only available on private threads + /// + [JsonProperty("invitable")] + public bool Invitable { get; set; } - /// - /// Amount of seconds a user has to wait before sending another message (0-21600) - /// Bots and users with the permission manage_messages, manage_thread, or manage_channel, are unaffected - /// - [JsonProperty("rate_limit_per_user")] - public int? RateLimitPerUser { get; set; } + /// + /// Amount of seconds a user has to wait before sending another message (0-21600) + /// Bots and users with the permission manage_messages, manage_thread, or manage_channel, are unaffected + /// + [JsonProperty("rate_limit_per_user")] + public int? RateLimitPerUser { get; set; } - /// - /// Channel flags combined as a bitfield; PINNED can only be set for threads in forum channels - /// - [JsonProperty("flags")] - public ChannelFlags? Flags { get; set; } + /// + /// Channel flags combined as a bitfield; PINNED can only be set for threads in forum channels + /// + [JsonProperty("flags")] + public ChannelFlags? Flags { get; set; } - /// - /// The IDs of the set of tags that have been applied to a thread in a GUILD_FORUM or GUILD_MEDIA channel - /// - [JsonProperty("applied_tags")] - public List AppliedTags { get; set; } + /// + /// The IDs of the set of tags that have been applied to a thread in a GUILD_FORUM or GUILD_MEDIA channel + /// + [JsonProperty("applied_tags")] + public List AppliedTags { get; set; } - /// - public void Validate() - { - InvalidChannelException.ThrowIfInvalidName(Name, true); - InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); - InvalidThreadException.ThrowIfInvalidAutoArchiveDuration(AutoArchiveDuration); - } + /// + public void Validate() + { + InvalidChannelException.ThrowIfInvalidName(Name, true); + InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); + InvalidThreadException.ThrowIfInvalidAutoArchiveDuration(AutoArchiveDuration); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadCreate.cs b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadCreate.cs index 16e49d555..96e5247f8 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadCreate.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadCreate.cs @@ -2,54 +2,53 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Thread Create Structure within Discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ThreadCreate : IDiscordValidation { /// - /// Represents a Thread Create Structure within Discord. + /// 1-100 character thread name /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ThreadCreate : IDiscordValidation - { - /// - /// 1-100 character thread name - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Duration in minutes to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 - /// - [JsonProperty("auto_archive_duration")] - public int? AutoArchiveDuration { get; set; } + /// + /// Duration in minutes to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 + /// + [JsonProperty("auto_archive_duration")] + public int? AutoArchiveDuration { get; set; } - /// - /// The type of thread to create - /// Can only be GuildNewsThread, GuildPublicThread, or GuildPrivateThread - /// - [JsonProperty("type")] - public ChannelType Type { get; set; } + /// + /// The type of thread to create + /// Can only be GuildNewsThread, GuildPublicThread, or GuildPrivateThread + /// + [JsonProperty("type")] + public ChannelType Type { get; set; } - /// - /// Whether non-moderators can add other non-moderators to a thread; only available when creating a private thread - /// - [JsonProperty("invitable")] - public bool? Invitable { get; set; } + /// + /// Whether non-moderators can add other non-moderators to a thread; only available when creating a private thread + /// + [JsonProperty("invitable")] + public bool? Invitable { get; set; } - /// - /// Amount of seconds a user has to wait before sending another message (0-21600) - /// - [JsonProperty("rate_limit_per_user")] - public int? RateLimitPerUser { get; set; } + /// + /// Amount of seconds a user has to wait before sending another message (0-21600) + /// + [JsonProperty("rate_limit_per_user")] + public int? RateLimitPerUser { get; set; } - /// - /// Validates the Thread Forum Create - /// - public void Validate() - { - InvalidChannelException.ThrowIfInvalidName(Name, false); - InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); - InvalidThreadException.ThrowIfInvalidAutoArchiveDuration(AutoArchiveDuration); - InvalidThreadException.ThrowIfInvalidChannelType(Type); - } + /// + /// Validates the Thread Forum Create + /// + public void Validate() + { + InvalidChannelException.ThrowIfInvalidName(Name, false); + InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); + InvalidThreadException.ThrowIfInvalidAutoArchiveDuration(AutoArchiveDuration); + InvalidThreadException.ThrowIfInvalidChannelType(Type); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadCreateFromMessage.cs b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadCreateFromMessage.cs index 1fa8b9f17..ca6a13ce2 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadCreateFromMessage.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadCreateFromMessage.cs @@ -2,38 +2,37 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Thread Create From Message Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ThreadCreateFromMessage : IDiscordValidation { /// - /// Represents a Thread Create From Message Structure + /// 1-100 character thread name /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ThreadCreateFromMessage : IDiscordValidation - { - /// - /// 1-100 character thread name - /// - [JsonProperty("id")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Duration in minutes to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 - /// - [JsonProperty("auto_archive_duration")] - public int? AutoArchiveDuration { get; set; } + /// + /// Duration in minutes to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 + /// + [JsonProperty("auto_archive_duration")] + public int? AutoArchiveDuration { get; set; } - /// - /// Amount of seconds a user has to wait before sending another message (0-21600) - /// - [JsonProperty("rate_limit_per_user")] - public int? RateLimitPerUser { get; set; } + /// + /// Amount of seconds a user has to wait before sending another message (0-21600) + /// + [JsonProperty("rate_limit_per_user")] + public int? RateLimitPerUser { get; set; } - /// - public void Validate() - { - InvalidChannelException.ThrowIfInvalidName(Name, false); - InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); - InvalidThreadException.ThrowIfInvalidAutoArchiveDuration(AutoArchiveDuration); - } + /// + public void Validate() + { + InvalidChannelException.ThrowIfInvalidName(Name, false); + InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); + InvalidThreadException.ThrowIfInvalidAutoArchiveDuration(AutoArchiveDuration); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadForumCreate.cs b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadForumCreate.cs index 3a61e82aa..d48716ab8 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadForumCreate.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadForumCreate.cs @@ -3,90 +3,90 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Start Thread in Forum Channel Structure +/// +public class ThreadForumCreate : IFileAttachments { /// - /// Represents a Start Thread in Forum Channel Structure + /// 1-100 character thread name /// - public class ThreadForumCreate : IFileAttachments - { - /// - /// 1-100 character thread name - /// - [JsonProperty("id")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Duration in minutes to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 - /// - [JsonProperty("auto_archive_duration")] - public int? AutoArchiveDuration { get; set; } + /// + /// Duration in minutes to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 + /// + [JsonProperty("auto_archive_duration")] + public int? AutoArchiveDuration { get; set; } - /// - /// Amount of seconds a user has to wait before sending another message (0-21600) - /// - [JsonProperty("rate_limit_per_user")] - public int? RateLimitPerUser { get; set; } + /// + /// Amount of seconds a user has to wait before sending another message (0-21600) + /// + [JsonProperty("rate_limit_per_user")] + public int? RateLimitPerUser { get; set; } - /// - /// Contents of the first message in the forum thread - /// - [JsonProperty("message")] - public MessageCreate Message { get; set; } + /// + /// Contents of the first message in the forum thread + /// + [JsonProperty("message")] + public MessageCreate Message { get; set; } - /// - /// The IDs of the set of tags that have been applied to a thread in a GUILD_FORUM or GUILD_MEDIA channel - /// - [JsonProperty("applied_tags")] - public List AppliedTags { get; set; } + /// + /// The IDs of the set of tags that have been applied to a thread in a GUILD_FORUM or GUILD_MEDIA channel + /// + [JsonProperty("applied_tags")] + public List AppliedTags { get; set; } - /// - /// Attachments for a discord message - /// - public List FileAttachments { get; set; } + /// + /// Attachments for a discord message + /// + public List FileAttachments { get; set; } - /// - /// Attachments for the message - /// - [JsonProperty("attachments")] - public List Attachments { get; set; } - - /// - /// Adds an attachment to the message - /// - /// Name of the file - /// byte[] of the attachment - /// Attachment content type - /// Description for the attachment - public void AddAttachment(string filename, byte[] data, string contentType, string description = null) - { - InvalidFileNameException.ThrowIfInvalid(filename); - InvalidMessageException.ThrowIfInvalidAttachmentDescription(description); - - if (FileAttachments == null) - { - FileAttachments = new List(); - } + /// + /// Attachments for the message + /// + [JsonProperty("attachments")] + public List Attachments { get; set; } - if (Attachments == null) - { - Attachments = new List(); - } + /// + /// Adds an attachment to the message + /// + /// Name of the file + /// byte[] of the attachment + /// Attachment content type + /// Description for the attachment + /// Title of the attachment + public void AddAttachment(string filename, byte[] data, string contentType, string description = null, string title = null) + { + InvalidFileNameException.ThrowIfInvalid(filename); + InvalidMessageException.ThrowIfInvalidAttachmentDescription(description); - FileAttachments.Add(new MessageFileAttachment(filename, data, contentType)); - Attachments.Add(new MessageAttachment {Id = new Snowflake((ulong)FileAttachments.Count), Filename = filename, Description = description}); + if (FileAttachments == null) + { + FileAttachments = new List(); } - - /// - /// Validates the Thread Forum Create - /// - public void Validate() + + if (Attachments == null) { - InvalidChannelException.ThrowIfInvalidName(Name, false); - InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); - InvalidThreadException.ThrowIfInvalidAutoArchiveDuration(AutoArchiveDuration); - InvalidThreadException.ThrowIfInvalidForumCreateMessage(Message); - Message.Validate(); + Attachments = new List(); } + + FileAttachments.Add(new MessageFileAttachment(filename, data, contentType)); + Attachments.Add(new MessageAttachment {Id = new Snowflake((ulong)FileAttachments.Count), Filename = filename, Description = description, Title = title}); + } + + /// + /// Validates the Thread Forum Create + /// + public void Validate() + { + InvalidChannelException.ThrowIfInvalidName(Name, false); + InvalidChannelException.ThrowIfInvalidRateLimitPerUser(RateLimitPerUser); + InvalidThreadException.ThrowIfInvalidAutoArchiveDuration(AutoArchiveDuration); + InvalidThreadException.ThrowIfInvalidForumCreateMessage(Message); + Message.Validate(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadList.cs b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadList.cs index c7042ce30..d516a1020 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadList.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadList.cs @@ -1,33 +1,32 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Thread List Structure within Discord. +/// Represents a Thread List Public Archived Structure within Discord. +/// Represents a Thread List Private Archived Structure within Discord. +/// Represents a Thread List Private Archived Structure within Discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ThreadList { /// - /// Represents a Thread List Structure within Discord. - /// Represents a Thread List Public Archived Structure within Discord. - /// Represents a Thread List Private Archived Structure within Discord. - /// Represents a Thread List Private Archived Structure within Discord. + /// The active threads /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ThreadList - { - /// - /// The active threads - /// - [JsonProperty("threads")] - public List Threads { get; set; } + [JsonProperty("threads")] + public List Threads { get; set; } - /// - /// A thread member object for each returned thread the current user has joined - /// - [JsonProperty("members")] - public List Members { get; set; } + /// + /// A thread member object for each returned thread the current user has joined + /// + [JsonProperty("members")] + public List Members { get; set; } - /// - /// Whether there are potentially additional threads that could be returned on a subsequent call - /// - [JsonProperty("has_more")] - public bool HasMore { get; set; } - } + /// + /// Whether there are potentially additional threads that could be returned on a subsequent call + /// + [JsonProperty("has_more")] + public bool HasMore { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadMember.cs b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadMember.cs index 9f30a5e12..dee84dd34 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadMember.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadMember.cs @@ -1,49 +1,48 @@ using System; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a guild or DM Thread Member Structure within Discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ThreadMember { /// - /// Represents a guild or DM Thread Member Structure within Discord. + /// The id of the thread /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ThreadMember - { - /// - /// The id of the thread - /// - [JsonProperty("id")] - public Snowflake? Id { get; set; } + [JsonProperty("id")] + public Snowflake? Id { get; set; } - /// - /// The id of the user - /// - [JsonProperty("user_id")] - public Snowflake? UserId { get; set; } + /// + /// The id of the user + /// + [JsonProperty("user_id")] + public Snowflake? UserId { get; set; } - /// - /// The time the current user last joined the thread - /// - [JsonProperty("join_timestamp")] - public DateTime JoinTimestamp { get; set; } + /// + /// The time the current user last joined the thread + /// + [JsonProperty("join_timestamp")] + public DateTime JoinTimestamp { get; set; } - /// - /// Any user-thread settings, currently only used for notifications - /// - //TODO: Move to Enum if one becomes public - [JsonProperty("flags")] - public int Flags { get; set; } + /// + /// Any user-thread settings, currently only used for notifications + /// + //TODO: Move to Enum if one becomes public + [JsonProperty("flags")] + public int Flags { get; set; } - /// - /// The time the current user last joined the thread - /// * field is only present when withMember is set to true when calling List Thread Members or Get Thread Member. - /// - [JsonProperty("member")] - public GuildMember Member { get; set; } + /// + /// The time the current user last joined the thread + /// * field is only present when withMember is set to true when calling List Thread Members or Get Thread Member. + /// + [JsonProperty("member")] + public GuildMember Member { get; set; } - internal void Update(ThreadMember update) - { - Flags = update.Flags; - } + internal void Update(ThreadMember update) + { + Flags = update.Flags; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadMetadata.cs b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadMetadata.cs index f496cbf90..344cc9cea 100644 --- a/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadMetadata.cs +++ b/Oxide.Ext.Discord/Entities/Channels/Threads/ThreadMetadata.cs @@ -1,50 +1,49 @@ using System; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a guild or DM Thread Metadata Structure within Discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ThreadMetadata { /// - /// Represents a guild or DM Thread Metadata Structure within Discord. + /// Whether the thread is archived /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ThreadMetadata - { - /// - /// Whether the thread is archived - /// - [JsonProperty("archived")] - public bool Archived { get; set; } + [JsonProperty("archived")] + public bool Archived { get; set; } - /// - /// Duration in minutes to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 - /// - [JsonProperty("auto_archive_duration")] - public int AutoArchiveDuration { get; set; } + /// + /// Duration in minutes to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 + /// + [JsonProperty("auto_archive_duration")] + public int AutoArchiveDuration { get; set; } - /// - /// Timestamp when the thread's archive status was last changed, used for calculating recent activity - /// - [JsonProperty("archive_timestamp")] - public DateTime ArchiveTimestamp { get; set; } + /// + /// Timestamp when the thread's archive status was last changed, used for calculating recent activity + /// + [JsonProperty("archive_timestamp")] + public DateTime ArchiveTimestamp { get; set; } - /// - /// Whether the thread is locked - /// When a thread is locked, only users with MANAGE_THREADS can unarchive it - /// - [JsonProperty("locked")] - public bool Locked { get; set; } + /// + /// Whether the thread is locked + /// When a thread is locked, only users with MANAGE_THREADS can unarchive it + /// + [JsonProperty("locked")] + public bool Locked { get; set; } - /// - /// Whether non-moderators can add other non-moderators to a thread - /// Only available on private threads - /// - [JsonProperty("invitable")] - public bool? Invitable { get; set; } + /// + /// Whether non-moderators can add other non-moderators to a thread + /// Only available on private threads + /// + [JsonProperty("invitable")] + public bool? Invitable { get; set; } - /// - /// Timestamp when the thread was created; only populated for threads created after 2022-01-09 - /// - [JsonProperty("create_timestamp")] - public DateTime? CreateTimestamp { get; set; } - } + /// + /// Timestamp when the thread was created; only populated for threads created after 2022-01-09 + /// + [JsonProperty("create_timestamp")] + public DateTime? CreateTimestamp { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Channels/VideoQualityMode.cs b/Oxide.Ext.Discord/Entities/Channels/VideoQualityMode.cs index 4f9dcd358..3cf7d3b0d 100644 --- a/Oxide.Ext.Discord/Entities/Channels/VideoQualityMode.cs +++ b/Oxide.Ext.Discord/Entities/Channels/VideoQualityMode.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Video Quality Mode +/// +public enum VideoQualityMode : byte { /// - /// Represents a Video Quality Mode + /// Discord chooses the quality for optimal performance /// - public enum VideoQualityMode : byte - { - /// - /// Discord chooses the quality for optimal performance - /// - Auto = 1, + Auto = 1, - /// - /// 720p - /// - Full = 2 - } + /// + /// 720p + /// + Full = 2 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/DiscordColor.cs b/Oxide.Ext.Discord/Entities/DiscordColor.cs index 6d4dd4cad..2bfab0e76 100644 --- a/Oxide.Ext.Discord/Entities/DiscordColor.cs +++ b/Oxide.Ext.Discord/Entities/DiscordColor.cs @@ -5,251 +5,250 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Color +/// +[JsonConverter(typeof(DiscordColorConverter))] +public readonly record struct DiscordColor { /// - /// Represents a Discord Color + /// Default Role Color /// - [JsonConverter(typeof(DiscordColorConverter))] - public struct DiscordColor - { - /// - /// Default Role Color - /// - public static readonly DiscordColor Default = new DiscordColor(0); - - /// - /// Teal Role Color - /// - public static readonly DiscordColor Teal = new DiscordColor(0x1ABC9C); - - /// - /// Dark Teal Role Color - /// - public static readonly DiscordColor DarkTeal = new DiscordColor(0x11806A); - - /// - /// Green Role Color - /// - public static readonly DiscordColor Green = new DiscordColor(0x2ECC71); - - /// - /// Dark Green Role Color - /// - public static readonly DiscordColor DarkGreen = new DiscordColor(0x1F8B4C); - - /// - /// Blue Role Color - /// - public static readonly DiscordColor Blue = new DiscordColor(0x3498DB); - - /// - /// Dark Blue Role Color - /// - public static readonly DiscordColor DarkBlue = new DiscordColor(0x206694); - - /// - /// Purple Role Color - /// - public static readonly DiscordColor Purple = new DiscordColor(0x9B59B6); - - /// - /// Dark Purple Role Color - /// - public static readonly DiscordColor DarkPurple = new DiscordColor(0x71368A); - - /// - /// Magenta Role Color - /// - public static readonly DiscordColor Magenta = new DiscordColor(0xE91E63); - - /// - /// Dark Magenta Role Color - /// - public static readonly DiscordColor DarkMagenta = new DiscordColor(0xAD1457); - - /// - /// Gold Role Color - /// - public static readonly DiscordColor Gold = new DiscordColor(0xF1C40F); - - /// - /// Light Orange Role Color - /// - public static readonly DiscordColor LightOrange = new DiscordColor(0xC27C0E); - - /// - /// Orange Role Color - /// - public static readonly DiscordColor Orange = new DiscordColor(0xE67E22); - - /// - /// Dark Orange Role Color - /// - public static readonly DiscordColor DarkOrange = new DiscordColor(0xA84300); - - /// - /// Red Role Color - /// - public static readonly DiscordColor Red = new DiscordColor(0xE74C3C); - - /// - /// Dark Red Role Color - /// - public static readonly DiscordColor DarkRed = new DiscordColor(0x992D22); - - /// - /// Light Gray Role Color - /// - public static readonly DiscordColor LightGrey = new DiscordColor(0x979C9F); - - /// - /// Lighter Gray Role Color - /// - public static readonly DiscordColor LighterGrey = new DiscordColor(0x95A5A6); - - /// - /// Dark Gray Role Color - /// - public static readonly DiscordColor DarkGrey = new DiscordColor(0x607D8B); - - /// - /// Darker Gray Role Color - /// - public static readonly DiscordColor DarkerGrey = new DiscordColor(0x546E7A); - - /// - /// Discord Success Color - /// - public static readonly DiscordColor Success = new DiscordColor(0x57F287); - - /// - /// Discord Warning Color - /// - public static readonly DiscordColor Warning = new DiscordColor(0xFEE75C); - - /// - /// Discord Danger Color - /// - public static readonly DiscordColor Danger = new DiscordColor(0xED4245); - - /// - /// Discord Old Blurple Color - /// - public static readonly DiscordColor BlurpleOld = new DiscordColor(0x7289DA); - - /// - /// Discord Blurple Color - /// - public static readonly DiscordColor Blurple = new DiscordColor(0x5865F2); - - /// - /// Discord Fuchsia Color - /// - public static readonly DiscordColor Fuchsia = new DiscordColor(0xEB459E); + public static readonly DiscordColor Default = new(0); + + /// + /// Teal Role Color + /// + public static readonly DiscordColor Teal = new(0x1ABC9C); + + /// + /// Dark Teal Role Color + /// + public static readonly DiscordColor DarkTeal = new(0x11806A); + + /// + /// Green Role Color + /// + public static readonly DiscordColor Green = new(0x2ECC71); + + /// + /// Dark Green Role Color + /// + public static readonly DiscordColor DarkGreen = new(0x1F8B4C); + + /// + /// Blue Role Color + /// + public static readonly DiscordColor Blue = new(0x3498DB); + + /// + /// Dark Blue Role Color + /// + public static readonly DiscordColor DarkBlue = new(0x206694); + + /// + /// Purple Role Color + /// + public static readonly DiscordColor Purple = new(0x9B59B6); + + /// + /// Dark Purple Role Color + /// + public static readonly DiscordColor DarkPurple = new(0x71368A); + + /// + /// Magenta Role Color + /// + public static readonly DiscordColor Magenta = new(0xE91E63); + + /// + /// Dark Magenta Role Color + /// + public static readonly DiscordColor DarkMagenta = new(0xAD1457); + + /// + /// Gold Role Color + /// + public static readonly DiscordColor Gold = new(0xF1C40F); + + /// + /// Light Orange Role Color + /// + public static readonly DiscordColor LightOrange = new(0xC27C0E); + + /// + /// Orange Role Color + /// + public static readonly DiscordColor Orange = new(0xE67E22); + + /// + /// Dark Orange Role Color + /// + public static readonly DiscordColor DarkOrange = new(0xA84300); + + /// + /// Red Role Color + /// + public static readonly DiscordColor Red = new(0xE74C3C); + + /// + /// Dark Red Role Color + /// + public static readonly DiscordColor DarkRed = new(0x992D22); + + /// + /// Light Gray Role Color + /// + public static readonly DiscordColor LightGrey = new(0x979C9F); + + /// + /// Lighter Gray Role Color + /// + public static readonly DiscordColor LighterGrey = new(0x95A5A6); + + /// + /// Dark Gray Role Color + /// + public static readonly DiscordColor DarkGrey = new(0x607D8B); + + /// + /// Darker Gray Role Color + /// + public static readonly DiscordColor DarkerGrey = new(0x546E7A); + + /// + /// Discord Success Color + /// + public static readonly DiscordColor Success = new(0x57F287); + + /// + /// Discord Warning Color + /// + public static readonly DiscordColor Warning = new(0xFEE75C); + + /// + /// Discord Danger Color + /// + public static readonly DiscordColor Danger = new(0xED4245); + + /// + /// Discord Old Blurple Color + /// + public static readonly DiscordColor BlurpleOld = new(0x7289DA); + + /// + /// Discord Blurple Color + /// + public static readonly DiscordColor Blurple = new(0x5865F2); + + /// + /// Discord Fuchsia Color + /// + public static readonly DiscordColor Fuchsia = new(0xEB459E); - /// - /// uint value of the hex color code - /// - public readonly uint Color; + /// + /// uint value of the hex color code + /// + public readonly uint Color; - /// - /// DiscordColor Constructor - /// - /// uint value of hex color code - public DiscordColor(uint color) - { - InvalidDiscordColorException.ThrowIfInvalidColor(color); + /// + /// DiscordColor Constructor + /// + /// uint value of hex color code + public DiscordColor(uint color) + { + InvalidDiscordColorException.ThrowIfInvalidColor(color); - Color = color; - } + Color = color; + } - /// - /// DiscordColor Constructor - /// - /// string hex color code - /// Throw if color is greater than #FFFFFF - public DiscordColor(string color) : this(uint.Parse(color.TrimStart('#'), NumberStyles.AllowHexSpecifier)) { } + /// + /// DiscordColor Constructor + /// + /// string hex color code + /// Throw if color is greater than #FFFFFF + public DiscordColor(string color) : this(uint.Parse(color.TrimStart('#'), NumberStyles.AllowHexSpecifier)) { } - /// - /// DiscordColor Constructor - /// - /// Red color (0-255) - /// Green color (0-255) - /// Blue color (0-255) - public DiscordColor(byte red, byte green, byte blue) - { - Color = (uint)((red << 16) + (green << 8) + blue); - } - - /// - /// DiscordColor Constructor - /// - /// Red color (0-255) - /// Green color (0-255) - /// Blue color (0-255) - /// Thrown if any of the colors are < 0 or > 255 - public DiscordColor(int red, int green, int blue) - { - InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(red), red); - InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(green), green); - InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(blue), blue); + /// + /// DiscordColor Constructor + /// + /// Red color (0-255) + /// Green color (0-255) + /// Blue color (0-255) + public DiscordColor(byte red, byte green, byte blue) + { + Color = (uint)((red << 16) + (green << 8) + blue); + } + + /// + /// DiscordColor Constructor + /// + /// Red color (0-255) + /// Green color (0-255) + /// Blue color (0-255) + /// Thrown if any of the colors are < 0 or > 255 + public DiscordColor(int red, int green, int blue) + { + InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(red), red); + InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(green), green); + InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(blue), blue); - Color = (uint)((red << 16) + (green << 8) + blue); - } - - /// - /// DiscordColor Constructor - /// - /// Red color (0-255) - /// Green color (0-255) - /// Blue color (0-255) - /// Thrown if any of the colors are > 255 - public DiscordColor(uint red, uint green, uint blue) - { - InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(red), red); - InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(green), green); - InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(blue), blue); + Color = (uint)((red << 16) + (green << 8) + blue); + } + + /// + /// DiscordColor Constructor + /// + /// Red color (0-255) + /// Green color (0-255) + /// Blue color (0-255) + /// Thrown if any of the colors are > 255 + public DiscordColor(uint red, uint green, uint blue) + { + InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(red), red); + InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(green), green); + InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(blue), blue); - Color = (red << 16) + (green << 8) + blue; - } + Color = (red << 16) + (green << 8) + blue; + } - /// - /// DiscordColor Constructor - /// - /// Red color (0.0 - 1.0) - /// Green color (0.0 - 1.0) - /// Blue color (0.0 - 1.0) - /// Thrown if any of the colors are < 0.0 or > 1.0 - public DiscordColor(float red, float green, float blue) - { - InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(red), red); - InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(green), green); - InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(blue), blue); + /// + /// DiscordColor Constructor + /// + /// Red color (0.0 - 1.0) + /// Green color (0.0 - 1.0) + /// Blue color (0.0 - 1.0) + /// Thrown if any of the colors are < 0.0 or > 1.0 + public DiscordColor(float red, float green, float blue) + { + InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(red), red); + InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(green), green); + InvalidDiscordColorException.ThrowIfOutOfColorRange(nameof(blue), blue); - Color = ((uint)(red * 255) << 16) + ((uint)(green * 255) << 8) + (uint)(blue * 255); - } - - /// - /// DiscordColor Constructor - /// - /// Red color (0.0 - 1.0) - /// Green color (0.0 - 1.0) - /// Blue color (0.0 - 1.0) - /// Thrown if any of the colors are < 0.0 or > 1.0 - public DiscordColor(double red, double green, double blue) : this((float)red, (float)green, (float)blue) { } - - /// - /// Returns the color as a string - /// - /// - public override string ToString() => Color.ToString(); - - /// - /// Returns the color as a hex color code - /// - /// - [Pure] - public string ToHex() => $"#{Color.ToString("X6")}"; + Color = ((uint)(red * 255) << 16) + ((uint)(green * 255) << 8) + (uint)(blue * 255); } + + /// + /// DiscordColor Constructor + /// + /// Red color (0.0 - 1.0) + /// Green color (0.0 - 1.0) + /// Blue color (0.0 - 1.0) + /// Thrown if any of the colors are < 0.0 or > 1.0 + public DiscordColor(double red, double green, double blue) : this((float)red, (float)green, (float)blue) { } + + /// + /// Returns the color as a string + /// + /// + public override string ToString() => Color.ToString(); + + /// + /// Returns the color as a hex color code + /// + /// + [Pure] + public string ToHex() => $"#{Color.ToString("X6")}"; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Emojis/DefaultReaction.cs b/Oxide.Ext.Discord/Entities/Emojis/DefaultReaction.cs index 8028bc534..b7a942d10 100644 --- a/Oxide.Ext.Discord/Entities/Emojis/DefaultReaction.cs +++ b/Oxide.Ext.Discord/Entities/Emojis/DefaultReaction.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Default Reaction Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DefaultReaction { /// - /// Represents Default Reaction Structure + /// The id of a guild's custom emoji /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DefaultReaction - { - /// - /// The id of a guild's custom emoji - /// - [JsonProperty("emoji_id")] - public Snowflake? EmojiId { get; set; } + [JsonProperty("emoji_id")] + public Snowflake? EmojiId { get; set; } - /// - /// The unicode character of the emoji - /// - [JsonProperty("emoji_name")] - public string EmojiName { get; set; } - } + /// + /// The unicode character of the emoji + /// + [JsonProperty("emoji_name")] + public string EmojiName { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Emojis/DiscordEmoji.cs b/Oxide.Ext.Discord/Entities/Emojis/DiscordEmoji.cs index 733667109..798273daa 100644 --- a/Oxide.Ext.Discord/Entities/Emojis/DiscordEmoji.cs +++ b/Oxide.Ext.Discord/Entities/Emojis/DiscordEmoji.cs @@ -3,116 +3,115 @@ using Oxide.Ext.Discord.Helpers; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Emoji Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordEmoji : EmojiUpdate, ISnowflakeEntity { /// - /// Represents Emoji Structure + /// The ID for the emoji if it is custom; Otherwise default snowflake /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordEmoji : EmojiUpdate, ISnowflakeEntity - { - /// - /// The ID for the emoji if it is custom; Otherwise invalid snowflake - /// - public Snowflake Id => EmojiId ?? default(Snowflake); + public Snowflake Id => EmojiId ?? default(Snowflake); - /// - /// Emoji id - /// - [JsonProperty("id")] - public Snowflake? EmojiId { get; set; } + /// + /// Emoji id + /// + [JsonProperty("id")] + public Snowflake? EmojiId { get; set; } - /// - /// User that created this emoji - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } + /// + /// User that created this emoji + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } - /// - /// Whether this emoji must be wrapped in colons - /// - [JsonProperty("require_colons")] - public bool? RequireColons { get; set; } + /// + /// Whether this emoji must be wrapped in colons + /// + [JsonProperty("require_colons")] + public bool? RequireColons { get; set; } - /// - /// Whether this emoji is managed - /// - [JsonProperty("managed")] - public bool? Managed { get; set; } + /// + /// Whether this emoji is managed + /// + [JsonProperty("managed")] + public bool? Managed { get; set; } - /// - /// Whether this emoji is animated - /// - [JsonProperty("animated")] - public bool? Animated { get; set; } + /// + /// Whether this emoji is animated + /// + [JsonProperty("animated")] + public bool? Animated { get; set; } - /// - /// Whether this emoji can be used, may be false due to loss of Server Boosts - /// - [JsonProperty("available")] - public bool? Available { get; set; } + /// + /// Whether this emoji can be used, may be false due to loss of Server Boosts + /// + [JsonProperty("available")] + public bool? Available { get; set; } - /// - /// Url to the emoji image - /// - public string Url => EmojiId.HasValue ? DiscordCdn.GetCustomEmojiUrl(EmojiId.Value, Animated.HasValue && Animated.Value ? DiscordImageFormat.Gif : DiscordImageFormat.Png) : null; + /// + /// Url to the emoji image + /// + public string Url => EmojiId.HasValue ? DiscordCdn.GetCustomEmojiUrl(EmojiId.Value, Animated.HasValue && Animated.Value ? DiscordImageFormat.Gif : DiscordImageFormat.Png) : null; - /// - /// Show the emoji in a message - /// - public string Mention => DiscordFormatting.EmojiMessageString(this); + /// + /// Show the emoji in a message + /// + public string Mention => DiscordFormatting.EmojiMessageString(this); - /// - /// Returns an emoji object for the given emoji character - /// - /// - /// - public static DiscordEmoji FromCharacter(string emoji) + /// + /// Returns an emoji object for the given emoji character + /// + /// + /// + public static DiscordEmoji FromCharacter(string emoji) + { + return new DiscordEmoji { - return new DiscordEmoji - { - Name = emoji - }; - } + Name = emoji + }; + } - /// - /// Returns an Emoji object from a custom emoji ID and Animated flag - /// - /// ID of the emoji - /// If the emoji is animated - /// - public static DiscordEmoji FromCustom(Snowflake id, bool animated = false) + /// + /// Returns an Emoji object from a custom emoji ID and Animated flag + /// + /// ID of the emoji + /// If the emoji is animated + /// + public static DiscordEmoji FromCustom(Snowflake id, bool animated = false) + { + return new DiscordEmoji { - return new DiscordEmoji - { - EmojiId = id, - Animated = animated - }; - } + EmojiId = id, + Animated = animated + }; + } - /// - /// Returns the data string to be used in the API request - /// - /// - public string ToDataString() + /// + /// Returns the data string to be used in the API request + /// + /// + public string ToDataString() + { + if (!EmojiId.HasValue) { - if (!EmojiId.HasValue) - { - return Name; - } - - return Uri.EscapeDataString(DiscordFormatting.CustomEmojiDataString(EmojiId.Value, Name, Animated ?? false)); + return Name; } - internal void Update(DiscordEmoji emoji) - { - if (emoji.Name != null) Name = emoji.Name; - if (emoji.Roles != null) Roles = emoji.Roles; - if (emoji.User != null) User = emoji.User; - if (emoji.RequireColons != null) RequireColons = emoji.RequireColons; - if (emoji.Managed != null) Managed = emoji.Managed; - if (emoji.Animated != null) Animated = emoji.Animated; - if (emoji.Available != null) Available = emoji.Available; - } + return Uri.EscapeDataString(DiscordFormatting.CustomEmojiDataString(EmojiId.Value, Name, Animated ?? false)); + } + + internal void Update(DiscordEmoji emoji) + { + if (emoji.Name != null) Name = emoji.Name; + if (emoji.Roles != null) Roles = emoji.Roles; + if (emoji.User != null) User = emoji.User; + if (emoji.RequireColons != null) RequireColons = emoji.RequireColons; + if (emoji.Managed != null) Managed = emoji.Managed; + if (emoji.Animated != null) Animated = emoji.Animated; + if (emoji.Available != null) Available = emoji.Available; } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Emojis/EmojiCreate.cs b/Oxide.Ext.Discord/Entities/Emojis/EmojiCreate.cs index 3157e9562..f9357aa8b 100644 --- a/Oxide.Ext.Discord/Entities/Emojis/EmojiCreate.cs +++ b/Oxide.Ext.Discord/Entities/Emojis/EmojiCreate.cs @@ -3,39 +3,38 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Emoji Create Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class EmojiCreate : IDiscordValidation { /// - /// Represents Emoji Create Structure + /// Emoji name /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class EmojiCreate : IDiscordValidation - { - /// - /// Emoji name - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// The 128x128 emoji image - /// Emojis and animated emojis have a maximum file size of 256kb. - /// Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request - /// - [JsonProperty("image")] - public DiscordImageData ImageData { get; set; } + /// + /// The 128x128 emoji image + /// Emojis and animated emojis have a maximum file size of 256kb. + /// Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request + /// + [JsonProperty("image")] + public DiscordImageData ImageData { get; set; } - /// - /// Roles this emoji is whitelisted to - /// - [JsonProperty("roles")] - public List Roles { get; set; } + /// + /// Roles this emoji is whitelisted to + /// + [JsonProperty("roles")] + public List Roles { get; set; } - /// - public void Validate() - { - InvalidEmojiException.ThrowIfInvalidName(Name, false); - InvalidEmojiException.ThrowIfInvalidImageData(ImageData); - } + /// + public void Validate() + { + InvalidEmojiException.ThrowIfInvalidName(Name, false); + InvalidEmojiException.ThrowIfInvalidImageData(ImageData); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Emojis/EmojiUpdate.cs b/Oxide.Ext.Discord/Entities/Emojis/EmojiUpdate.cs index 0428eb7a5..fbcfd7091 100644 --- a/Oxide.Ext.Discord/Entities/Emojis/EmojiUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Emojis/EmojiUpdate.cs @@ -3,30 +3,29 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Emoji Update Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class EmojiUpdate : IDiscordValidation { /// - /// Represents Emoji Update Structure + /// Emoji name /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class EmojiUpdate : IDiscordValidation - { - /// - /// Emoji name - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Roles this emoji is whitelisted to - /// - [JsonProperty("roles")] - public List Roles { get; set; } + /// + /// Roles this emoji is whitelisted to + /// + [JsonProperty("roles")] + public List Roles { get; set; } - /// - public void Validate() - { - InvalidEmojiException.ThrowIfInvalidName(Name, true); - } + /// + public void Validate() + { + InvalidEmojiException.ThrowIfInvalidName(Name, true); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/CommandPayload.cs b/Oxide.Ext.Discord/Entities/Gateway/CommandPayload.cs index 7f4730052..2e8686dee 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/CommandPayload.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/CommandPayload.cs @@ -2,55 +2,54 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a command payload +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class CommandPayload : BasePoolable { /// - /// Represents a command payload + /// Command Code for the payload /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class CommandPayload : BasePoolable - { - /// - /// Command Code for the payload - /// - [JsonProperty("op")] - public GatewayCommandCode OpCode; + [JsonProperty("op")] + public GatewayCommandCode OpCode; - /// - /// Payload data - /// - [JsonProperty("d")] - public object Payload; + /// + /// Payload data + /// + [JsonProperty("d")] + public object Payload; - /// - /// Creates a for the web socket - /// - /// OP Code for the command - /// Payload for the command - /// - public static CommandPayload CreatePayload(GatewayCommandCode code, object payload) - { - CommandPayload command = DiscordPool.Internal.Get(); - command.Init(code, payload); - return command; - } + /// + /// Creates a for the web socket + /// + /// OP Code for the command + /// Payload for the command + /// + public static CommandPayload CreatePayload(GatewayCommandCode code, object payload) + { + CommandPayload command = DiscordPool.Internal.Get(); + command.Init(code, payload); + return command; + } - /// - /// Initializes the pooled command payload - /// - /// OP Code for the command - /// Payload for the command - private void Init(GatewayCommandCode code, object payload) - { - OpCode = code; - Payload = payload; - } + /// + /// Initializes the pooled command payload + /// + /// OP Code for the command + /// Payload for the command + private void Init(GatewayCommandCode code, object payload) + { + OpCode = code; + Payload = payload; + } - /// - protected override void EnterPool() - { - OpCode = default(GatewayCommandCode); - Payload = null; - } + /// + protected override void EnterPool() + { + OpCode = default; + Payload = null; } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Commands/ClientStatus.cs b/Oxide.Ext.Discord/Entities/Gateway/Commands/ClientStatus.cs index 23d1b0e3a..91b06a425 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Commands/ClientStatus.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Commands/ClientStatus.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Client Status Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ClientStatus { /// - /// Represents Client Status Structure + /// The user's status set for an active desktop (Windows, Linux, Mac) application session /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ClientStatus - { - /// - /// The user's status set for an active desktop (Windows, Linux, Mac) application session - /// - [JsonProperty("desktop")] - public string Desktop { get; set; } + [JsonProperty("desktop")] + public string Desktop { get; set; } - /// - /// The user's status set for an active mobile (iOS, Android) application session - /// - [JsonProperty("mobile")] - public string Mobile { get; set; } + /// + /// The user's status set for an active mobile (iOS, Android) application session + /// + [JsonProperty("mobile")] + public string Mobile { get; set; } - /// - /// The user's status set for an active web (browser, bot account) application session - /// - [JsonProperty("web")] - public string Web { get; set; } - } + /// + /// The user's status set for an active web (browser, bot account) application session + /// + [JsonProperty("web")] + public string Web { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Commands/GatewayCommandCode.cs b/Oxide.Ext.Discord/Entities/Gateway/Commands/GatewayCommandCode.cs index b7c6aa6e7..4fd85d1cc 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Commands/GatewayCommandCode.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Commands/GatewayCommandCode.cs @@ -1,38 +1,37 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Gateway Opcodes +/// +public enum GatewayCommandCode : byte { /// - /// Represents Gateway Opcodes + /// Maintains an active gateway connection /// - public enum GatewayCommandCode : byte - { - /// - /// Maintains an active gateway connection - /// - Heartbeat = 1, + Heartbeat = 1, - /// - /// Starts a new session during the initial handshake. - /// - Identify = 2, + /// + /// Starts a new session during the initial handshake. + /// + Identify = 2, - /// - /// Update the client's status. - /// - PresenceUpdate = 3, + /// + /// Update the client's status. + /// + PresenceUpdate = 3, - /// - /// Used to join/leave or move between voice channels. - /// - VoiceStateUpdate = 4, + /// + /// Used to join/leave or move between voice channels. + /// + VoiceStateUpdate = 4, - /// - /// Resume a previous session that was disconnected. - /// - Resume = 6, + /// + /// Resume a previous session that was disconnected. + /// + Resume = 6, - /// - /// Request information about offline guild members in a large guild. - /// - RequestGuildMembers = 8, - } + /// + /// Request information about offline guild members in a large guild. + /// + RequestGuildMembers = 8, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Commands/GuildMembersRequestCommand.cs b/Oxide.Ext.Discord/Entities/Gateway/Commands/GuildMembersRequestCommand.cs index 36bdb462e..53961f93c 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Commands/GuildMembersRequestCommand.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Commands/GuildMembersRequestCommand.cs @@ -1,49 +1,48 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Request Guild Members +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildMembersRequestCommand { /// - /// Represents Request Guild Members + /// ID of the guild to get members for /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildMembersRequestCommand - { - /// - /// ID of the guild to get members for - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// String that username starts with, or an empty string to return all members - /// - [JsonProperty("query")] - public string Query { get; set; } = ""; + /// + /// String that username starts with, or an empty string to return all members + /// + [JsonProperty("query")] + public string Query { get; set; } = ""; - /// - /// Maximum number of members to send matching the query; - /// a limit of 0 can be used with an empty string query to return all members - /// - [JsonProperty("limit")] - public int Limit { get; set; } = 0; + /// + /// Maximum number of members to send matching the query; + /// a limit of 0 can be used with an empty string query to return all members + /// + [JsonProperty("limit")] + public int Limit { get; set; } = 0; - /// - /// Used to specify if we want the presences of the matched members - /// - [JsonProperty("presences")] - public bool? Presences { get; set; } + /// + /// Used to specify if we want the presences of the matched members + /// + [JsonProperty("presences")] + public bool? Presences { get; set; } - /// - /// Used to specify which users you wish to fetch - /// - [JsonProperty("user_ids")] - public List UserIds { get; set; } + /// + /// Used to specify which users you wish to fetch + /// + [JsonProperty("user_ids")] + public List UserIds { get; set; } - /// - /// Nonce to identify the Guild Members Chunk response (Up to 25 characters) - /// - [JsonProperty("nonce")] - public string Nonce { get; set; } - } + /// + /// Nonce to identify the Guild Members Chunk response (Up to 25 characters) + /// + [JsonProperty("nonce")] + public string Nonce { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Commands/IdentifyCommand.cs b/Oxide.Ext.Discord/Entities/Gateway/Commands/IdentifyCommand.cs index 470a76fbb..ed813fc18 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Commands/IdentifyCommand.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Commands/IdentifyCommand.cs @@ -2,96 +2,92 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Identify Command +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class IdentifyCommand { /// - /// Represents Identify Command + /// Authentication token /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class IdentifyCommand - { - /// - /// Authentication token - /// - [JsonProperty("token")] - public string Token; + [JsonProperty("token")] + public string Token; - /// - /// Connection properties - /// - [JsonProperty("properties")] - public ConnectionProperties Properties; + /// + /// Connection properties + /// + [JsonProperty("properties")] + public ConnectionProperties Properties; - /// - /// Whether this connection supports compression of packets - /// - [JsonProperty("compress")] - public bool? Compress; + /// + /// Whether this connection supports compression of packets + /// + [JsonProperty("compress")] + public bool? Compress; - /// - /// Value between 50 and 250, total number of members where the gateway will stop sending offline members in the guild member list - /// - [JsonProperty("large_threshold")] - public int? LargeThreshold; + /// + /// Value between 50 and 250, total number of members where the gateway will stop sending offline members in the guild member list + /// + [JsonProperty("large_threshold")] + public int? LargeThreshold; - /// - /// Used for Guild Sharding - /// See Guild Sharding - /// - [JsonProperty("shard")] - public List Shard; + /// + /// Used for Guild Sharding + /// See Guild Sharding + /// + [JsonProperty("shard")] + public List Shard; - /// - /// Presence structure for initial presence information - /// - [JsonProperty("presence")] - public UpdatePresenceCommand PresenceUpdate; + /// + /// Presence structure for initial presence information + /// + [JsonProperty("presence")] + public UpdatePresenceCommand PresenceUpdate; - /// - /// The Gateway Intents you wish to receive - /// See Gateway Intents - /// See - /// - [JsonProperty("intents")] - public GatewayIntents Intents { get; set; } - } + /// + /// The Gateway Intents you wish to receive + /// See Gateway Intents + /// See + /// + [JsonProperty("intents")] + public GatewayIntents Intents { get; set; } +} +/// +/// Represents Identify Connection Properties +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ConnectionProperties +{ /// - /// Represents Identify Connection Properties + /// Your operating system /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ConnectionProperties + [JsonProperty("os")] + public string OperatingSystem { - /// - /// Your operating system - /// - [JsonProperty("os")] - public string OperatingSystem + get { - get + return Environment.OSVersion.Platform switch { - switch (Environment.OSVersion.Platform) - { - case PlatformID.Unix: - return "unix"; - case PlatformID.MacOSX: - return "mac"; - default: - return "windows"; - } - } + PlatformID.Unix => "unix", + PlatformID.MacOSX => "mac", + _ => "windows" + }; } + } - /// - /// Your library name - /// - [JsonProperty("browser")] - public string Browser => "Oxide.Ext.Discord"; + /// + /// Your library name + /// + [JsonProperty("browser")] + public string Browser => "Oxide.Ext.Discord"; - /// - /// Your library name - /// - [JsonProperty("device")] - public string Device => Browser; - } -} + /// + /// Your library name + /// + [JsonProperty("device")] + public string Device => Browser; +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Commands/ResumeSessionCommand.cs b/Oxide.Ext.Discord/Entities/Gateway/Commands/ResumeSessionCommand.cs index cb74ee46f..b3f8f29f5 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Commands/ResumeSessionCommand.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Commands/ResumeSessionCommand.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Resume +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ResumeSessionCommand { /// - /// Represents Resume + /// Session token /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ResumeSessionCommand - { - /// - /// Session token - /// - [JsonProperty("token")] - public string Token; + [JsonProperty("token")] + public string Token; - /// - /// Session ID - /// - [JsonProperty("session_id")] - public string SessionId; + /// + /// Session ID + /// + [JsonProperty("session_id")] + public string SessionId; - /// - /// Last sequence number received - /// - [JsonProperty("seq")] - public int Sequence; - } -} + /// + /// Last sequence number received + /// + [JsonProperty("seq")] + public int Sequence; +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Commands/UpdatePresenceCommand.cs b/Oxide.Ext.Discord/Entities/Gateway/Commands/UpdatePresenceCommand.cs index be914504b..0c9085033 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Commands/UpdatePresenceCommand.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Commands/UpdatePresenceCommand.cs @@ -1,37 +1,36 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Update Status +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class UpdatePresenceCommand { /// - /// Represents Update Status + /// The user's new status + /// /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class UpdatePresenceCommand - { - /// - /// The user's new status - /// - /// - [JsonProperty("status")] - public UserStatusType Status { get; set; } = UserStatusType.Online; + [JsonProperty("status")] + public UserStatusType Status { get; set; } = UserStatusType.Online; - /// - /// The user's activities (Required) - /// - [JsonProperty("activities")] - public List Activities { get; set; } + /// + /// The user's activities (Required) + /// + [JsonProperty("activities")] + public List Activities { get; set; } - /// - /// Unix time (in milliseconds) of when the client went idle, or null if the client is not idle - /// - [JsonProperty("since")] - public int? Since { get; set; } = 0; + /// + /// Unix time (in milliseconds) of when the client went idle, or null if the client is not idle + /// + [JsonProperty("since")] + public int? Since { get; set; } = 0; - /// - /// Whether or not the client is afk - /// - [JsonProperty("afk")] - public bool Afk { get; set; } = false; - } -} + /// + /// Whether or not the client is afk + /// + [JsonProperty("afk")] + public bool Afk { get; set; } = false; +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Commands/UpdateVoiceStatusCommand.cs b/Oxide.Ext.Discord/Entities/Gateway/Commands/UpdateVoiceStatusCommand.cs index a57fe5083..8d745988b 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Commands/UpdateVoiceStatusCommand.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Commands/UpdateVoiceStatusCommand.cs @@ -1,35 +1,34 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Update Voice State +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class UpdateVoiceStatusCommand { /// - /// Represents Update Voice State + /// ID of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class UpdateVoiceStatusCommand - { - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// ID of the voice channel client wants to join (null if disconnecting) - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } + /// + /// ID of the voice channel client wants to join (null if disconnecting) + /// + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } - /// - /// Is the client muted - /// - [JsonProperty("self_mute")] - public bool SelfMute { get; set; } + /// + /// Is the client muted + /// + [JsonProperty("self_mute")] + public bool SelfMute { get; set; } - /// - /// Is the client deafened - /// - [JsonProperty("self_deaf")] - public bool SelfDeaf { get; set; } - } + /// + /// Is the client deafened + /// + [JsonProperty("self_deaf")] + public bool SelfDeaf { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Commands/WebSocketCommand.cs b/Oxide.Ext.Discord/Entities/Gateway/Commands/WebSocketCommand.cs index b30fbffec..af0b33559 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Commands/WebSocketCommand.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Commands/WebSocketCommand.cs @@ -4,56 +4,55 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a command to be sent over the web socket +/// +public class WebSocketCommand : BasePoolable, IDebugLoggable { /// - /// Represents a command to be sent over the web socket + /// Client requesting the command /// - public class WebSocketCommand : BasePoolable, IDebugLoggable - { - /// - /// Client requesting the command - /// - public DiscordClient Client; + public DiscordClient Client; - /// - /// Payload for the command - /// - public CommandPayload Payload; + /// + /// Payload for the command + /// + public CommandPayload Payload; - /// - /// Creates a new - /// - /// Client for the command - /// For the command - /// Payload for the command - /// - internal static WebSocketCommand CreateCommand(DiscordClient client, GatewayCommandCode code, object payload) - { - WebSocketCommand command = DiscordPool.Internal.Get(); - command.Init(client, code, payload); - return command; - } + /// + /// Creates a new + /// + /// Client for the command + /// For the command + /// Payload for the command + /// + internal static WebSocketCommand CreateCommand(DiscordClient client, GatewayCommandCode code, object payload) + { + WebSocketCommand command = DiscordPool.Internal.Get(); + command.Init(client, code, payload); + return command; + } - private void Init(DiscordClient client, GatewayCommandCode code, object payload) - { - Client = client; - Payload = CommandPayload.CreatePayload(code, payload); - } + private void Init(DiscordClient client, GatewayCommandCode code, object payload) + { + Client = client; + Payload = CommandPayload.CreatePayload(code, payload); + } - /// - protected override void EnterPool() - { - Payload?.Dispose(); - Client = null; - Payload = null; - } + /// + protected override void EnterPool() + { + Payload?.Dispose(); + Client = null; + Payload = null; + } - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendField("Plugin", Client.PluginName); - logger.AppendFieldEnum("Code", Payload.OpCode); - } + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("Plugin", Client.PluginName); + logger.AppendFieldEnum("Code", Payload.OpCode); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/EventPayload.cs b/Oxide.Ext.Discord/Entities/Gateway/EventPayload.cs index 52adc7200..5322dd030 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/EventPayload.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/EventPayload.cs @@ -5,58 +5,57 @@ using Oxide.Ext.Discord.Types; using Oxide.Ext.Discord.WebSockets; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Gateway Payload Structure +/// +[JsonConverter(typeof(EventPayloadConverter))] +public class EventPayload : BasePoolable { /// - /// Represents Gateway Payload Structure + /// Op Code for the payload /// - [JsonConverter(typeof(EventPayloadConverter))] - public class EventPayload : BasePoolable - { - /// - /// Op Code for the payload - /// - public GatewayEventCode OpCode { get; internal set; } + public GatewayEventCode OpCode { get; internal set; } - /// - /// The event name for this payload - /// - public DiscordDispatchCode DispatchCode { get; internal set; } + /// + /// The event name for this payload + /// + public DiscordDispatchCode DispatchCode { get; internal set; } - /// - /// Event data - /// - public object Data { get; internal set; } + /// + /// Event data + /// + public object Data { get; private set; } - /// - /// Sequence number, used for resuming sessions and heartbeats - /// - public int? Sequence { get; internal set; } + /// + /// Sequence number, used for resuming sessions and heartbeats + /// + public int? Sequence { get; internal set; } - /// - /// If the websocket should resume on reconnect. - /// - public bool ShouldResume { get; internal set; } + /// + /// If the websocket should resume on reconnect. + /// + public bool ShouldResume { get; internal set; } - internal JToken JsonData { get; set; } + internal JToken JsonData { get; set; } - /// - /// Returns the Data as {T} - /// - /// Type to convert Data to - /// Data converted to {T} - public T GetData(BotClient client) - { - return JsonData.ToObject(client.JsonSerializer); - } + /// + /// Returns the Data as {T} + /// + /// Type to convert Data to + /// Data converted to {T} + public T GetData(BotClient client) + { + return JsonData.ToObject(client.JsonSerializer); + } - /// - protected override void EnterPool() - { - OpCode = default(GatewayEventCode); - DispatchCode = default(DiscordDispatchCode); - Data = null; - Sequence = null; - } + /// + protected override void EnterPool() + { + OpCode = default; + DispatchCode = default; + Data = null; + Sequence = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/AutoModActionExecutionEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/AutoModActionExecutionEvent.cs index 71d9c586a..1084db4d6 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/AutoModActionExecutionEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/AutoModActionExecutionEvent.cs @@ -1,71 +1,70 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Auto Moderation Action Execution Event +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class AutoModActionExecutionEvent { /// - /// Represents Auto Moderation Action Execution Event + /// Id of the guild in which action was executed /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class AutoModActionExecutionEvent - { - /// - /// Id of the guild in which action was executed - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The action which was executed - /// - [JsonProperty("action")] - public AutoModAction Action { get; set; } + /// + /// The action which was executed + /// + [JsonProperty("action")] + public AutoModAction Action { get; set; } - /// - /// Id of the rule which action belongs to - /// - [JsonProperty("rule_id")] - public Snowflake RuleId { get; set; } + /// + /// Id of the rule which action belongs to + /// + [JsonProperty("rule_id")] + public Snowflake RuleId { get; set; } - /// - /// The of rule which was triggered - /// - [JsonProperty("rule_trigger_type")] - public AutoModTriggerType RuleTriggerType { get; set; } + /// + /// The of rule which was triggered + /// + [JsonProperty("rule_trigger_type")] + public AutoModTriggerType RuleTriggerType { get; set; } - /// - /// Id of the user which generated the content which triggered the rule - /// - [JsonProperty("user_id")] - public Snowflake? UserId { get; set; } + /// + /// Id of the user which generated the content which triggered the rule + /// + [JsonProperty("user_id")] + public Snowflake? UserId { get; set; } - /// - /// Id of any user message which content belongs to - /// - [JsonProperty("message_id")] - public Snowflake? MessageId { get; set; } + /// + /// Id of any user message which content belongs to + /// + [JsonProperty("message_id")] + public Snowflake? MessageId { get; set; } - /// - /// The id of any system auto moderation messages posted as a result of this action - /// - [JsonProperty("alert_system_message_id")] - public Snowflake? AlertSystemMessageId { get; set; } + /// + /// The id of any system auto moderation messages posted as a result of this action + /// + [JsonProperty("alert_system_message_id")] + public Snowflake? AlertSystemMessageId { get; set; } - /// - /// The user generated text content - /// - [JsonProperty("content")] - public string Content { get; set; } + /// + /// The user generated text content + /// + [JsonProperty("content")] + public string Content { get; set; } - /// - /// The word or phrase configured in the rule that triggered the rule - /// - [JsonProperty("matched_keyword")] - public string MatchedKeyword { get; set; } + /// + /// The word or phrase configured in the rule that triggered the rule + /// + [JsonProperty("matched_keyword")] + public string MatchedKeyword { get; set; } - /// - /// The substring in content that triggered the rule - /// - [JsonProperty("matched_content")] - public string MatchedContent { get; set; } - } + /// + /// The substring in content that triggered the rule + /// + [JsonProperty("matched_content")] + public string MatchedContent { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/ChannelPinsUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/ChannelPinsUpdatedEvent.cs index 1ac7695a7..f70c1e402 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/ChannelPinsUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/ChannelPinsUpdatedEvent.cs @@ -1,30 +1,29 @@ using System; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Channel Pins Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ChannelPinsUpdatedEvent { /// - /// Represents Channel Pins Update + /// The id of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ChannelPinsUpdatedEvent - { - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// The id of the channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + /// + /// The id of the channel + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The time at which the most recent pinned message was pinned - /// - [JsonProperty("last_pin_timestamp")] - public DateTime? LastPinTimestamp { get; set; } - } -} + /// + /// The time at which the most recent pinned message was pinned + /// + [JsonProperty("last_pin_timestamp")] + public DateTime? LastPinTimestamp { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayEventCode.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayEventCode.cs index f5f90852a..f418f3cef 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayEventCode.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayEventCode.cs @@ -1,38 +1,37 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Gateway Opcodes +/// +public enum GatewayEventCode : byte { /// - /// Represents Gateway Opcodes + /// An event was dispatched. /// - public enum GatewayEventCode : byte - { - /// - /// An event was dispatched. - /// - Dispatch = 0, + Dispatch = 0, - /// - /// Fired periodically by the client to keep the connection alive. - /// - Heartbeat = 1, + /// + /// Fired periodically by the client to keep the connection alive. + /// + Heartbeat = 1, - /// - /// You should attempt to reconnect and resume immediately. - /// - Reconnect = 7, + /// + /// You should attempt to reconnect and resume immediately. + /// + Reconnect = 7, - /// - /// The session has been invalidated. You should reconnect and identify/resume accordingly. - /// - InvalidSession = 9, + /// + /// The session has been invalidated. You should reconnect and identify/resume accordingly. + /// + InvalidSession = 9, - /// - /// Sent immediately after connecting, contains the heartbeat_interval to use. - /// - Hello = 10, + /// + /// Sent immediately after connecting, contains the heartbeat_interval to use. + /// + Hello = 10, - /// - /// Sent in response to receiving a heartbeat to acknowledge that it has been received. - /// - HeartbeatAcknowledge = 11 - } + /// + /// Sent in response to receiving a heartbeat to acknowledge that it has been received. + /// + HeartbeatAcknowledge = 11 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayHelloEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayHelloEvent.cs index 4f174b026..e0dcfa4f4 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayHelloEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayHelloEvent.cs @@ -1,18 +1,17 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Hello +/// Sent on connection to the websocket. Defines the heartbeat interval that the client should heartbeat to. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GatewayHelloEvent { /// - /// Represents Hello - /// Sent on connection to the websocket. Defines the heartbeat interval that the client should heartbeat to. + /// The interval (in milliseconds) the client should heartbeat with /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GatewayHelloEvent - { - /// - /// The interval (in milliseconds) the client should heartbeat with - /// - [JsonProperty("heartbeat_interval")] - public int HeartbeatInterval { get; set; } - } -} + [JsonProperty("heartbeat_interval")] + public int HeartbeatInterval { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayReadyEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayReadyEvent.cs index 58f76b4c6..b459bda2a 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayReadyEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayReadyEvent.cs @@ -3,59 +3,58 @@ using Oxide.Ext.Discord.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Ready +/// The ready event is dispatched when a client has completed the initial handshake with the gateway (for new sessions) +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GatewayReadyEvent { /// - /// Represents Ready - /// The ready event is dispatched when a client has completed the initial handshake with the gateway (for new sessions) + /// Gateway version + /// See Gateway Version /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GatewayReadyEvent - { - /// - /// Gateway version - /// See Gateway Version - /// - [JsonProperty("v")] - public int Version { get; set; } + [JsonProperty("v")] + public int Version { get; set; } - /// - /// Information about the user including email - /// See - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } + /// + /// Information about the user including email + /// See + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } - /// - /// The guilds the user is in - /// - [JsonProperty("guilds")] - [JsonConverter(typeof(HashListConverter))] - public Hash Guilds { get; set; } + /// + /// The guilds the user is in + /// + [JsonProperty("guilds")] + [JsonConverter(typeof(HashListConverter))] + public Hash Guilds { get; set; } - /// - /// Used for resuming connections - /// - [JsonProperty("session_id")] - public string SessionId { get; set; } + /// + /// Used for resuming connections + /// + [JsonProperty("session_id")] + public string SessionId { get; set; } - /// - /// Websocket URL to use when resuming the session - /// - [JsonProperty("resume_gateway_url")] - public string ResumeSessionUrl { get; set; } + /// + /// Websocket URL to use when resuming the session + /// + [JsonProperty("resume_gateway_url")] + public string ResumeSessionUrl { get; set; } - /// - /// The shard information associated with this session, if sent when identifying - /// - [JsonProperty("shard")] - public List Shard { get; set; } + /// + /// The shard information associated with this session, if sent when identifying + /// + [JsonProperty("shard")] + public List Shard { get; set; } - /// - /// Contains id and flags - /// See - /// - [JsonProperty("application")] - public DiscordApplication Application { get; set; } - } -} + /// + /// Contains id and flags + /// See + /// + [JsonProperty("application")] + public DiscordApplication Application { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayResumedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayResumedEvent.cs index e5d78f4a3..6975ca633 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayResumedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GatewayResumedEvent.cs @@ -1,14 +1,13 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Resumed +/// The resumed event is dispatched when a client has sent a resume payload to the gateway (for resuming existing sessions). +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GatewayResumedEvent { - /// - /// Represents Resumed - /// The resumed event is dispatched when a client has sent a resume payload to the gateway (for resuming existing sessions). - /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GatewayResumedEvent - { - } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildEmojisUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildEmojisUpdatedEvent.cs index cd3cfe9f7..3c97c6ce1 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildEmojisUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildEmojisUpdatedEvent.cs @@ -2,25 +2,24 @@ using Oxide.Ext.Discord.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Emojis Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildEmojisUpdatedEvent { /// - /// Represents Guild Emojis Update + /// ID of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildEmojisUpdatedEvent - { - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// List of emojis - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("emojis")] - public Hash Emojis { get; set; } - } -} + /// + /// List of emojis + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("emojis")] + public Hash Emojis { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildIntegrationsUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildIntegrationsUpdatedEvent.cs index b4eea1acf..bd162b86b 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildIntegrationsUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildIntegrationsUpdatedEvent.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Integrations Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildIntegrationsUpdatedEvent { /// - /// Represents Guild Integrations Update + /// ID of the guild whose integrations were updated /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildIntegrationsUpdatedEvent - { - /// - /// ID of the guild whose integrations were updated - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } - } -} + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberAddedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberAddedEvent.cs index 0429de5d6..2b3511e31 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberAddedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberAddedEvent.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Member Add +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildMemberAddedEvent : GuildMember { /// - /// Represents Guild Member Add + /// ID of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildMemberAddedEvent : GuildMember - { - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } - } -} + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberBannedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberBannedEvent.cs index dc7747f5e..8ccb38b81 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberBannedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberBannedEvent.cs @@ -1,24 +1,23 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Ban Add Event +/// Represents Guild Ban Remove Event +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildMemberBannedEvent { /// - /// Represents Guild Ban Add Event - /// Represents Guild Ban Remove Event + /// ID of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildMemberBannedEvent - { - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The banned / unbanned user - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } - } -} + /// + /// The banned / unbanned user + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberRemovedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberRemovedEvent.cs index df8528c04..aa83d8d08 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberRemovedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberRemovedEvent.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Member Remove +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildMemberRemovedEvent { /// - /// Represents Guild Member Remove + /// The id of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildMemberRemovedEvent - { - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The user who was removed - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } - } -} + /// + /// The user who was removed + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberUpdatedEvent.cs index e16d3791e..20ddde256 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMemberUpdatedEvent.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Member Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildMemberUpdatedEvent : GuildMember { /// - /// Represents Guild Member Update + /// The id of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildMemberUpdatedEvent : GuildMember - { - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } - } -} + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMembersChunkEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMembersChunkEvent.cs index 1a7974881..072ae6a3c 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMembersChunkEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildMembersChunkEvent.cs @@ -1,54 +1,53 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Members Chunk +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildMembersChunkEvent { /// - /// Represents Guild Members Chunk + /// The id of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildMembersChunkEvent - { - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// Set of guild members - /// - [JsonProperty("members")] - public List Members { get; set; } + /// + /// Set of guild members + /// + [JsonProperty("members")] + public List Members { get; set; } - /// - /// The chunk index in the expected chunks for this response (0 <= chunk_index < chunk_count) - /// - [JsonProperty("chunk_index")] - public int ChunkIndex { get; set; } + /// + /// The chunk index in the expected chunks for this response (0 <= chunk_index < chunk_count) + /// + [JsonProperty("chunk_index")] + public int ChunkIndex { get; set; } - /// - /// The total number of expected chunks for this response - /// - [JsonProperty("chunk_count")] - public int ChunkCount { get; set; } + /// + /// The total number of expected chunks for this response + /// + [JsonProperty("chunk_count")] + public int ChunkCount { get; set; } - /// - /// If passing an invalid id to REQUEST_GUILD_MEMBERS, it will be returned here - /// - [JsonProperty("not_found")] - public List NotFound { get; set; } + /// + /// If passing an invalid id to REQUEST_GUILD_MEMBERS, it will be returned here + /// + [JsonProperty("not_found")] + public List NotFound { get; set; } - /// - /// If passing true to REQUEST_GUILD_MEMBERS, presences of the returned members will be here - /// - [JsonProperty("presences")] - public List Presences { get; set; } + /// + /// If passing true to REQUEST_GUILD_MEMBERS, presences of the returned members will be here + /// + [JsonProperty("presences")] + public List Presences { get; set; } - /// - /// The nonce used in the Guild Members Request - /// - [JsonProperty("nonce")] - public string Nonce { get; set; } - } -} + /// + /// The nonce used in the Guild Members Request + /// + [JsonProperty("nonce")] + public string Nonce { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleCreatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleCreatedEvent.cs index 173af5c6c..476d1579a 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleCreatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleCreatedEvent.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Role Create +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildRoleCreatedEvent { /// - /// Represents Guild Role Create + /// The id of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildRoleCreatedEvent - { - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The role created - /// - [JsonProperty("role")] - public DiscordRole Role { get; set; } - } -} + /// + /// The role created + /// + [JsonProperty("role")] + public DiscordRole Role { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleDeletedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleDeletedEvent.cs index 7d848cd05..c59b0cf9c 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleDeletedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleDeletedEvent.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Role Delete +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildRoleDeletedEvent { /// - /// Represents Guild Role Delete + /// ID of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildRoleDeletedEvent - { - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// ID of the role - /// - [JsonProperty("role_id")] - public Snowflake RoleId { get; set; } - } -} + /// + /// ID of the role + /// + [JsonProperty("role_id")] + public Snowflake RoleId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleUpdatedEvent.cs index 4b83edb9b..1ac954dfc 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildRoleUpdatedEvent.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Role Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildRoleUpdatedEvent { /// - /// Represents Guild Role Update + /// The id of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildRoleUpdatedEvent - { - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The role updated - /// - [JsonProperty("role")] - public DiscordRole Role { get; set; } - } -} + /// + /// The role updated + /// + [JsonProperty("role")] + public DiscordRole Role { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildScheduleEventUserAddedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildScheduleEventUserAddedEvent.cs index 08cc7c7b0..a2e8ac12b 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildScheduleEventUserAddedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildScheduleEventUserAddedEvent.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Guild Scheduled Event User Add Event Fields +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildScheduleEventUserAddedEvent { /// - /// Represents a Guild Scheduled Event User Add Event Fields + /// ID of the guild scheduled event /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildScheduleEventUserAddedEvent - { - /// - /// ID of the guild scheduled event - /// - [JsonProperty("guild_scheduled_event_id")] - public Snowflake GuildScheduledEventId { get; set; } + [JsonProperty("guild_scheduled_event_id")] + public Snowflake GuildScheduledEventId { get; set; } - /// - /// ID of the user - /// - [JsonProperty("user_id")] - public Snowflake UserId { get; set; } + /// + /// ID of the user + /// + [JsonProperty("user_id")] + public Snowflake UserId { get; set; } - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } - } + /// + /// ID of the guild + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildScheduleEventUserRemovedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildScheduleEventUserRemovedEvent.cs index 477efa53b..9c53054ac 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildScheduleEventUserRemovedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildScheduleEventUserRemovedEvent.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Guild Scheduled Event User Remove Event Fields +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildScheduleEventUserRemovedEvent { /// - /// Represents a Guild Scheduled Event User Remove Event Fields + /// ID of the guild scheduled event /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildScheduleEventUserRemovedEvent - { - /// - /// ID of the guild scheduled event - /// - [JsonProperty("guild_scheduled_event_id")] - public Snowflake GuildScheduledEventId { get; set; } + [JsonProperty("guild_scheduled_event_id")] + public Snowflake GuildScheduledEventId { get; set; } - /// - /// ID of the user - /// - [JsonProperty("user_id")] - public Snowflake UserId { get; set; } + /// + /// ID of the user + /// + [JsonProperty("user_id")] + public Snowflake UserId { get; set; } - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } - } + /// + /// ID of the guild + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildStickersUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildStickersUpdatedEvent.cs index 0a63c940f..7833012be 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/GuildStickersUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/GuildStickersUpdatedEvent.cs @@ -2,25 +2,24 @@ using Oxide.Ext.Discord.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Stickers Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildStickersUpdatedEvent { /// - /// Represents Guild Stickers Update + /// ID of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildStickersUpdatedEvent - { - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// List of emojis - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("stickers")] - public Hash Stickers { get; set; } - } + /// + /// List of emojis + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("stickers")] + public Hash Stickers { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationCreatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationCreatedEvent.cs index 45be6423f..37125820e 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationCreatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationCreatedEvent.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Integration Create Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class IntegrationCreatedEvent : Integration { /// - /// Represents a Integration Create Structure + /// Guild Id the Integration was created in /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class IntegrationCreatedEvent : Integration - { - /// - /// Guild Id the Integration was created in - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } - } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationDeletedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationDeletedEvent.cs index 84d0065f0..f2f6693af 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationDeletedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationDeletedEvent.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Integration Delete Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class IntegrationDeletedEvent { /// - /// Represents a Integration Delete Structure + /// ID of the integration /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class IntegrationDeletedEvent - { - /// - /// ID of the integration - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Guild ID the integration was in - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + /// + /// Guild ID the integration was in + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// Application ID of the integration - /// - [JsonProperty("application_id")] - public Snowflake ApplicationId { get; set; } - } + /// + /// Application ID of the integration + /// + [JsonProperty("application_id")] + public Snowflake ApplicationId { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationUpdatedEvent.cs index b9c49e930..292d9d045 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/IntegrationUpdatedEvent.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Integration Update Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class IntegrationUpdatedEvent : Integration { /// - /// Represents a Integration Update Structure + /// Guild ID the integration was updated In /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class IntegrationUpdatedEvent : Integration - { - /// - /// Guild ID the integration was updated In - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } - } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/InviteCreatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/InviteCreatedEvent.cs index 1c1defddd..05e2da384 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/InviteCreatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/InviteCreatedEvent.cs @@ -1,78 +1,77 @@ using System; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Invite Create +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class InviteCreatedEvent { /// - /// Represents Invite Create + /// The channel the invite is for /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InviteCreatedEvent - { - /// - /// The channel the invite is for - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The unique invite code - /// - [JsonProperty("code")] - public string Code { get; set; } + /// + /// The unique invite code + /// + [JsonProperty("code")] + public string Code { get; set; } - /// - /// The time at which the invite was created - /// - [JsonProperty("created_at")] - public DateTime CreatedAt { get; set; } + /// + /// The time at which the invite was created + /// + [JsonProperty("created_at")] + public DateTime CreatedAt { get; set; } - /// - /// The guild of the invite - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// The guild of the invite + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// The user that created the invite - /// - [JsonProperty("inviter")] - public DiscordUser Inviter { get; set; } + /// + /// The user that created the invite + /// + [JsonProperty("inviter")] + public DiscordUser Inviter { get; set; } - /// - /// How long the invite is valid for (in seconds) - /// - [JsonProperty("max_age")] - public int MaxAge { get; set; } + /// + /// How long the invite is valid for (in seconds) + /// + [JsonProperty("max_age")] + public int MaxAge { get; set; } - /// - /// The maximum number of times the invite can be use - /// - [JsonProperty("max_uses")] - public int MaxUses { get; set; } + /// + /// The maximum number of times the invite can be use + /// + [JsonProperty("max_uses")] + public int MaxUses { get; set; } - /// - /// The target user for this invite - /// - [JsonProperty("target_user")] - public DiscordUser TargetUser { get; set; } + /// + /// The target user for this invite + /// + [JsonProperty("target_user")] + public DiscordUser TargetUser { get; set; } - /// - /// The type of user target for this invite - /// - [JsonProperty("target_user")] - public TargetUserType TargetUserType { get; set; } + /// + /// The type of user target for this invite + /// + [JsonProperty("target_user")] + public TargetUserType TargetUserType { get; set; } - /// - /// Whether or not the invite is temporary (invited users will be kicked on disconnect unless they're assigned a role) - /// - [JsonProperty("temporary")] - public bool? Temporary { get; set; } + /// + /// Whether or not the invite is temporary (invited users will be kicked on disconnect unless they're assigned a role) + /// + [JsonProperty("temporary")] + public bool? Temporary { get; set; } - /// - /// How many times the invite has been used (always will be 0) - /// - [JsonProperty("uses")] - public int? Uses { get; set; } - } -} + /// + /// How many times the invite has been used (always will be 0) + /// + [JsonProperty("uses")] + public int? Uses { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/InviteDeletedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/InviteDeletedEvent.cs index 6d49c2d96..48148aed0 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/InviteDeletedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/InviteDeletedEvent.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Invite Delete +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class InviteDeletedEvent { /// - /// Represents Invite Delete + /// The channel of the invite /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InviteDeletedEvent - { - /// - /// The channel of the invite - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The guild of the invite - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// The guild of the invite + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// The unique invite code - /// - [JsonProperty("code")] - public string Code { get; set; } - } -} + /// + /// The unique invite code + /// + [JsonProperty("code")] + public string Code { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageBulkDeletedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageBulkDeletedEvent.cs index c1b0b8254..5f8bcfd38 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageBulkDeletedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageBulkDeletedEvent.cs @@ -1,30 +1,29 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Delete Bulk +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageBulkDeletedEvent { /// - /// Represents Message Delete Bulk + /// The ids of the messages /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageBulkDeletedEvent - { - /// - /// The ids of the messages - /// - [JsonProperty("ids")] - public List Ids { get; set; } + [JsonProperty("ids")] + public List Ids { get; set; } - /// - /// The id of the channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + /// + /// The id of the channel + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } - } -} + /// + /// The id of the guild + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageDeletedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageDeletedEvent.cs index 7b8bd7f68..7f438d48e 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageDeletedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageDeletedEvent.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Delete +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageDeletedEvent { /// - /// Represents Message Delete + /// The id of the message /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageDeletedEvent - { - /// - /// The id of the message - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The id of the channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + /// + /// The id of the channel + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } - } -} + /// + /// The id of the guild + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/MessagePollVoteAddedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/MessagePollVoteAddedEvent.cs new file mode 100644 index 000000000..998f24200 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/MessagePollVoteAddedEvent.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Poll Vote Added Event +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessagePollVoteAddedEvent +{ + /// + /// ID of the user + /// + [JsonProperty("user_id")] + public Snowflake UserId { get; set; } + + /// + /// The id of the channel + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } + + /// + /// ID of the message + /// + [JsonProperty("message_id")] + public Snowflake MessageId { get; set; } + + /// + /// ID of the guild + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } + + /// + /// ID of the answer + /// + [JsonProperty("answer_id")] + public int AnswerId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/MessagePollVoteRemovedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/MessagePollVoteRemovedEvent.cs new file mode 100644 index 000000000..36acb7596 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/MessagePollVoteRemovedEvent.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Poll Vote Removed Event +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessagePollVoteRemovedEvent +{ + /// + /// ID of the user + /// + [JsonProperty("user_id")] + public Snowflake UserId { get; set; } + + /// + /// The id of the channel + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } + + /// + /// ID of the message + /// + [JsonProperty("message_id")] + public Snowflake MessageId { get; set; } + + /// + /// ID of the guild + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } + + /// + /// ID of the answer + /// + [JsonProperty("answer_id")] + public int AnswerId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionAddedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionAddedEvent.cs index adfdc0899..2388801dd 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionAddedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionAddedEvent.cs @@ -1,53 +1,71 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Reaction Add +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageReactionAddedEvent { /// - /// Represents Message Reaction Add + /// The id of the user /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageReactionAddedEvent - { - /// - /// The id of the user - /// - [JsonProperty("user_id")] - public Snowflake UserId { get; set; } + [JsonProperty("user_id")] + public Snowflake UserId { get; set; } - /// - /// The id of the channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + /// + /// The id of the channel + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The id of the message - /// - [JsonProperty("message_id")] - public Snowflake MessageId { get; set; } + /// + /// The id of the message + /// + [JsonProperty("message_id")] + public Snowflake MessageId { get; set; } - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// The id of the guild + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// The member who reacted if this happened in a guild - /// - [JsonProperty("member")] - public GuildMember Member { get; set; } + /// + /// The member who reacted if this happened in a guild + /// + [JsonProperty("member")] + public GuildMember Member { get; set; } - /// - /// The emoji used to react - /// - [JsonProperty("emoji")] - public DiscordEmoji Emoji { get; set; } + /// + /// The emoji used to react + /// + [JsonProperty("emoji")] + public DiscordEmoji Emoji { get; set; } - /// - /// ID of the user who authored the message which was reacted to - /// - [JsonProperty("message_author_id")] - public Snowflake? MessageAuthorId { get; set; } - } -} + /// + /// ID of the user who authored the message which was reacted to + /// + [JsonProperty("message_author_id")] + public Snowflake? MessageAuthorId { get; set; } + + /// + /// True if this is a super-reaction + /// + [JsonProperty("burst")] + public bool Burst { get; set; } + + /// + /// Colors used for super-reaction animation + /// + [JsonProperty("burst_colors")] + public List BurstColors { get; set; } + + /// + /// The type of the reaction + /// + [JsonProperty("type")] + public ReactionType Type { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedAllEmojiEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedAllEmojiEvent.cs index 382f3a381..c65723778 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedAllEmojiEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedAllEmojiEvent.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Reaction Remove All +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageReactionRemovedAllEmojiEvent : MessageReactionRemovedAllEvent { /// - /// Represents Message Reaction Remove All + /// Emoji that was removed from the message /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageReactionRemovedAllEmojiEvent : MessageReactionRemovedAllEvent - { - /// - /// Emoji that was removed from the message - /// - public DiscordEmoji Emoji { get; set; } - } -} + public DiscordEmoji Emoji { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedAllEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedAllEvent.cs index e9c8f34f8..05bb3b38e 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedAllEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedAllEvent.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Reaction Remove All +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageReactionRemovedAllEvent { /// - /// Represents Message Reaction Remove All + /// The id of the channel /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageReactionRemovedAllEvent - { - /// - /// The id of the channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The id of the message - /// - [JsonProperty("message_id")] - public Snowflake MessageId { get; set; } + /// + /// The id of the message + /// + [JsonProperty("message_id")] + public Snowflake MessageId { get; set; } - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } - } -} + /// + /// The id of the guild + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedEvent.cs index d5467271b..1750c1833 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/MessageReactionRemovedEvent.cs @@ -1,41 +1,52 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Reaction Remove +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageReactionRemovedEvent { /// - /// Represents Message Reaction Remove + /// The id of the user /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageReactionRemovedEvent - { - /// - /// The id of the user - /// - [JsonProperty("user_id")] - public Snowflake UserId { get; set; } + [JsonProperty("user_id")] + public Snowflake UserId { get; set; } - /// - /// The id of the channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + /// + /// The id of the channel + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The id of the message - /// - [JsonProperty("message_id")] - public Snowflake MessageId { get; set; } + /// + /// The id of the message + /// + [JsonProperty("message_id")] + public Snowflake MessageId { get; set; } - /// - /// The id of the guild - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// The id of the guild + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// The emoji removed - /// - [JsonProperty("emoji")] - public DiscordEmoji Emoji { get; set; } - } + /// + /// Emoji used to react + /// + [JsonProperty("emoji")] + public DiscordEmoji Emoji { get; set; } + + /// + /// True if this is a super-reaction + /// + [JsonProperty("burst")] + public bool Burst { get; set; } + + /// + /// The type of the reaction + /// + [JsonProperty("type")] + public ReactionType Type { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/PresenceUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/PresenceUpdatedEvent.cs index e595a56e0..f3ffeb63b 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/PresenceUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/PresenceUpdatedEvent.cs @@ -1,42 +1,41 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Presence Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class PresenceUpdatedEvent { /// - /// Represents Presence Update + /// The user presence is being updated for /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class PresenceUpdatedEvent - { - /// - /// The user presence is being updated for - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } + [JsonProperty("user")] + public DiscordUser User { get; set; } - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + /// + /// ID of the guild + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// Users status - /// - [JsonProperty("status")] - public UserStatusType Status { get; set; } + /// + /// Users status + /// + [JsonProperty("status")] + public UserStatusType Status { get; set; } - /// - /// User's current activities - /// - [JsonProperty("activities")] - public List Activities { get; set; } + /// + /// User's current activities + /// + [JsonProperty("activities")] + public List Activities { get; set; } - /// - /// User's platform-dependent status - /// - [JsonProperty("client_status")] - public ClientStatus ClientStatus { get; set; } - } -} + /// + /// User's platform-dependent status + /// + [JsonProperty("client_status")] + public ClientStatus ClientStatus { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadListSyncEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadListSyncEvent.cs index 7e71bd16a..4f3bb7568 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadListSyncEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadListSyncEvent.cs @@ -3,37 +3,36 @@ using Oxide.Ext.Discord.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Thread List Sync +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ThreadListSyncEvent { /// - /// Represents Thread List Sync + /// The ID of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ThreadListSyncEvent - { - /// - /// The ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The parent channel ids whose threads are being synced. If omitted, then threads were synced for the entire guild. This array may contain channel_ids that have no active threads as well, so you know to clear that data. - /// - [JsonProperty("channel_ids")] - public List ChannelIds { get; set; } + /// + /// The parent channel ids whose threads are being synced. If omitted, then threads were synced for the entire guild. This array may contain channel_ids that have no active threads as well, so you know to clear that data. + /// + [JsonProperty("channel_ids")] + public List ChannelIds { get; set; } - /// - /// All active threads in the given channels that the current user can access - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("threads")] - public Hash Threads { get; set; } + /// + /// All active threads in the given channels that the current user can access + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("threads")] + public Hash Threads { get; set; } - /// - /// All thread member objects from the synced threads for the current user, indicating which threads the current user has been added to - /// - [JsonProperty("members")] - public List Members { get; set; } - } + /// + /// All thread member objects from the synced threads for the current user, indicating which threads the current user has been added to + /// + [JsonProperty("members")] + public List Members { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadMemberUpdateEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadMemberUpdateEvent.cs index 3a340bde7..1f4fadcd5 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadMemberUpdateEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadMemberUpdateEvent.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Thread Member Update Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ThreadMemberUpdateEvent : ThreadMember { /// - /// Represents Thread Member Update Structure + /// The ID of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ThreadMemberUpdateEvent : ThreadMember - { - /// - /// The ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } - } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadMembersUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadMembersUpdatedEvent.cs index 495d0434e..3b895e265 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadMembersUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/ThreadMembersUpdatedEvent.cs @@ -1,42 +1,41 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Thread Members Update Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ThreadMembersUpdatedEvent { /// - /// Represents Thread Members Update Structure + /// The id of the thread /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ThreadMembersUpdatedEvent - { - /// - /// The id of the thread - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + /// + /// The ID of the guild + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The approximate number of members in the thread, capped at 50 - /// - [JsonProperty("member_count")] - public int MemberCount { get; set; } + /// + /// The approximate number of members in the thread, capped at 50 + /// + [JsonProperty("member_count")] + public int MemberCount { get; set; } - /// - /// The users who were added to the thread - /// - [JsonProperty("added_members")] - public List AddedMembers { get; set; } + /// + /// The users who were added to the thread + /// + [JsonProperty("added_members")] + public List AddedMembers { get; set; } - /// - /// The id of the users who were removed from the thread - /// - [JsonProperty("removed_member_ids")] - public List RemovedMemberIds { get; set; } - } + /// + /// The id of the users who were removed from the thread + /// + [JsonProperty("removed_member_ids")] + public List RemovedMemberIds { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/TypingStartedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/TypingStartedEvent.cs index b426f6264..183bfde2d 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/TypingStartedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/TypingStartedEvent.cs @@ -1,41 +1,40 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Typing Start +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class TypingStartedEvent { /// - /// Represents Typing Start + /// ID of the channel /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class TypingStartedEvent - { - /// - /// ID of the channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// ID of the guild + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// ID of the user - /// - [JsonProperty("user_id")] - public Snowflake UserId { get; set; } + /// + /// ID of the user + /// + [JsonProperty("user_id")] + public Snowflake UserId { get; set; } - /// - /// Unix time (in seconds) of when the user started typing - /// - [JsonProperty("timestamp")] - public int? Timestamp { get; set; } + /// + /// Unix time (in seconds) of when the user started typing + /// + [JsonProperty("timestamp")] + public int? Timestamp { get; set; } - /// - /// The member who started typing if this happened in a guild - /// - [JsonProperty("member")] - public GuildMember Member { get; set; } - } -} + /// + /// The member who started typing if this happened in a guild + /// + [JsonProperty("member")] + public GuildMember Member { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/VoiceServerUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/VoiceServerUpdatedEvent.cs index 3af1435ce..94dfc4b0d 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/VoiceServerUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/VoiceServerUpdatedEvent.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Voice Server Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class VoiceServerUpdatedEvent { /// - /// Represents Voice Server Update + /// Voice connection token /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class VoiceServerUpdatedEvent - { - /// - /// Voice connection token - /// - [JsonProperty("token")] - public string Token { get; set; } + [JsonProperty("token")] + public string Token { get; set; } - /// - /// The guild this voice server update is for - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + /// + /// The guild this voice server update is for + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The voice server host - /// - [JsonProperty("endpoint")] - public string Endpoint { get; set; } - } -} + /// + /// The voice server host + /// + [JsonProperty("endpoint")] + public string Endpoint { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Events/WebhooksUpdatedEvent.cs b/Oxide.Ext.Discord/Entities/Gateway/Events/WebhooksUpdatedEvent.cs index 28191af51..5a314d0a6 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Events/WebhooksUpdatedEvent.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Events/WebhooksUpdatedEvent.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Webhooks Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class WebhooksUpdatedEvent { /// - /// Represents Webhooks Update + /// ID of the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class WebhooksUpdatedEvent - { - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// ID of the channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } - } -} + /// + /// ID of the channel + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/Gateway.cs b/Oxide.Ext.Discord/Entities/Gateway/Gateway.cs index f6f43bea6..c67cace77 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/Gateway.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/Gateway.cs @@ -6,51 +6,50 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Discord Gatway Connection Url +/// See Get Gateway +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +internal class Gateway { /// - /// Represents Discord Gatway Connection Url - /// See Get Gateway + /// Gatway URL to use /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - internal class Gateway - { - /// - /// Gatway URL to use - /// - [JsonProperty("url")] - public string Url { get; set; } + [JsonProperty("url")] + public string Url { get; set; } - /// - /// Saved Gateway URL - /// Example: wss://gateway.discord.gg/?v=8&encoding=json - /// - public static string WebsocketUrl { get; private set; } + /// + /// Saved Gateway URL + /// Example: wss://gateway.discord.gg/?v=8&encoding=json + /// + public static string WebsocketUrl { get; private set; } - public static DateTime LastUpdate { get; private set; } + public static DateTime LastUpdate { get; private set; } - internal static readonly List Shard = new List {0, 1}; - internal static readonly ConnectionProperties Properties = new ConnectionProperties(); + internal static readonly List Shard = [0, 1]; + internal static readonly ConnectionProperties Properties = new(); - /// - /// Returns an object with a single valid WSS URL, which the client can use for Connecting. - /// Clients should cache this value and only call this endpoint to retrieve a new URL if they are unable to properly establish a connection using the cached version of the URL. - /// See Get Gateway - /// - /// Client to use - private static IPromise GetGateway(BotClient client) - { - return client.Rest.Get(client.GetFirstClient(),"gateway"); - } + /// + /// Returns an object with a single valid WSS URL, which the client can use for Connecting. + /// Clients should cache this value and only call this endpoint to retrieve a new URL if they are unable to properly establish a connection using the cached version of the URL. + /// See Get Gateway + /// + /// Client to use + private static IPromise GetGateway(BotClient client) + { + return client.Rest.Get(client.GetFirstClient(),"gateway"); + } - public static IPromise UpdateGatewayUrl(BotClient client) + public static IPromise UpdateGatewayUrl(BotClient client) + { + return GetGateway(client).Then(gateway => { - return GetGateway(client).Then(gateway => - { - WebsocketUrl = $"{gateway.Url}/?{DiscordEndpoints.Websocket.WebsocketArgs}"; - LastUpdate = DateTime.UtcNow; - client.Logger.Debug($"{nameof(Gateway)}.{nameof(UpdateGatewayUrl)} Updated Gateway Url: {{0}}", WebsocketUrl); - }); - } + WebsocketUrl = $"{gateway.Url}/?{DiscordEndpoints.Websocket.WebsocketArgs}"; + LastUpdate = DateTime.UtcNow; + client.Logger.Debug($"{nameof(Gateway)}.{nameof(UpdateGatewayUrl)} Updated Gateway Url: {{0}}", WebsocketUrl); + }); } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Gateway/GatewayIntents.cs b/Oxide.Ext.Discord/Entities/Gateway/GatewayIntents.cs index 5751b345d..f0037fb4e 100644 --- a/Oxide.Ext.Discord/Entities/Gateway/GatewayIntents.cs +++ b/Oxide.Ext.Discord/Entities/Gateway/GatewayIntents.cs @@ -1,158 +1,157 @@ using System; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Gateway Intents +/// These are used to indicate which events your bot / application wants to listen to / have access to +/// +[Flags] +public enum GatewayIntents { /// - /// Represents Gateway Intents - /// These are used to indicate which events your bot / application wants to listen to / have access to - /// - [Flags] - public enum GatewayIntents - { - /// - /// Represents No Intents - /// - None = 0, - - /// - /// - GUILD_CREATE - /// - GUILD_UPDATE - /// - GUILD_DELETE - /// - GUILD_ROLE_CREATE - /// - GUILD_ROLE_UPDATE - /// - GUILD_ROLE_DELETE - /// - CHANNEL_CREATE - /// - CHANNEL_UPDATE - /// - CHANNEL_DELETE - /// - CHANNEL_PINS_UPDATE - /// - THREAD_CREATE - /// - THREAD_UPDATE - /// - THREAD_DELETE - /// - THREAD_LIST_SYNC - /// - THREAD_MEMBER_UPDATE - /// - THREAD_MEMBERS_UPDATE - /// - STAGE_INSTANCE_CREATE - /// - STAGE_INSTANCE_UPDATE - /// - STAGE_INSTANCE_DELETE - /// - Guilds = 1 << 0, - - /// - /// - GUILD_MEMBER_ADD - /// - GUILD_MEMBER_UPDATE - /// - GUILD_MEMBER_REMOVE - /// - THREAD_MEMBERS_UPDATE - /// - GuildMembers = 1 << 1, - - /// - /// - GUILD_AUDIT_LOG_ENTRY_CREATE - /// - GUILD_BAN_ADD - /// - GUILD_BAN_REMOVE - /// - GuildModeration = 1 << 2, - - /// - /// - GUILD_EMOJIS_UPDATE - /// - GUILD_STICKERS_UPDATE - /// - GuildEmojisAndStickers = 1 << 3, - - /// - /// - GUILD_INTEGRATIONS_UPDATE - /// - INTEGRATION_CREATE - /// - INTEGRATION_UPDATE - /// - INTEGRATION_DELETE - /// - GuildIntegrations = 1 << 4, - - /// - /// - WEBHOOKS_UPDATE - /// - GuildWebhooks = 1 << 5, - - /// - /// - INVITE_CREATE - /// - INVITE_DELETE - /// - GuildInvites = 1 << 6, - - /// - /// - VOICE_STATE_UPDATE - /// - GuildVoiceStates = 1 << 7, - - /// - /// - PRESENCE_UPDATE - /// - GuildPresences = 1 << 8, - - /// - /// - MESSAGE_CREATE - /// - MESSAGE_UPDATE - /// - MESSAGE_DELETE - /// - MESSAGE_DELETE_BULK - /// - GuildMessages = 1 << 9, - - /// - /// - MESSAGE_REACTION_ADD - /// - MESSAGE_REACTION_REMOVE - /// - MESSAGE_REACTION_REMOVE_ALL - /// - MESSAGE_REACTION_REMOVE_EMOJI - /// - GuildMessageReactions = 1 << 10, - - /// - /// - TYPING_START - /// - GuildMessageTyping = 1 << 11, - - /// - /// - MESSAGE_CREATE - /// - MESSAGE_UPDATE - /// - MESSAGE_DELETE - /// - CHANNEL_PINS_UPDATE - /// - DirectMessages = 1 << 12, - - /// - /// - MESSAGE_REACTION_ADD - /// - MESSAGE_REACTION_REMOVE - /// - MESSAGE_REACTION_REMOVE_ALL - /// - MESSAGE_REACTION_REMOVE_EMOJI - /// - DirectMessageReactions = 1 << 13, - - /// - /// - TYPING_START - /// - DirectMessageTyping = 1 << 14, - - /// - /// - Guild Message.Content - /// - MessageContent = 1 << 15, - - /// - /// - GUILD_SCHEDULED_EVENT_CREATE - /// - GUILD_SCHEDULED_EVENT_UPDATE - /// - GUILD_SCHEDULED_EVENT_DELETE - /// - GUILD_SCHEDULED_EVENT_USER_ADD - /// - GUILD_SCHEDULED_EVENT_USER_REMOVE - /// - GuildScheduledEvents = 1 << 16, - - /// - /// - AUTO_MODERATION_RULE_CREATE - /// - AUTO_MODERATION_RULE_UPDATE - /// - AUTO_MODERATION_RULE_DELETE - /// - AutoModerationConfiguration = 1 << 20, - - /// - /// - AUTO_MODERATION_ACTION_EXECUTION - /// - AutoModerationExecution = 1 << 21, - } + /// Represents No Intents + /// + None = 0, + + /// + /// - GUILD_CREATE + /// - GUILD_UPDATE + /// - GUILD_DELETE + /// - GUILD_ROLE_CREATE + /// - GUILD_ROLE_UPDATE + /// - GUILD_ROLE_DELETE + /// - CHANNEL_CREATE + /// - CHANNEL_UPDATE + /// - CHANNEL_DELETE + /// - CHANNEL_PINS_UPDATE + /// - THREAD_CREATE + /// - THREAD_UPDATE + /// - THREAD_DELETE + /// - THREAD_LIST_SYNC + /// - THREAD_MEMBER_UPDATE + /// - THREAD_MEMBERS_UPDATE + /// - STAGE_INSTANCE_CREATE + /// - STAGE_INSTANCE_UPDATE + /// - STAGE_INSTANCE_DELETE + /// + Guilds = 1 << 0, + + /// + /// - GUILD_MEMBER_ADD + /// - GUILD_MEMBER_UPDATE + /// - GUILD_MEMBER_REMOVE + /// - THREAD_MEMBERS_UPDATE + /// + GuildMembers = 1 << 1, + + /// + /// - GUILD_AUDIT_LOG_ENTRY_CREATE + /// - GUILD_BAN_ADD + /// - GUILD_BAN_REMOVE + /// + GuildModeration = 1 << 2, + + /// + /// - GUILD_EMOJIS_UPDATE + /// - GUILD_STICKERS_UPDATE + /// + GuildEmojisAndStickers = 1 << 3, + + /// + /// - GUILD_INTEGRATIONS_UPDATE + /// - INTEGRATION_CREATE + /// - INTEGRATION_UPDATE + /// - INTEGRATION_DELETE + /// + GuildIntegrations = 1 << 4, + + /// + /// - WEBHOOKS_UPDATE + /// + GuildWebhooks = 1 << 5, + + /// + /// - INVITE_CREATE + /// - INVITE_DELETE + /// + GuildInvites = 1 << 6, + + /// + /// - VOICE_STATE_UPDATE + /// + GuildVoiceStates = 1 << 7, + + /// + /// - PRESENCE_UPDATE + /// + GuildPresences = 1 << 8, + + /// + /// - MESSAGE_CREATE + /// - MESSAGE_UPDATE + /// - MESSAGE_DELETE + /// - MESSAGE_DELETE_BULK + /// + GuildMessages = 1 << 9, + + /// + /// - MESSAGE_REACTION_ADD + /// - MESSAGE_REACTION_REMOVE + /// - MESSAGE_REACTION_REMOVE_ALL + /// - MESSAGE_REACTION_REMOVE_EMOJI + /// + GuildMessageReactions = 1 << 10, + + /// + /// - TYPING_START + /// + GuildMessageTyping = 1 << 11, + + /// + /// - MESSAGE_CREATE + /// - MESSAGE_UPDATE + /// - MESSAGE_DELETE + /// - CHANNEL_PINS_UPDATE + /// + DirectMessages = 1 << 12, + + /// + /// - MESSAGE_REACTION_ADD + /// - MESSAGE_REACTION_REMOVE + /// - MESSAGE_REACTION_REMOVE_ALL + /// - MESSAGE_REACTION_REMOVE_EMOJI + /// + DirectMessageReactions = 1 << 13, + + /// + /// - TYPING_START + /// + DirectMessageTyping = 1 << 14, + + /// + /// - Guild Message.Content + /// + MessageContent = 1 << 15, + + /// + /// - GUILD_SCHEDULED_EVENT_CREATE + /// - GUILD_SCHEDULED_EVENT_UPDATE + /// - GUILD_SCHEDULED_EVENT_DELETE + /// - GUILD_SCHEDULED_EVENT_USER_ADD + /// - GUILD_SCHEDULED_EVENT_USER_REMOVE + /// + GuildScheduledEvents = 1 << 16, + + /// + /// - AUTO_MODERATION_RULE_CREATE + /// - AUTO_MODERATION_RULE_UPDATE + /// - AUTO_MODERATION_RULE_DELETE + /// + AutoModerationConfiguration = 1 << 20, + + /// + /// - AUTO_MODERATION_ACTION_EXECUTION + /// + AutoModerationExecution = 1 << 21, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/DefaultNotificationLevel.cs b/Oxide.Ext.Discord/Entities/Guilds/DefaultNotificationLevel.cs index 108316856..b939d35cc 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/DefaultNotificationLevel.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/DefaultNotificationLevel.cs @@ -1,22 +1,21 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Default Message Notification Level +/// +public enum DefaultNotificationLevel : byte { /// - /// Represents Default Message Notification Level + /// Notify for all guild messages /// - public enum DefaultNotificationLevel : byte - { - /// - /// Notify for all guild messages - /// - [DiscordEnum("ALL_MESSAGES")] - AllMessages = 0, + [DiscordEnum("ALL_MESSAGES")] + AllMessages = 0, - /// - /// Notify for only mentions - /// - [DiscordEnum("ONLY_MENTIONS")] - OnlyMentions = 1 - } + /// + /// Notify for only mentions + /// + [DiscordEnum("ONLY_MENTIONS")] + OnlyMentions = 1 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/DiscordGuild.cs b/Oxide.Ext.Discord/Entities/Guilds/DiscordGuild.cs index cc646760b..2699a4198 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/DiscordGuild.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/DiscordGuild.cs @@ -8,1443 +8,1445 @@ using Oxide.Ext.Discord.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordGuild : ISnowflakeEntity { + #region Discord Fields /// - /// Represents Guild Structure + /// Guild id /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordGuild : ISnowflakeEntity - { - #region Discord Fields - /// - /// Guild id - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Name of the guild (2-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the guild (2-100 characters) + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Base64 128x128 image for the guild icon - /// - [JsonProperty("icon")] - public string Icon { get; set; } + /// + /// Base64 128x128 image for the guild icon + /// + [JsonProperty("icon")] + public string Icon { get; set; } - /// - /// Icon hash - /// - [JsonProperty("icon_Hash")] - public string IconHash { get; set; } + /// + /// Icon hash + /// + [JsonProperty("icon_Hash")] + public string IconHash { get; set; } - /// - /// Splash hash - /// - [JsonProperty("splash")] - public string Splash { get; set; } - - /// - /// Discovery splash hash - /// Only present for guilds with the "DISCOVERABLE" feature - /// - [JsonProperty("discovery_splash")] - public string DiscoverySplash { get; set; } + /// + /// Splash hash + /// + [JsonProperty("splash")] + public string Splash { get; set; } + + /// + /// Discovery splash hash + /// Only present for guilds with the "DISCOVERABLE" feature + /// + [JsonProperty("discovery_splash")] + public string DiscoverySplash { get; set; } - /// - /// True if the user is the owner of the guild - /// - [JsonProperty("owner")] - public bool? Owner { get; set; } + /// + /// True if the user is the owner of the guild + /// + [JsonProperty("owner")] + public bool? Owner { get; set; } - /// - /// ID of owner - /// - [JsonProperty("owner_id")] - public Snowflake OwnerId { get; set; } - - /// - /// Total permissions for the user in the guild (excludes overrides) - /// - [JsonProperty("permissions")] - public string Permissions { get; set; } - - /// - /// ID of afk channel - /// - [JsonProperty("afk_channel_id")] - public Snowflake? AfkChannelId { get; set; } + /// + /// ID of owner + /// + [JsonProperty("owner_id")] + public Snowflake OwnerId { get; set; } + + /// + /// Total permissions for the user in the guild (excludes overrides) + /// + [JsonProperty("permissions")] + public string Permissions { get; set; } + + /// + /// ID of afk channel + /// + [JsonProperty("afk_channel_id")] + public Snowflake? AfkChannelId { get; set; } - /// - /// Afk timeout in seconds - /// - [JsonProperty("afk_timeout")] - public int? AfkTimeout { get; set; } + /// + /// Afk timeout in seconds + /// + [JsonProperty("afk_timeout")] + public int? AfkTimeout { get; set; } - /// - /// True if the server widget is enabled - /// - [JsonProperty("widget_enabled")] - public bool? WidgetEnabled { get; set; } + /// + /// True if the server widget is enabled + /// + [JsonProperty("widget_enabled")] + public bool? WidgetEnabled { get; set; } - /// - /// The channel id that the widget will generate an invite to, or null if set to no invite - /// - [JsonProperty("widget_channel_id")] - public Snowflake? WidgetChannelId { get; set; } + /// + /// The channel id that the widget will generate an invite to, or null if set to no invite + /// + [JsonProperty("widget_channel_id")] + public Snowflake? WidgetChannelId { get; set; } - /// - /// Verification level - /// - [JsonProperty("verification_level")] - public GuildVerificationLevel? VerificationLevel { get; set; } + /// + /// Verification level + /// + [JsonProperty("verification_level")] + public GuildVerificationLevel? VerificationLevel { get; set; } - /// - /// Default message notification level - /// - [JsonProperty("default_message_notifications")] - public DefaultNotificationLevel? DefaultMessageNotifications { get; set; } + /// + /// Default message notification level + /// + [JsonProperty("default_message_notifications")] + public DefaultNotificationLevel? DefaultMessageNotifications { get; set; } - /// - /// Explicit content filter level - /// - [JsonProperty("explicit_content_filter")] - public ExplicitContentFilterLevel? ExplicitContentFilter { get; set; } - - /// - /// Roles in the guild - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("roles")] - public Hash Roles { get; set; } - - /// - /// Custom guild emojis - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("emojis")] - - public Hash Emojis { get; set; } - - /// - /// Enabled guild features - /// See - /// - [JsonProperty("features")] - public List Features { get; set; } + /// + /// Explicit content filter level + /// + [JsonProperty("explicit_content_filter")] + public ExplicitContentFilterLevel? ExplicitContentFilter { get; set; } + + /// + /// Roles in the guild + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("roles")] + public Hash Roles { get; set; } + + /// + /// Custom guild emojis + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("emojis")] + + public Hash Emojis { get; set; } + + /// + /// Enabled guild features + /// See + /// + [JsonProperty("features")] + public List Features { get; set; } - /// - /// Required MFA level for the guild - /// See - /// - [JsonProperty("mfa_level")] - public GuildMfaLevel? MfaLevel { get; set; } + /// + /// Required MFA level for the guild + /// See + /// + [JsonProperty("mfa_level")] + public GuildMfaLevel? MfaLevel { get; set; } - /// - /// Application id of the guild creator if it is bot-created - /// - [JsonProperty("application_id")] - public Snowflake? ApplicationId { get; set; } + /// + /// Application id of the guild creator if it is bot-created + /// + [JsonProperty("application_id")] + public Snowflake? ApplicationId { get; set; } - /// - /// The id of the channel where guild notices such as welcome messages and boost events are posted - /// - [JsonProperty("system_channel_id")] - public Snowflake? SystemChannelId { get; set; } + /// + /// The id of the channel where guild notices such as welcome messages and boost events are posted + /// + [JsonProperty("system_channel_id")] + public Snowflake? SystemChannelId { get; set; } - /// - /// System channel flags - /// See - /// - [JsonProperty("system_channel_flags")] - public SystemChannelFlags SystemChannelFlags { get; set; } - - /// - /// The id of the channel where Community guilds can display rules and/or guidelines - /// - [JsonProperty("rules_channel_id")] - public Snowflake? RulesChannelId { get; set; } + /// + /// System channel flags + /// See + /// + [JsonProperty("system_channel_flags")] + public SystemChannelFlags SystemChannelFlags { get; set; } + + /// + /// The id of the channel where Community guilds can display rules and/or guidelines + /// + [JsonProperty("rules_channel_id")] + public Snowflake? RulesChannelId { get; set; } - /// - /// When this guild was joined at - /// - [JsonProperty("joined_at")] - public DateTime? JoinedAt { get; set; } + /// + /// When this guild was joined at + /// + [JsonProperty("joined_at")] + public DateTime? JoinedAt { get; set; } - /// - /// True if this is considered a large guild - /// - [JsonProperty("large")] - public bool? Large { get; set; } + /// + /// True if this is considered a large guild + /// + [JsonProperty("large")] + public bool? Large { get; set; } - /// - /// True if this guild is unavailable due to an outage - /// - [JsonProperty("unavailable")] - public bool? Unavailable { get; set; } + /// + /// True if this guild is unavailable due to an outage + /// + [JsonProperty("unavailable")] + public bool? Unavailable { get; set; } - /// - /// Total number of members in this guild - /// - [JsonProperty("member_count")] - public int? MemberCount { get; set; } - - /// - /// States of members currently in voice channels; lacks the guild_id key - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("voice_states")] - public Hash VoiceStates { get; set; } - - /// - /// Users in the guild - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("members")] - public Hash Members { get; set; } - - /// - /// Channels in the guild - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("channels")] - public Hash Channels { get; set; } - - /// - /// All active threads in the guild that current user has permission to view - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("threads")] - public Hash Threads { get; set; } - - /// - /// Presences of the members in the guild - /// will only include non-offline members if the size is greater than large threshold - /// - [JsonProperty("presences")] - public List Presences { get; set; } + /// + /// Total number of members in this guild + /// + [JsonProperty("member_count")] + public int? MemberCount { get; set; } + + /// + /// States of members currently in voice channels; lacks the guild_id key + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("voice_states")] + public Hash VoiceStates { get; set; } + + /// + /// Users in the guild + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("members")] + public Hash Members { get; set; } + + /// + /// Channels in the guild + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("channels")] + public Hash Channels { get; set; } + + /// + /// All active threads in the guild that current user has permission to view + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("threads")] + public Hash Threads { get; set; } + + /// + /// Presences of the members in the guild + /// will only include non-offline members if the size is greater than large threshold + /// + [JsonProperty("presences")] + public List Presences { get; set; } - /// - /// The maximum number of presences for the guild (the default value, currently 25000, is in effect when null is returned) - /// - [JsonProperty("max_presences")] - public int? MaxPresences { get; set; } + /// + /// The maximum number of presences for the guild (the default value, currently 25000, is in effect when null is returned) + /// + [JsonProperty("max_presences")] + public int? MaxPresences { get; set; } - /// - /// The maximum number of members for the guild - /// - [JsonProperty("max_members")] - public int? MaxMembers { get; set; } + /// + /// The maximum number of members for the guild + /// + [JsonProperty("max_members")] + public int? MaxMembers { get; set; } - /// - /// The vanity url code for the guild - /// - [JsonProperty("vanity_url_code")] - public string VanityUrlCode { get; set; } + /// + /// The vanity url code for the guild + /// + [JsonProperty("vanity_url_code")] + public string VanityUrlCode { get; set; } - /// - /// The description of a guild - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// The description of a guild + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Banner hash - /// - [JsonProperty("banner")] - public string Banner { get; set; } - - /// - /// Premium tier (Server Boost level) - /// - [JsonProperty("premium_tier")] - public GuildPremiumTier? PremiumTier { get; set; } + /// + /// Banner hash + /// + [JsonProperty("banner")] + public string Banner { get; set; } + + /// + /// Premium tier (Server Boost level) + /// + [JsonProperty("premium_tier")] + public GuildPremiumTier? PremiumTier { get; set; } - /// - /// The number of boosts this guild currently has - /// - [JsonProperty("premium_subscription_count")] - public int? PremiumSubscriptionCount { get; set; } - - /// - /// The preferred locale of a Community guild - /// Used in server discovery and notices from Discord - /// Defaults to "en-US" - /// - [JsonProperty("preferred_locale")] - public string PreferredLocale { get; set; } + /// + /// The number of boosts this guild currently has + /// + [JsonProperty("premium_subscription_count")] + public int? PremiumSubscriptionCount { get; set; } + + /// + /// The preferred locale of a Community guild + /// Used in server discovery and notices from Discord + /// Defaults to "en-US" + /// + [JsonProperty("preferred_locale")] + public string PreferredLocale { get; set; } - /// - /// The maximum amount of users in a video channel - /// - [JsonProperty("public_updates_channel_id")] - public Snowflake? PublicUpdatesChannelId { get; set; } + /// + /// The maximum amount of users in a video channel + /// + [JsonProperty("public_updates_channel_id")] + public Snowflake? PublicUpdatesChannelId { get; set; } - /// - /// The maximum amount of users in a stage video channel - /// - [JsonProperty("max_stage_video_channel_users")] - public int? MaxStageVideoChannelUsers { get; set; } + /// + /// The maximum amount of users in a stage video channel + /// + [JsonProperty("max_stage_video_channel_users")] + public int? MaxStageVideoChannelUsers { get; set; } - /// - /// The maximum amount of users in a video channel - /// - [JsonProperty("max_video_channel_users")] - public int? MaxVideoChannelUsers { get; set; } + /// + /// The maximum amount of users in a video channel + /// + [JsonProperty("max_video_channel_users")] + public int? MaxVideoChannelUsers { get; set; } - /// - /// Approximate number of members in this guild - /// - [JsonProperty("approximate_member_count")] - public int? ApproximateMemberCount { get; set; } + /// + /// Approximate number of members in this guild + /// + [JsonProperty("approximate_member_count")] + public int? ApproximateMemberCount { get; set; } - /// - /// Approximate number of non-offline members in this guild - /// - [JsonProperty("approximate_presence_count")] - public int? ApproximatePresenceCount { get; set; } + /// + /// Approximate number of non-offline members in this guild + /// + [JsonProperty("approximate_presence_count")] + public int? ApproximatePresenceCount { get; set; } - /// - /// The welcome screen of a Community guild - /// Shown to new members, returned in an Invite's guild object - /// - [JsonProperty("welcome_screen")] - public GuildWelcomeScreen WelcomeScreen { get; set; } + /// + /// The welcome screen of a Community guild + /// Shown to new members, returned in an Invite's guild object + /// + [JsonProperty("welcome_screen")] + public GuildWelcomeScreen WelcomeScreen { get; set; } - /// - /// Guild NSFW level - /// NSFW Information - /// - [JsonProperty("nsfw_level")] - public GuildNsfwLevel NsfwLevel { get; set; } - - /// - /// Stage instances in the guild - /// - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("stage_instances")] - public Hash StageInstances { get; set; } - - /// - /// Custom guild stickers - /// - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("stickers")] - public Hash Stickers { get; set; } + /// + /// Guild NSFW level + /// NSFW Information + /// + [JsonProperty("nsfw_level")] + public GuildNsfwLevel NsfwLevel { get; set; } + + /// + /// Stage instances in the guild + /// + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("stage_instances")] + public Hash StageInstances { get; set; } + + /// + /// Custom guild stickers + /// + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("stickers")] + public Hash Stickers { get; set; } - /// - /// The scheduled events in the guild - /// - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("guild_scheduled_events")] - public Hash ScheduledEvents { get; set; } + /// + /// The scheduled events in the guild + /// + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("guild_scheduled_events")] + public Hash ScheduledEvents { get; set; } - /// - /// The scheduled events in the guild - /// - [JsonProperty("premium_progress_bar_enabled")] - public bool PremiumProgressBarEnabled { get; set; } + /// + /// The scheduled events in the guild + /// + [JsonProperty("premium_progress_bar_enabled")] + public bool PremiumProgressBarEnabled { get; set; } - /// - /// The ID of the channel where admins and moderators of Community guilds receive safety alerts from Discord - /// - [JsonProperty("safety_alerts_channel_id")] - public Snowflake? SafetyAlertsChannelId { get; set; } - #endregion - - #region Extension Fields - /// - /// Returns true if all guild members have been loaded - /// - public bool HasLoadedAllMembers { get; internal set; } - - /// - /// Members who have left the guild - /// This list will contain members who have left the guild since the initial bot connection - /// - public Hash LeftMembers { get; } = new Hash(); - #endregion - - #region Helper Properties - /// - /// Returns if the guild is available to use - /// - public bool IsAvailable => Unavailable.HasValue && !Unavailable.Value; - - /// - /// Returns the guild Icon Url - /// - public string IconUrl => DiscordCdn.GetGuildIconUrl(Id, Icon); + /// + /// The ID of the channel where admins and moderators of Community guilds receive safety alerts from Discord + /// + [JsonProperty("safety_alerts_channel_id")] + public Snowflake? SafetyAlertsChannelId { get; set; } + #endregion + + #region Extension Fields + /// + /// Returns true if all guild members have been loaded + /// + public bool HasLoadedAllMembers { get; internal set; } + + /// + /// Members who have left the guild + /// This list will contain members who have left the guild since the initial bot connection + /// + public Hash LeftMembers { get; } = new(); + #endregion + + #region Helper Properties + /// + /// Returns if the guild is available to use + /// + public bool IsAvailable => Unavailable.HasValue && !Unavailable.Value; + + /// + /// Returns the guild Icon Url + /// + public string IconUrl => DiscordCdn.GetGuildIconUrl(Id, Icon); - /// - /// Returns the Guilds Splash Url - /// - public string SplashUrl => DiscordCdn.GetGuildSplashUrl(Id, Splash); + /// + /// Returns the Guilds Splash Url + /// + public string SplashUrl => DiscordCdn.GetGuildSplashUrl(Id, Splash); - /// - /// Returns the guilds Discovery Splash - /// - public string DiscoverySplashUrl => DiscordCdn.GetGuildDiscoverySplashUrl(Id, DiscoverySplash); + /// + /// Returns the guilds Discovery Splash + /// + public string DiscoverySplashUrl => DiscordCdn.GetGuildDiscoverySplashUrl(Id, DiscoverySplash); - /// - /// Return the guilds Banner Url - /// - public string BannerUrl => DiscordCdn.GetGuildBannerUrl(Id, Banner); - - /// - /// Returns the everyone role for the guild. - /// - public DiscordRole EveryoneRole => Roles[Id]; - #endregion - - #region Helper Methods - /// - /// Returns a channel with the given name (Case Insensitive) - /// - /// Name of the channel - /// Channel with the given name; Null otherwise - public DiscordChannel GetChannel(string name) - { - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - - foreach (DiscordChannel channel in Channels.Values) - { - if (channel.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) - { - return channel; - } - } + /// + /// Return the guilds Banner Url + /// + public string BannerUrl => DiscordCdn.GetGuildBannerUrl(Id, Banner); - return null; - } + /// + /// Returns the everyone role for the guild. + /// + public DiscordRole EveryoneRole => Roles[Id]; + #endregion - /// - /// Returns the channel or thread by ID - /// - /// ID of the thread of channel - /// - public DiscordChannel GetChannel(Snowflake id) - { - return Channels[id] ?? Threads[id]; - } + #region Helper Methods + /// + /// Returns a channel with the given name (Case Insensitive) + /// + /// Name of the channel + /// Channel with the given name; Null otherwise + public DiscordChannel GetChannel(string name) + { + if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - /// - /// Returns the parent channel for a channel if it exists - /// - /// Channel to find the parent for - /// Parent channel for the given channel; null otherwise - public DiscordChannel GetParentChannel(DiscordChannel channel) + foreach (DiscordChannel channel in Channels.Values) { - if (!channel.ParentId.HasValue || !channel.ParentId.Value.IsValid()) + if (channel.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) { - return null; + return channel; } - - return Channels[channel.ParentId.Value]; } - /// - /// Returns a Role with the given name (Case Insensitive) - /// - /// Name of the role - /// Role with the given name; Null otherwise - public DiscordRole GetRole(string name) - { - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); + return null; + } - foreach (DiscordRole role in Roles.Values) - { - if (role.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) - { - return role; - } - } + /// + /// Returns the channel or thread by ID + /// + /// ID of the thread of channel + /// + public DiscordChannel GetChannel(Snowflake id) + { + return Channels[id] ?? Threads[id]; + } + /// + /// Returns the parent channel for a channel if it exists + /// + /// Channel to find the parent for + /// Parent channel for the given channel; null otherwise + public DiscordChannel GetParentChannel(DiscordChannel channel) + { + if (!channel.ParentId.HasValue || !channel.ParentId.Value.IsValid()) + { return null; } - /// - /// Returns the booster role for the guild if it exists - /// - /// Booster role; null otherwise - public DiscordRole GetBoosterRole() - { - foreach (DiscordRole role in Roles.Values) - { - if (role.IsBoosterRole()) - { - return role; - } - } + return Channels[channel.ParentId.Value]; + } - return null; - } - - /// - /// Returns a GuildMember with the given username (Case Insensitive) - /// - /// Username of the GuildMember - /// GuildMember with the given username; Null otherwise - public GuildMember GetMember(string userName) + /// + /// Returns a Role with the given name (Case Insensitive) + /// + /// Name of the role + /// Role with the given name; Null otherwise + public DiscordRole GetRole(string name) + { + if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); + + foreach (DiscordRole role in Roles.Values) { - if (string.IsNullOrEmpty(userName)) throw new ArgumentNullException(nameof(userName)); - - foreach (GuildMember member in Members.Values) + if (role.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) { - if (member.User.Username.Equals(userName, StringComparison.OrdinalIgnoreCase)) - { - return member; - } + return role; } - - return null; } - /// - /// Returns the for the given User ID including members who are no longer in the guild - /// Left members only include s who have left the guild since the bot was connected - /// - /// User ID of the guild member to get - /// If we should include guild members who have left the guild - /// For the UserId - public GuildMember GetMember(Snowflake userId, bool includeLeft = false) - { - return Members[userId] ?? (includeLeft ? LeftMembers[userId] : null); - } - - /// - /// Finds guild emoji by name - /// - /// Name of the emoji - /// Emoji if found; null otherwise - /// - public DiscordEmoji GetEmoji(string name) - { - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); + return null; + } - foreach (DiscordEmoji emoji in Emojis.Values) + /// + /// Returns the booster role for the guild if it exists + /// + /// Booster role; null otherwise + public DiscordRole GetBoosterRole() + { + foreach (DiscordRole role in Roles.Values) + { + if (role.IsBoosterRole()) { - if (emoji.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) - { - return emoji; - } + return role; } - - return null; } + + return null; + } - /// - /// Returns the user permissions for the given user ID - /// - /// - /// - public PermissionFlags GetUserPermissions(Snowflake userId) + /// + /// Returns a GuildMember with the given username (Case Insensitive) + /// + /// Username of the GuildMember + /// GuildMember with the given username; Null otherwise + public GuildMember GetMember(string userName) + { + if (string.IsNullOrEmpty(userName)) throw new ArgumentNullException(nameof(userName)); + + foreach (GuildMember member in Members.Values) { - GuildMember member = Members[userId]; - if (member == null) + if (member.User.Username.Equals(userName, StringComparison.OrdinalIgnoreCase)) { - return PermissionFlags.None; + return member; } - - PermissionFlags permissions = EveryoneRole.Permissions; + } + + return null; + } - for (int index = 0; index < member.Roles.Count; index++) - { - DiscordRole role = Roles[member.Roles[index]]; - if (role != null) - { - permissions |= role.Permissions; - } - } + /// + /// Returns the for the given User ID including members who are no longer in the guild + /// Left members only include s who have left the guild since the bot was connected + /// + /// User ID of the guild member to get + /// If we should include guild members who have left the guild + /// For the UserId + public GuildMember GetMember(Snowflake userId, bool includeLeft = false) + { + return Members[userId] ?? (includeLeft ? LeftMembers[userId] : null); + } + + /// + /// Finds guild emoji by name + /// + /// Name of the emoji + /// Emoji if found; null otherwise + /// + public DiscordEmoji GetEmoji(string name) + { + if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - if ((permissions & PermissionFlags.Administrator) == PermissionFlags.Administrator) + foreach (DiscordEmoji emoji in Emojis.Values) + { + if (emoji.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) { - return PermissionFlags.All; + return emoji; } - - return permissions; - } - #endregion - - #region API Methods - /// - /// Create a new guild. - /// See Create Guild - /// - /// Client to use - /// Guild Create Object - public static IPromise Create(DiscordClient client, GuildCreate create) - { - if (create == null) throw new ArgumentNullException(nameof(create)); - return client.Bot.Rest.Post(client,"guilds", create); } - /// - /// Returns the guild object for the given id - /// See Get Guild - /// - /// Client to use - /// Guild ID to lookup - public static IPromise Get(DiscordClient client, Snowflake guildId) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Get(client,$"guilds/{guildId}"); - } + return null; + } - /// - /// Returns the guild preview object for the given id. - /// If the user is not in the guild, then the guild must be Discoverable. - /// - /// Client to use - /// Guild ID to get preview for - public static IPromise GetGuildPreview(DiscordClient client, Snowflake guildId) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Get(client,$"guilds/{guildId}/preview"); - } - - /// - /// Modify a guild's settings. - /// Requires the MANAGE_GUILD permission. - /// See Modify Guild - /// - /// Client to use - /// Update to be applied to the guild - public IPromise Edit(DiscordClient client, GuildUpdate update) + /// + /// Returns the user permissions for the given user ID + /// + /// + /// + public PermissionFlags GetUserPermissions(Snowflake userId) + { + GuildMember member = Members[userId]; + if (member == null) { - return client.Bot.Rest.Patch(client,$"guilds/{Id}", update); + return PermissionFlags.None; } + + PermissionFlags permissions = EveryoneRole.Permissions; - /// - /// Delete a guild permanently. - /// User must be owner - /// See Delete Guild - /// - /// Client to use - public IPromise Delete(DiscordClient client) + for (int index = 0; index < member.Roles.Count; index++) { - return client.Bot.Rest.Delete(client,$"guilds/{Id}"); + DiscordRole role = Roles[member.Roles[index]]; + if (role != null) + { + permissions |= role.Permissions; + } } - /// - /// Returns a list of guild channel objects. - /// Does not include threads - /// See Get Guild Channels - /// - /// Client to use - public IPromise> GetChannels(DiscordClient client) + if ((permissions & PermissionFlags.Administrator) == PermissionFlags.Administrator) { - return client.Bot.Rest.Get>(client,$"guilds/{Id}/channels"); + return PermissionFlags.All; } - /// - /// Create a new channel object for the guild. - /// Requires the MANAGE_CHANNELS permission. - /// See Create Guild Channel - /// - /// Client to use - /// Channel to create - public IPromise CreateChannel(DiscordClient client, ChannelCreate channel) - { - return client.Bot.Rest.Post(client,$"guilds/{Id}/channels", channel); - } + return permissions; + } + #endregion - /// - /// Modify the positions of a set of channel objects for the guild. - /// Requires MANAGE_CHANNELS permission. - /// Only channels to be modified are required, with the minimum being a swap between at least two channels. - /// See Modify Guild Channel Positions - /// - /// Client to use - /// List new channel positions for each channel - public IPromise> EditChannelPositions(DiscordClient client, List positions) - { - return client.Bot.Rest.Patch>(client,$"guilds/{Id}/channels", positions); - } + #region API Methods + /// + /// Create a new guild. + /// See Create Guild + /// + /// Client to use + /// Guild Create Object + public static IPromise Create(DiscordClient client, GuildCreate create) + { + if (create == null) throw new ArgumentNullException(nameof(create)); + return client.Bot.Rest.Post(client,"guilds", create); + } - /// - /// Returns all active threads in the guild, including public and private threads. Threads are ordered by their id, in descending order. - /// See List Active Threads - /// - /// Client to use - public IPromise ListActiveThreads(DiscordClient client) - { - return client.Bot.Rest.Get(client,$"guilds/{Id}/threads/active"); - } + /// + /// Returns the guild object for the given id + /// See Get Guild + /// + /// Client to use + /// Guild ID to lookup + public static IPromise Get(DiscordClient client, Snowflake guildId) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Get(client,$"guilds/{guildId}"); + } - /// - /// Returns a guild member object for the specified user. - /// See Get Guild Member - /// - /// Client to use - /// UserID to get guild member for - public IPromise GetMember(DiscordClient client, Snowflake userId) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Get(client,$"guilds/{Id}/members/{userId}"); - } + /// + /// Returns the guild preview object for the given id. + /// If the user is not in the guild, then the guild must be Discoverable. + /// + /// Client to use + /// Guild ID to get preview for + public static IPromise GetGuildPreview(DiscordClient client, Snowflake guildId) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Get(client,$"guilds/{guildId}/preview"); + } - /// - /// Returns a list of guild member objects that are members of the guild. - /// In the future, this endpoint will be restricted in line with our Privileged Intents - /// - /// Client to use - /// Query string request for the list - public IPromise> Listembers(DiscordClient client, GuildListMembers list = null) - { - return client.Bot.Rest.Get>(client,$"guilds/{Id}/members{list?.ToQueryString()}"); - } + /// + /// Modify a guild's settings. + /// Requires the MANAGE_GUILD permission. + /// See Modify Guild + /// + /// Client to use + /// Update to be applied to the guild + public IPromise Edit(DiscordClient client, GuildUpdate update) + { + return client.Bot.Rest.Patch(client,$"guilds/{Id}", update); + } - /// - /// Searches for guild members by username or nickname - /// - /// Client to use - /// Username or nickname to match - public IPromise> SearchMembers(DiscordClient client, GuildSearchMembers search) - { - if (search == null) throw new ArgumentNullException(nameof(search)); - return client.Bot.Rest.Get>(client,$"guilds/{Id}/members/search{search.ToQueryString()}"); - } + /// + /// Delete a guild permanently. + /// User must be owner + /// See Delete Guild + /// + /// Client to use + public IPromise Delete(DiscordClient client) + { + return client.Bot.Rest.Delete(client,$"guilds/{Id}"); + } - /// - /// Adds a user to the guild, provided you have a valid oauth2 access token for the user with the guilds.join scope. - /// See Add Guild Member - /// - /// Client to use - /// User ID of the user to add - /// Member to copy from - public IPromise AddMember(DiscordClient client, Snowflake userId, GuildMemberAdd member) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Put(client,$"guilds/{Id}/members/{userId}", member); - } + /// + /// Returns a list of guild channel objects. + /// Does not include threads + /// See Get Guild Channels + /// + /// Client to use + public IPromise> GetChannels(DiscordClient client) + { + return client.Bot.Rest.Get>(client,$"guilds/{Id}/channels"); + } + + /// + /// Create a new channel object for the guild. + /// Requires the MANAGE_CHANNELS permission. + /// See Create Guild Channel + /// + /// Client to use + /// Channel to create + public IPromise CreateChannel(DiscordClient client, ChannelCreate channel) + { + return client.Bot.Rest.Post(client,$"guilds/{Id}/channels", channel); + } + + /// + /// Modify the positions of a set of channel objects for the guild. + /// Requires MANAGE_CHANNELS permission. + /// Only channels to be modified are required, with the minimum being a swap between at least two channels. + /// See Modify Guild Channel Positions + /// + /// Client to use + /// List new channel positions for each channel + public IPromise> EditChannelPositions(DiscordClient client, List positions) + { + return client.Bot.Rest.Patch>(client,$"guilds/{Id}/channels", positions); + } - /// - /// Modify attributes of a guild member - /// See Modify Guild Member - /// - /// Client to use - /// User ID of the user to update - /// Changes to make to the user - public IPromise EditMember(DiscordClient client, Snowflake userId, GuildMemberUpdate update) + /// + /// Returns all active threads in the guild, including public and private threads. Threads are ordered by their id, in descending order. + /// See List Active Threads + /// + /// Client to use + public IPromise ListActiveThreads(DiscordClient client) + { + return client.Bot.Rest.Get(client,$"guilds/{Id}/threads/active"); + } + + /// + /// Returns a guild member object for the specified user. + /// See Get Guild Member + /// + /// Client to use + /// UserID to get guild member for + public IPromise GetMember(DiscordClient client, Snowflake userId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Get(client,$"guilds/{Id}/members/{userId}").Then(member => { - if (update == null) throw new ArgumentNullException(nameof(update)); - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Patch(client,$"guilds/{Id}/members/{userId}", update); - } + Members.TryAdd(member.Id, member); + }); + } + + /// + /// Returns a list of guild member objects that are members of the guild. + /// In the future, this endpoint will be restricted in line with our Privileged Intents + /// + /// Client to use + /// Query string request for the list + public IPromise> ListMembers(DiscordClient client, GuildListMembers list = null) + { + return client.Bot.Rest.Get>(client,$"guilds/{Id}/members{list?.ToQueryString()}"); + } + + /// + /// Searches for guild members by username or nickname + /// + /// Client to use + /// Username or nickname to match + public IPromise> SearchMembers(DiscordClient client, GuildSearchMembers search) + { + if (search == null) throw new ArgumentNullException(nameof(search)); + return client.Bot.Rest.Get>(client,$"guilds/{Id}/members/search{search.ToQueryString()}"); + } + + /// + /// Adds a user to the guild, provided you have a valid oauth2 access token for the user with the guilds.join scope. + /// See Add Guild Member + /// + /// Client to use + /// User ID of the user to add + /// Member to copy from + public IPromise AddMember(DiscordClient client, Snowflake userId, GuildMemberAdd member) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Put(client,$"guilds/{Id}/members/{userId}", member); + } + + /// + /// Modify attributes of a guild member + /// See Modify Guild Member + /// + /// Client to use + /// User ID of the user to update + /// Changes to make to the user + public IPromise EditMember(DiscordClient client, Snowflake userId, GuildMemberUpdate update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Patch(client,$"guilds/{Id}/members/{userId}", update); + } - /// - /// Modify attributes of a guild member - /// See Modify Guild Member - /// - /// Client to use - /// User ID of the user to update - /// Nickname for the user - public IPromise EditMemberNick(DiscordClient client, Snowflake userId, string nick) + /// + /// Modify attributes of a guild member + /// See Modify Guild Member + /// + /// Client to use + /// User ID of the user to update + /// Nickname for the user + public IPromise EditMemberNick(DiscordClient client, Snowflake userId, string nick) + { + GuildMemberUpdate update = new() { - GuildMemberUpdate update = new GuildMemberUpdate - { - Nick = nick - }; + Nick = nick + }; - return EditMember(client, userId, update); - } + return EditMember(client, userId, update); + } - /// - /// Modifies the current members nickname in the guild - /// See Modify Current Member - /// - /// Client to use - /// New members nickname (1-32 characters) - public IPromise EditCurrentMember(DiscordClient client, string nick) - { - InvalidGuildMemberException.ThrowIfInvalidNickname(nick); + /// + /// Modifies the current members nickname in the guild + /// See Modify Current Member + /// + /// Client to use + /// New members nickname (1-32 characters) + public IPromise EditCurrentMember(DiscordClient client, string nick) + { + InvalidGuildMemberException.ThrowIfInvalidNickname(nick); - Dictionary data = new Dictionary - { - ["nick"] = nick - }; + Dictionary data = new() + { + ["nick"] = nick + }; - return client.Bot.Rest.Patch(client,$"guilds/{Id}/members/@me", data); - } + return client.Bot.Rest.Patch(client,$"guilds/{Id}/members/@me", data); + } - /// - /// Adds a role to a guild member. - /// Requires the MANAGE_ROLES permission. - /// See Add Guild Member Role - /// - /// Client to use - /// User to add role to - /// Role to add - public IPromise AddMemberRole(DiscordClient client, DiscordUser user, DiscordRole role) => AddMemberRole(client, user.Id, role.Id); - - /// - /// Adds a role to a guild member. - /// Requires the MANAGE_ROLES permission. - /// See Add Guild Member Role - /// - /// Client to use - /// User ID to add role to - /// Role ID to add - public IPromise AddMemberRole(DiscordClient client, Snowflake userId, Snowflake roleId) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - InvalidSnowflakeException.ThrowIfInvalid(roleId, nameof(roleId)); - return client.Bot.Rest.Put(client,$"guilds/{Id}/members/{userId}/roles/{roleId}", null); - } + /// + /// Adds a role to a guild member. + /// Requires the MANAGE_ROLES permission. + /// See Add Guild Member Role + /// + /// Client to use + /// User to add role to + /// Role to add + public IPromise AddMemberRole(DiscordClient client, DiscordUser user, DiscordRole role) => AddMemberRole(client, user.Id, role.Id); - /// - /// Removes a role from a guild member. - /// Requires the MANAGE_ROLES permission. - /// See Remove Guild Member Role - /// - /// Client to use - /// User to remove role form - /// Role to remove - public IPromise RemoveMemberRole(DiscordClient client, DiscordUser user, DiscordRole role) => RemoveMemberRole(client, user.Id, role.Id); - - /// - /// Removes a role from a guild member. - /// Requires the MANAGE_ROLES permission. - /// See Remove Guild Member Role - /// - /// Client to use - /// User ID to remove role form - /// Role ID to remove - public IPromise RemoveMemberRole(DiscordClient client, Snowflake userId, Snowflake roleId) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - InvalidSnowflakeException.ThrowIfInvalid(roleId, nameof(roleId)); - return client.Bot.Rest.Delete(client,$"guilds/{Id}/members/{userId}/roles/{roleId}"); - } + /// + /// Adds a role to a guild member. + /// Requires the MANAGE_ROLES permission. + /// See Add Guild Member Role + /// + /// Client to use + /// User ID to add role to + /// Role ID to add + public IPromise AddMemberRole(DiscordClient client, Snowflake userId, Snowflake roleId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + InvalidSnowflakeException.ThrowIfInvalid(roleId); + return client.Bot.Rest.Put(client,$"guilds/{Id}/members/{userId}/roles/{roleId}", null); + } - /// - /// Remove a member from a guild. - /// Requires KICK_MEMBERS permission. - /// See Remove Guild Member - /// - /// Client to use - /// Guild Member to remove - public IPromise RemoveMember(DiscordClient client, GuildMember member) => RemoveMember(client, member.User.Id); - - /// - /// Remove a member from a guild. - /// Requires KICK_MEMBERS permission. - /// See Remove Guild Member - /// - /// Client to use - /// User ID of the user to remove - public IPromise RemoveMember(DiscordClient client, Snowflake userId) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Delete(client,$"guilds/{Id}/members/{userId}"); - } + /// + /// Removes a role from a guild member. + /// Requires the MANAGE_ROLES permission. + /// See Remove Guild Member Role + /// + /// Client to use + /// User to remove role form + /// Role to remove + public IPromise RemoveMemberRole(DiscordClient client, DiscordUser user, DiscordRole role) => RemoveMemberRole(client, user.Id, role.Id); - /// - /// Returns a list of ban objects for the users banned from this guild. - /// See Get Guild Bans - /// - /// Client to use - /// Request params for retrieving guild bans - public IPromise> GetBans(DiscordClient client, GuildBansRequest request = null) - { - return client.Bot.Rest.Get>(client,$"guilds/{Id}/bans{request?.ToQueryString()}"); - } + /// + /// Removes a role from a guild member. + /// Requires the MANAGE_ROLES permission. + /// See Remove Guild Member Role + /// + /// Client to use + /// User ID to remove role form + /// Role ID to remove + public IPromise RemoveMemberRole(DiscordClient client, Snowflake userId, Snowflake roleId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + InvalidSnowflakeException.ThrowIfInvalid(roleId); + return client.Bot.Rest.Delete(client,$"guilds/{Id}/members/{userId}/roles/{roleId}"); + } - /// - /// Returns a guild ban for a specific user - /// See Get Guild Ban - /// Returns 404 if not found - /// - /// Client to use - /// User ID to get guild ban for - public IPromise GetBan(DiscordClient client, Snowflake userId) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Get(client,$"guilds/{Id}/bans/{userId}"); - } + /// + /// Remove a member from a guild. + /// Requires KICK_MEMBERS permission. + /// See Remove Guild Member + /// + /// Client to use + /// Guild Member to remove + public IPromise RemoveMember(DiscordClient client, GuildMember member) => RemoveMember(client, member.User.Id); - /// - /// Create a guild ban, and optionally delete previous messages sent by the banned user. - /// Requires the BAN_MEMBERS permission. - /// See Create Guild Ban - /// - /// Client to use - /// Guild Member to ban - /// User ban information - public IPromise CreateBan(DiscordClient client, GuildMember member, GuildBanCreate ban) => CreateBan(client, member.User.Id, ban); - - /// - /// Create a guild ban, and optionally delete previous messages sent by the banned user. - /// Requires the BAN_MEMBERS permission. - /// See Create Guild Ban - /// - /// Client to use - /// User ID to ban - /// User ban information - public IPromise CreateBan(DiscordClient client, Snowflake userId, GuildBanCreate ban) - { - if (ban == null) throw new ArgumentNullException(nameof(ban)); - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Put(client,$"guilds/{Id}/bans/{userId}", ban); - } + /// + /// Remove a member from a guild. + /// Requires KICK_MEMBERS permission. + /// See Remove Guild Member + /// + /// Client to use + /// User ID of the user to remove + public IPromise RemoveMember(DiscordClient client, Snowflake userId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Delete(client,$"guilds/{Id}/members/{userId}"); + } - /// - /// Remove the ban for a user. - /// Requires the BAN_MEMBERS permissions. - /// See Remove Guild Ban - /// - /// Client to use - /// User ID of the user to unban - public IPromise RemoveBan(DiscordClient client, Snowflake userId) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Delete(client,$"guilds/{Id}/bans/{userId}"); - } + /// + /// Returns a list of ban objects for the users banned from this guild. + /// See Get Guild Bans + /// + /// Client to use + /// Request params for retrieving guild bans + public IPromise> GetBans(DiscordClient client, GuildBansRequest request = null) + { + return client.Bot.Rest.Get>(client,$"guilds/{Id}/bans{request?.ToQueryString()}"); + } - /// - /// Returns a list of role objects for the guild. - /// See Get Guild Roles - /// - /// Client to use - public IPromise> GetRoles(DiscordClient client) - { - return client.Bot.Rest.Get>(client,$"guilds/{Id}/roles"); - } + /// + /// Returns a guild ban for a specific user + /// See Get Guild Ban + /// Returns 404 if not found + /// + /// Client to use + /// User ID to get guild ban for + public IPromise GetBan(DiscordClient client, Snowflake userId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Get(client,$"guilds/{Id}/bans/{userId}"); + } - /// - /// Create a new role for the guild. - /// Requires the MANAGE_ROLES permission. - /// Returns the new role object on success. - /// See Create Guild Role - /// - /// Client to use - /// New role to create - public IPromise CreateRole(DiscordClient client, DiscordRole role) - { - if (role == null) throw new ArgumentNullException(nameof(role)); - return client.Bot.Rest.Post(client,$"guilds/{Id}/roles", role); - } + /// + /// Create a guild ban, and optionally delete previous messages sent by the banned user. + /// Requires the BAN_MEMBERS permission. + /// See Create Guild Ban + /// + /// Client to use + /// Guild Member to ban + /// User ban information + public IPromise CreateBan(DiscordClient client, GuildMember member, GuildBanCreate ban) => CreateBan(client, member.User.Id, ban); - /// - /// Modify the positions of a set of role objects for the guild. - /// Requires the MANAGE_ROLES permission. - /// Returns a list of all of the guild's role objects on success. - /// See Modify Guild Role Positions - /// - /// Client to use - /// List of role with updated positions - public IPromise> EditRolePositions(DiscordClient client, List positions) - { - if (positions == null) throw new ArgumentNullException(nameof(positions)); - return client.Bot.Rest.Patch>(client,$"guilds/{Id}/roles", positions); - } + /// + /// Create a guild ban, and optionally delete previous messages sent by the banned user. + /// Requires the BAN_MEMBERS permission. + /// See Create Guild Ban + /// + /// Client to use + /// User ID to ban + /// User ban information + public IPromise CreateBan(DiscordClient client, Snowflake userId, GuildBanCreate ban) + { + if (ban == null) throw new ArgumentNullException(nameof(ban)); + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Put(client,$"guilds/{Id}/bans/{userId}", ban); + } - /// - /// Modify a guild role. - /// Requires the MANAGE_ROLES permission. - /// Returns the updated role on success. - /// See Modify Guild Role - /// - /// Client to use - /// Role to update - public IPromise EditRole(DiscordClient client, DiscordRole role) => EditRole(client, role.Id, role); - - /// - /// Modify a guild role. - /// Requires the MANAGE_ROLES permission. - /// Returns the updated role on success. - /// See Modify Guild Role - /// - /// Client to use - /// Role ID to update - /// Role to update - public IPromise EditRole(DiscordClient client, Snowflake roleId, DiscordRole role) - { - if (role == null) throw new ArgumentNullException(nameof(role)); - InvalidSnowflakeException.ThrowIfInvalid(roleId, nameof(roleId)); - return client.Bot.Rest.Patch(client,$"guilds/{Id}/roles/{roleId}", role); - } + /// + /// Remove the ban for a user. + /// Requires the BAN_MEMBERS permissions. + /// See Remove Guild Ban + /// + /// Client to use + /// User ID of the user to unban + public IPromise RemoveBan(DiscordClient client, Snowflake userId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Delete(client,$"guilds/{Id}/bans/{userId}"); + } + + /// + /// Returns a list of role objects for the guild. + /// See Get Guild Roles + /// + /// Client to use + public IPromise> GetRoles(DiscordClient client) + { + return client.Bot.Rest.Get>(client,$"guilds/{Id}/roles"); + } + + /// + /// Create a new role for the guild. + /// Requires the MANAGE_ROLES permission. + /// Returns the new role object on success. + /// See Create Guild Role + /// + /// Client to use + /// New role to create + public IPromise CreateRole(DiscordClient client, DiscordRole role) + { + if (role == null) throw new ArgumentNullException(nameof(role)); + return client.Bot.Rest.Post(client,$"guilds/{Id}/roles", role); + } + + /// + /// Modify the positions of a set of role objects for the guild. + /// Requires the MANAGE_ROLES permission. + /// Returns a list of all of the guild's role objects on success. + /// See Modify Guild Role Positions + /// + /// Client to use + /// List of role with updated positions + public IPromise> EditRolePositions(DiscordClient client, List positions) + { + if (positions == null) throw new ArgumentNullException(nameof(positions)); + return client.Bot.Rest.Patch>(client,$"guilds/{Id}/roles", positions); + } + + /// + /// Modify a guild role. + /// Requires the MANAGE_ROLES permission. + /// Returns the updated role on success. + /// See Modify Guild Role + /// + /// Client to use + /// Role to update + public IPromise EditRole(DiscordClient client, DiscordRole role) => EditRole(client, role.Id, role); + + /// + /// Modify a guild role. + /// Requires the MANAGE_ROLES permission. + /// Returns the updated role on success. + /// See Modify Guild Role + /// + /// Client to use + /// Role ID to update + /// Role to update + public IPromise EditRole(DiscordClient client, Snowflake roleId, DiscordRole role) + { + if (role == null) throw new ArgumentNullException(nameof(role)); + InvalidSnowflakeException.ThrowIfInvalid(roleId); + return client.Bot.Rest.Patch(client,$"guilds/{Id}/roles/{roleId}", role); + } - /// - /// Modify a guild's MFA level. - /// Requires guild ownership. - /// See Modify Guild MFA Level - /// - /// Client to use - /// to set - public IPromise EditMfaLevel(DiscordClient client, GuildUpdateMfaLevel level) - { - return client.Bot.Rest.Post(client,$"guilds/{Id}/mfa/", level); - } + /// + /// Modify a guild's MFA level. + /// Requires guild ownership. + /// See Modify Guild MFA Level + /// + /// Client to use + /// to set + public IPromise EditMfaLevel(DiscordClient client, GuildUpdateMfaLevel level) + { + return client.Bot.Rest.Post(client,$"guilds/{Id}/mfa/", level); + } - /// - /// Delete a guild role. - /// Requires the MANAGE_ROLES permission - /// See Delete Guild Role - /// - /// Client to use - /// Role to Delete - public IPromise DeleteRole(DiscordClient client, DiscordRole role) => DeleteRole(client, role.Id); - - /// - /// Delete a guild role. - /// Requires the MANAGE_ROLES permission - /// See Delete Guild Role - /// - /// Client to use - /// Role ID to Delete - public IPromise DeleteRole(DiscordClient client, Snowflake roleId) - { - InvalidSnowflakeException.ThrowIfInvalid(roleId, nameof(roleId)); - return client.Bot.Rest.Delete(client,$"guilds/{Id}/roles/{roleId}"); - } + /// + /// Delete a guild role. + /// Requires the MANAGE_ROLES permission + /// See Delete Guild Role + /// + /// Client to use + /// Role to Delete + public IPromise DeleteRole(DiscordClient client, DiscordRole role) => DeleteRole(client, role.Id); - /// - /// Returns an object with one 'pruned' key indicating the number of members that would be removed in a prune operation. - /// Requires the KICK_MEMBERS permission. - /// See Get Guild Prune Count - /// - /// Client to use - /// Prune get request - public IPromise GetPruneCount(DiscordClient client, GuildPruneGet prune) - { - if (prune == null) throw new ArgumentNullException(nameof(prune)); - return client.Bot.Rest.Get(client, $"guilds/{Id}/prune?{prune.ToQueryString()}"); - } + /// + /// Delete a guild role. + /// Requires the MANAGE_ROLES permission + /// See Delete Guild Role + /// + /// Client to use + /// Role ID to Delete + public IPromise DeleteRole(DiscordClient client, Snowflake roleId) + { + InvalidSnowflakeException.ThrowIfInvalid(roleId); + return client.Bot.Rest.Delete(client,$"guilds/{Id}/roles/{roleId}"); + } - /// - /// Begin a prune operation. - /// Requires the KICK_MEMBERS permission. - /// See Begin Guild Prune - /// - /// Client to use - /// Prune begin request - public IPromise BeginPrune(DiscordClient client, GuildPruneBegin prune) - { - if (prune == null) throw new ArgumentNullException(nameof(prune)); - return client.Bot.Rest.Post(client, $"guilds/{Id}/prune?{prune.ToQueryString()}", null); - } + /// + /// Returns an object with one 'pruned' key indicating the number of members that would be removed in a prune operation. + /// Requires the KICK_MEMBERS permission. + /// See Get Guild Prune Count + /// + /// Client to use + /// Prune get request + public IPromise GetPruneCount(DiscordClient client, GuildPruneGet prune) + { + if (prune == null) throw new ArgumentNullException(nameof(prune)); + return client.Bot.Rest.Get(client, $"guilds/{Id}/prune?{prune.ToQueryString()}"); + } - /// - /// Returns a list of voice region objects for the guild. - /// Unlike the similar /voice route, this returns VIP servers when the guild is VIP-enabled. - /// See Get Guild Voice Regions - /// - /// Client to use - public IPromise> GetVoiceRegions(DiscordClient client) - { - return client.Bot.Rest.Get>(client,$"guilds/{Id}/regions"); - } + /// + /// Begin a prune operation. + /// Requires the KICK_MEMBERS permission. + /// See Begin Guild Prune + /// + /// Client to use + /// Prune begin request + public IPromise BeginPrune(DiscordClient client, GuildPruneBegin prune) + { + if (prune == null) throw new ArgumentNullException(nameof(prune)); + return client.Bot.Rest.Post(client, $"guilds/{Id}/prune?{prune.ToQueryString()}", null); + } - /// - /// Returns a list of invite objects (with invite metadata) for the guild. - /// Requires the MANAGE_GUILD permission. - /// See Get Guild Invites - /// - /// Client to use - public IPromise> GetInvites(DiscordClient client) - { - return client.Bot.Rest.Get>(client,$"guilds/{Id}/invites"); - } + /// + /// Returns a list of voice region objects for the guild. + /// Unlike the similar /voice route, this returns VIP servers when the guild is VIP-enabled. + /// See Get Guild Voice Regions + /// + /// Client to use + public IPromise> GetVoiceRegions(DiscordClient client) + { + return client.Bot.Rest.Get>(client,$"guilds/{Id}/regions"); + } - /// - /// Returns a list of integration objects for the guild. - /// Requires the MANAGE_GUILD permission. - /// See Get Guild Integrations - /// - /// Client to use - public IPromise> GetIntegrations(DiscordClient client) - { - return client.Bot.Rest.Get>(client,$"guilds/{Id}/integrations"); - } + /// + /// Returns a list of invite objects (with invite metadata) for the guild. + /// Requires the MANAGE_GUILD permission. + /// See Get Guild Invites + /// + /// Client to use + public IPromise> GetInvites(DiscordClient client) + { + return client.Bot.Rest.Get>(client,$"guilds/{Id}/invites"); + } - /// - /// Delete the attached integration object for the guild. - /// Deletes any associated webhooks and kicks the associated bot if there is one. - /// Requires the MANAGE_GUILD permission. - /// See Delete Guild Integration - /// - /// Client to use - /// Integration to delete - public IPromise DeleteIntegration(DiscordClient client, Integration integration) => DeleteIntegration(client, integration.Id); - - /// - /// Delete the attached integration object for the guild. - /// Deletes any associated webhooks and kicks the associated bot if there is one. - /// Requires the MANAGE_GUILD permission. - /// See Delete Guild Integration - /// - /// Client to use - /// Integration ID to delete - public IPromise DeleteIntegration(DiscordClient client, Snowflake integrationId) - { - InvalidSnowflakeException.ThrowIfInvalid(integrationId, nameof(integrationId)); - return client.Bot.Rest.Delete(client,$"guilds/{Id}/integrations/{integrationId}"); - } + /// + /// Returns a list of integration objects for the guild. + /// Requires the MANAGE_GUILD permission. + /// See Get Guild Integrations + /// + /// Client to use + public IPromise> GetIntegrations(DiscordClient client) + { + return client.Bot.Rest.Get>(client,$"guilds/{Id}/integrations"); + } - /// - /// Returns a guild widget object. - /// Requires the MANAGE_GUILD permission. - /// See Get Guild Widget Settings - /// - /// client to use - public IPromise GetWidgetSettings(DiscordClient client) - { - return client.Bot.Rest.Get(client,$"guilds/{Id}/widget"); - } + /// + /// Delete the attached integration object for the guild. + /// Deletes any associated webhooks and kicks the associated bot if there is one. + /// Requires the MANAGE_GUILD permission. + /// See Delete Guild Integration + /// + /// Client to use + /// Integration to delete + public IPromise DeleteIntegration(DiscordClient client, Integration integration) => DeleteIntegration(client, integration.Id); + + /// + /// Delete the attached integration object for the guild. + /// Deletes any associated webhooks and kicks the associated bot if there is one. + /// Requires the MANAGE_GUILD permission. + /// See Delete Guild Integration + /// + /// Client to use + /// Integration ID to delete + public IPromise DeleteIntegration(DiscordClient client, Snowflake integrationId) + { + InvalidSnowflakeException.ThrowIfInvalid(integrationId); + return client.Bot.Rest.Delete(client,$"guilds/{Id}/integrations/{integrationId}"); + } + + /// + /// Returns a guild widget object. + /// Requires the MANAGE_GUILD permission. + /// See Get Guild Widget Settings + /// + /// client to use + public IPromise GetWidgetSettings(DiscordClient client) + { + return client.Bot.Rest.Get(client,$"guilds/{Id}/widget"); + } - /// - /// Modify a guild widget object for the guild. - /// Requires the MANAGE_GUILD permission. - /// See Modify Guild Widget - /// - /// Client to use - /// Updated widget - public IPromise EditWidget(DiscordClient client, GuildWidget widget) - { - if (widget == null) throw new ArgumentNullException(nameof(widget)); - return client.Bot.Rest.Patch(client,$"guilds/{Id}/widget", widget); - } + /// + /// Modify a guild widget object for the guild. + /// Requires the MANAGE_GUILD permission. + /// See Modify Guild Widget + /// + /// Client to use + /// Updated widget + public IPromise EditWidget(DiscordClient client, GuildWidget widget) + { + if (widget == null) throw new ArgumentNullException(nameof(widget)); + return client.Bot.Rest.Patch(client,$"guilds/{Id}/widget", widget); + } - /// - /// Returns the widget for the guild. - /// See Get Guild Widget - /// - /// Client to use - public IPromise GetWidget(DiscordClient client) - { - return client.Bot.Rest.Get(client,$"guilds/{Id}/widget.json"); - } + /// + /// Returns the widget for the guild. + /// See Get Guild Widget + /// + /// Client to use + public IPromise GetWidget(DiscordClient client) + { + return client.Bot.Rest.Get(client,$"guilds/{Id}/widget.json"); + } - /// - /// Returns the Welcome Screen object for the guild. - /// Requires the `MANAGE_GUILD` permission. - /// - /// Client to use - public IPromise GetWelcomeScreen(DiscordClient client) - { - return client.Bot.Rest.Get(client,$"guilds/{Id}/welcome-screen"); - } + /// + /// Returns the Welcome Screen object for the guild. + /// Requires the `MANAGE_GUILD` permission. + /// + /// Client to use + public IPromise GetWelcomeScreen(DiscordClient client) + { + return client.Bot.Rest.Get(client,$"guilds/{Id}/welcome-screen"); + } - /// - /// Modify the guild's Welcome Screen. - /// Requires the MANAGE_GUILD permission. - /// Returns the updated Welcome Screen object. - /// - /// Client to use - /// Update to be made to the welcome screen - public IPromise EditWelcomeScreen(DiscordClient client, WelcomeScreenUpdate update) - { - if (update == null) throw new ArgumentNullException(nameof(update)); - return client.Bot.Rest.Patch(client,$"guilds/{Id}/welcome-screen", update); - } + /// + /// Modify the guild's Welcome Screen. + /// Requires the MANAGE_GUILD permission. + /// Returns the updated Welcome Screen object. + /// + /// Client to use + /// Update to be made to the welcome screen + public IPromise EditWelcomeScreen(DiscordClient client, WelcomeScreenUpdate update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + return client.Bot.Rest.Patch(client,$"guilds/{Id}/welcome-screen", update); + } - /// - /// Returns a partial invite object for guilds with that feature enabled. - /// Requires the MANAGE_GUILD permission. - /// Code will be null if a vanity url for the guild is not set. - /// - /// Client to use - public IPromise GetVanityUrl(DiscordClient client) - { - return client.Bot.Rest.Get(client,$"guilds/{Id}/vanity-url"); - } + /// + /// Returns a partial invite object for guilds with that feature enabled. + /// Requires the MANAGE_GUILD permission. + /// Code will be null if a vanity url for the guild is not set. + /// + /// Client to use + public IPromise GetVanityUrl(DiscordClient client) + { + return client.Bot.Rest.Get(client,$"guilds/{Id}/vanity-url"); + } - /// - /// Returns a list of emoji objects for the given guild. - /// See List Guild Emojis - /// - /// Client to use - public IPromise> ListEmojis(DiscordClient client) - { - return client.Bot.Rest.Get>(client,$"guilds/{Id}/emojis"); - } + /// + /// Returns a list of emoji objects for the given guild. + /// See List Guild Emojis + /// + /// Client to use + public IPromise> ListEmojis(DiscordClient client) + { + return client.Bot.Rest.Get>(client,$"guilds/{Id}/emojis"); + } - /// - /// Returns an emoji object for the given guild and emoji IDs. - /// See Get Guild Emoji - /// - /// Client to use - /// Emoji to lookup - public IPromise GetEmoji(DiscordClient client, Snowflake emojiId) - { - InvalidSnowflakeException.ThrowIfInvalid(emojiId, nameof(emojiId)); - return client.Bot.Rest.Get(client,$"guilds/{Id}/emojis/{emojiId}"); - } + /// + /// Returns an emoji object for the given guild and emoji IDs. + /// See Get Guild Emoji + /// + /// Client to use + /// Emoji to lookup + public IPromise GetEmoji(DiscordClient client, Snowflake emojiId) + { + InvalidSnowflakeException.ThrowIfInvalid(emojiId); + return client.Bot.Rest.Get(client,$"guilds/{Id}/emojis/{emojiId}"); + } - /// - /// Create a new emoji for the guild. - /// Requires the MANAGE_EMOJIS permission. - /// Returns the new emoji object on success. - /// See Create Guild Emoji - /// - /// Client to use - /// Emoji to create - public IPromise CreateEmoji(DiscordClient client, EmojiCreate emoji) - { - if (emoji == null) throw new ArgumentNullException(nameof(emoji)); - return client.Bot.Rest.Post(client,$"guilds/{Id}/emojis", emoji); - } + /// + /// Create a new emoji for the guild. + /// Requires the MANAGE_EMOJIS permission. + /// Returns the new emoji object on success. + /// See Create Guild Emoji + /// + /// Client to use + /// Emoji to create + public IPromise CreateEmoji(DiscordClient client, EmojiCreate emoji) + { + if (emoji == null) throw new ArgumentNullException(nameof(emoji)); + return client.Bot.Rest.Post(client,$"guilds/{Id}/emojis", emoji); + } - /// - /// Modify the given emoji. - /// Requires the MANAGE_EMOJIS permission. - /// Returns the updated emoji object on success. - /// See Modify Guild Emoji - /// - /// Client to use - /// Emoji ID to update - /// Emoji update - public IPromise EditEmoji(DiscordClient client, Snowflake emojiId, EmojiUpdate emoji) - { - if (emoji == null) throw new ArgumentNullException(nameof(emoji)); - InvalidSnowflakeException.ThrowIfInvalid(emojiId, nameof(emojiId)); - return client.Bot.Rest.Patch(client,$"guilds/{Id}/emojis/{emojiId}", emoji); - } + /// + /// Modify the given emoji. + /// Requires the MANAGE_EMOJIS permission. + /// Returns the updated emoji object on success. + /// See Modify Guild Emoji + /// + /// Client to use + /// Emoji ID to update + /// Emoji update + public IPromise EditEmoji(DiscordClient client, Snowflake emojiId, EmojiUpdate emoji) + { + if (emoji == null) throw new ArgumentNullException(nameof(emoji)); + InvalidSnowflakeException.ThrowIfInvalid(emojiId); + return client.Bot.Rest.Patch(client,$"guilds/{Id}/emojis/{emojiId}", emoji); + } - /// - /// Delete the given emoji. - /// Requires the MANAGE_EMOJIS permission. - /// See Delete Guild Emoji - /// - /// Client to use - /// Emoji ID to delete - public IPromise DeleteEmoji(DiscordClient client, Snowflake emojiId) - { - InvalidSnowflakeException.ThrowIfInvalid(emojiId, nameof(emojiId)); - return client.Bot.Rest.Delete(client,$"guilds/{Id}/emojis/{emojiId}"); - } + /// + /// Delete the given emoji. + /// Requires the MANAGE_EMOJIS permission. + /// See Delete Guild Emoji + /// + /// Client to use + /// Emoji ID to delete + public IPromise DeleteEmoji(DiscordClient client, Snowflake emojiId) + { + InvalidSnowflakeException.ThrowIfInvalid(emojiId); + return client.Bot.Rest.Delete(client,$"guilds/{Id}/emojis/{emojiId}"); + } - /// - /// Modifies the current user's voice state. - /// See Update Current User Voice State - /// - /// Client to use - /// Update to the guild voice state - public IPromise EditCurrentUserVoiceState(DiscordClient client, GuildCurrentUserVoiceStateUpdate update) - { - if (update == null) throw new ArgumentNullException(nameof(update)); - return client.Bot.Rest.Patch(client,$"guilds/{Id}/voice-states/@me", update); - } + /// + /// Modifies the current user's voice state. + /// See Update Current User Voice State + /// + /// Client to use + /// Update to the guild voice state + public IPromise EditCurrentUserVoiceState(DiscordClient client, GuildCurrentUserVoiceStateUpdate update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + return client.Bot.Rest.Patch(client,$"guilds/{Id}/voice-states/@me", update); + } - /// - /// Modifies another user's voice state. - /// See Update Users Voice State - /// - /// Client to use - /// User to modify - /// Update to the guild voice state - public IPromise EditUserVoiceState(DiscordClient client, Snowflake userId, GuildUserVoiceStateUpdate update) - { - if (update == null) throw new ArgumentNullException(nameof(update)); - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Patch(client,$"guilds/{Id}/voice-states/{userId}", update); - } + /// + /// Modifies another user's voice state. + /// See Update Users Voice State + /// + /// Client to use + /// User to modify + /// Update to the guild voice state + public IPromise EditUserVoiceState(DiscordClient client, Snowflake userId, GuildUserVoiceStateUpdate update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Patch(client,$"guilds/{Id}/voice-states/{userId}", update); + } - /// - /// Returns an array of sticker objects for the given guild. - /// Includes user fields if the bot has the MANAGE_EMOJIS_AND_STICKERS permission. - /// See List Guild Stickers - /// - /// Client to use - public IPromise> ListStickers(DiscordClient client) - { - return client.Bot.Rest.Get>(client,$"guilds/{Id}/stickers"); - } + /// + /// Returns an array of sticker objects for the given guild. + /// Includes user fields if the bot has the MANAGE_EMOJIS_AND_STICKERS permission. + /// See List Guild Stickers + /// + /// Client to use + public IPromise> ListStickers(DiscordClient client) + { + return client.Bot.Rest.Get>(client,$"guilds/{Id}/stickers"); + } - /// - /// Returns a sticker object for the given guild and sticker IDs. - /// Includes the user field if the bot has the MANAGE_EMOJIS_AND_STICKERS permission. - /// See Get Guild Sticker - /// - /// Client to use - /// ID of the sticker to get - public IPromise GetSticker(DiscordClient client, Snowflake stickerId) - { - InvalidSnowflakeException.ThrowIfInvalid(stickerId, nameof(stickerId)); - return client.Bot.Rest.Get(client,$"guilds/{Id}/stickers/{stickerId}"); - } + /// + /// Returns a sticker object for the given guild and sticker IDs. + /// Includes the user field if the bot has the MANAGE_EMOJIS_AND_STICKERS permission. + /// See Get Guild Sticker + /// + /// Client to use + /// ID of the sticker to get + public IPromise GetSticker(DiscordClient client, Snowflake stickerId) + { + InvalidSnowflakeException.ThrowIfInvalid(stickerId); + return client.Bot.Rest.Get(client,$"guilds/{Id}/stickers/{stickerId}"); + } - /// - /// Create a new sticker for the guild. - /// Requires the MANAGE_EMOJIS_AND_STICKERS permission. - /// Returns the new sticker object on success. - /// See Create Guild Sticker - /// - /// Client to use - /// Sticker to create - public IPromise CreateSticker(DiscordClient client, GuildStickerCreate sticker) - { - if (sticker == null) throw new ArgumentNullException(nameof(sticker)); - return client.Bot.Rest.Post(client,$"guilds/{Id}/stickers", sticker); - } + /// + /// Create a new sticker for the guild. + /// Requires the MANAGE_EMOJIS_AND_STICKERS permission. + /// Returns the new sticker object on success. + /// See Create Guild Sticker + /// + /// Client to use + /// Sticker to create + public IPromise CreateSticker(DiscordClient client, GuildStickerCreate sticker) + { + if (sticker == null) throw new ArgumentNullException(nameof(sticker)); + return client.Bot.Rest.Post(client,$"guilds/{Id}/stickers", sticker); + } - /// - /// Modify the given sticker. - /// Requires the MANAGE_EMOJIS_AND_STICKERS permission. - /// Returns the updated sticker object on success. - /// See Modify Guild Sticker - /// - /// Client to use - /// Sticker to modify - public IPromise EditSticker(DiscordClient client, DiscordSticker sticker) - { - if (sticker == null) throw new ArgumentNullException(nameof(sticker)); - return client.Bot.Rest.Patch(client,$"guilds/{Id}/stickers/{sticker.Id}", sticker); - } + /// + /// Modify the given sticker. + /// Requires the MANAGE_EMOJIS_AND_STICKERS permission. + /// Returns the updated sticker object on success. + /// See Modify Guild Sticker + /// + /// Client to use + /// Sticker to modify + public IPromise EditSticker(DiscordClient client, DiscordSticker sticker) + { + if (sticker == null) throw new ArgumentNullException(nameof(sticker)); + return client.Bot.Rest.Patch(client,$"guilds/{Id}/stickers/{sticker.Id}", sticker); + } - /// - /// Delete the given sticker. - /// Requires the MANAGE_EMOJIS_AND_STICKERS permission. - /// - /// Client to use - /// ID of the sticker to delete - /// See Delete Guild Sticker - public IPromise DeleteSticker(DiscordClient client, Snowflake stickerId) - { - InvalidSnowflakeException.ThrowIfInvalid(stickerId, nameof(stickerId)); - return client.Bot.Rest.Delete(client,$"guilds/{Id}/stickers/{stickerId}"); - } + /// + /// Delete the given sticker. + /// Requires the MANAGE_EMOJIS_AND_STICKERS permission. + /// + /// Client to use + /// ID of the sticker to delete + /// See Delete Guild Sticker + public IPromise DeleteSticker(DiscordClient client, Snowflake stickerId) + { + InvalidSnowflakeException.ThrowIfInvalid(stickerId); + return client.Bot.Rest.Delete(client,$"guilds/{Id}/stickers/{stickerId}"); + } - /// - public IPromise> ListAutoModRules(DiscordClient client) - => AutoModRule.GetAll(client, Id); + /// + public IPromise> ListAutoModRules(DiscordClient client) + => AutoModRule.GetAll(client, Id); - /// - public IPromise GetAutoModRule(DiscordClient client, Snowflake ruleId) - => AutoModRule.Get(client, Id, ruleId); + /// + public IPromise GetAutoModRule(DiscordClient client, Snowflake ruleId) + => AutoModRule.Get(client, Id, ruleId); - /// - public IPromise CreateAutoModRule(DiscordClient client, AutoModRuleCreate create) - => AutoModRule.Create(client, Id, create); + /// + public IPromise CreateAutoModRule(DiscordClient client, AutoModRuleCreate create) + => AutoModRule.Create(client, Id, create); - /// - /// Returns the for the guild. - /// - /// Client to use - /// See Get Guild Onboarding - public IPromise GetOnboarding(DiscordClient client) - { - return client.Bot.Rest.Get(client,$"guilds/{Id}/onboarding"); - } + /// + /// Returns the for the guild. + /// + /// Client to use + /// See Get Guild Onboarding + public IPromise GetOnboarding(DiscordClient client) + { + return client.Bot.Rest.Get(client,$"guilds/{Id}/onboarding"); + } - /// - /// Modifies the onboarding configuration of the guild. - /// - /// Client to use - /// Update for the guild onboarding - /// See Modify Guild Onboarding - public IPromise EditOnboarding(DiscordClient client, GuildOnboardingUpdate update) - { - return client.Bot.Rest.Put(client,$"guilds/{Id}/onboarding", update); - } - #endregion + /// + /// Modifies the onboarding configuration of the guild. + /// + /// Client to use + /// Update for the guild onboarding + /// See Modify Guild Onboarding + public IPromise EditOnboarding(DiscordClient client, GuildOnboardingUpdate update) + { + return client.Bot.Rest.Put(client,$"guilds/{Id}/onboarding", update); + } + #endregion - #region Entity Update Methods - internal DiscordGuild Edit(DiscordGuild updatedGuild) - { - DiscordGuild previous = (DiscordGuild)MemberwiseClone(); - if (updatedGuild.Name != null) - Name = updatedGuild.Name; - if (updatedGuild.Icon != null) - Icon = updatedGuild.Icon; - if (updatedGuild.IconHash != null) - IconHash = updatedGuild.IconHash; - if (updatedGuild.Splash != null) - Splash = updatedGuild.Splash; - if (updatedGuild.DiscoverySplash != null) - DiscoverySplash = updatedGuild.DiscoverySplash; - if(updatedGuild.OwnerId.IsValid()) - OwnerId = updatedGuild.OwnerId; - if (updatedGuild.AfkChannelId != null) - AfkChannelId = updatedGuild.AfkChannelId; - if (updatedGuild.AfkTimeout != null) - AfkTimeout = updatedGuild.AfkTimeout; - if (updatedGuild.WidgetEnabled != null) - WidgetEnabled = updatedGuild.WidgetEnabled; - if (updatedGuild.WidgetChannelId != null) - WidgetChannelId = updatedGuild.WidgetChannelId; - VerificationLevel = updatedGuild.VerificationLevel; - DefaultMessageNotifications = updatedGuild.DefaultMessageNotifications; - ExplicitContentFilter = updatedGuild.ExplicitContentFilter; - if (updatedGuild.Roles != null) - Roles = updatedGuild.Roles; - if (updatedGuild.Emojis != null) - Emojis = updatedGuild.Emojis; - if (updatedGuild.Features != null) - Features = updatedGuild.Features; - if (updatedGuild.MfaLevel != null) - MfaLevel = updatedGuild.MfaLevel; - if (updatedGuild.ApplicationId != null) - ApplicationId = updatedGuild.ApplicationId; - if (updatedGuild.SystemChannelId != null) - SystemChannelId = updatedGuild.SystemChannelId; - SystemChannelFlags = updatedGuild.SystemChannelFlags; - if (RulesChannelId != null) - RulesChannelId = updatedGuild.RulesChannelId; - if (updatedGuild.JoinedAt != null) - JoinedAt = updatedGuild.JoinedAt; - if (updatedGuild.Large != null) - Large = updatedGuild.Large; - if (updatedGuild.Unavailable != null && (!Unavailable.HasValue || Unavailable.Value)) - Unavailable = updatedGuild.Unavailable; - if (updatedGuild.MemberCount != null) - MemberCount = updatedGuild.MemberCount; - if (updatedGuild.VoiceStates != null) - VoiceStates = updatedGuild.VoiceStates; - if (updatedGuild.Members != null) - Members = updatedGuild.Members; - if (updatedGuild.Channels != null) - Channels = updatedGuild.Channels; - if (updatedGuild.Threads != null) - Threads = updatedGuild.Threads; - if (updatedGuild.Presences != null) - Presences = updatedGuild.Presences; - if (updatedGuild.MaxPresences != null) - MaxPresences = updatedGuild.MaxPresences; - if (updatedGuild.MaxMembers != null) - MaxMembers = updatedGuild.MaxMembers; - if (updatedGuild.VanityUrlCode != null) - VanityUrlCode = updatedGuild.VanityUrlCode; - if (updatedGuild.Description != null) - Description = updatedGuild.Description; - if (updatedGuild.Banner != null) - Banner = updatedGuild.Banner; - if (updatedGuild.PremiumTier != null) - PremiumTier = updatedGuild.PremiumTier; - if (updatedGuild.PremiumSubscriptionCount != null) - PremiumSubscriptionCount = updatedGuild.PremiumSubscriptionCount; - if (updatedGuild.PreferredLocale != null) - PreferredLocale = updatedGuild.PreferredLocale; - if (updatedGuild.PublicUpdatesChannelId != null) - PublicUpdatesChannelId = updatedGuild.PublicUpdatesChannelId; - if (updatedGuild.MaxVideoChannelUsers != null) - MaxVideoChannelUsers = updatedGuild.MaxVideoChannelUsers; - if (updatedGuild.ApproximateMemberCount != null) - ApproximateMemberCount = updatedGuild.ApproximateMemberCount; - if (updatedGuild.ApproximatePresenceCount != null) - ApproximatePresenceCount = updatedGuild.ApproximatePresenceCount; - if (updatedGuild.WelcomeScreen != null) - WelcomeScreen = updatedGuild.WelcomeScreen; - NsfwLevel = updatedGuild.NsfwLevel; - if (updatedGuild.StageInstances != null) - StageInstances = updatedGuild.StageInstances; - if (updatedGuild.Stickers != null) - Stickers = updatedGuild.Stickers; - if (updatedGuild.ScheduledEvents != null) - ScheduledEvents = updatedGuild.ScheduledEvents; - PremiumProgressBarEnabled = updatedGuild.PremiumProgressBarEnabled; - if (updatedGuild.SafetyAlertsChannelId != null) - SafetyAlertsChannelId = updatedGuild.SafetyAlertsChannelId; - return previous; - } - #endregion + #region Entity Update Methods + internal DiscordGuild Edit(DiscordGuild updatedGuild) + { + DiscordGuild previous = (DiscordGuild)MemberwiseClone(); + if (updatedGuild.Name != null) + Name = updatedGuild.Name; + if (updatedGuild.Icon != null) + Icon = updatedGuild.Icon; + if (updatedGuild.IconHash != null) + IconHash = updatedGuild.IconHash; + if (updatedGuild.Splash != null) + Splash = updatedGuild.Splash; + if (updatedGuild.DiscoverySplash != null) + DiscoverySplash = updatedGuild.DiscoverySplash; + if(updatedGuild.OwnerId.IsValid()) + OwnerId = updatedGuild.OwnerId; + if (updatedGuild.AfkChannelId != null) + AfkChannelId = updatedGuild.AfkChannelId; + if (updatedGuild.AfkTimeout != null) + AfkTimeout = updatedGuild.AfkTimeout; + if (updatedGuild.WidgetEnabled != null) + WidgetEnabled = updatedGuild.WidgetEnabled; + if (updatedGuild.WidgetChannelId != null) + WidgetChannelId = updatedGuild.WidgetChannelId; + VerificationLevel = updatedGuild.VerificationLevel; + DefaultMessageNotifications = updatedGuild.DefaultMessageNotifications; + ExplicitContentFilter = updatedGuild.ExplicitContentFilter; + if (updatedGuild.Roles != null) + Roles = updatedGuild.Roles; + if (updatedGuild.Emojis != null) + Emojis = updatedGuild.Emojis; + if (updatedGuild.Features != null) + Features = updatedGuild.Features; + if (updatedGuild.MfaLevel != null) + MfaLevel = updatedGuild.MfaLevel; + if (updatedGuild.ApplicationId != null) + ApplicationId = updatedGuild.ApplicationId; + if (updatedGuild.SystemChannelId != null) + SystemChannelId = updatedGuild.SystemChannelId; + SystemChannelFlags = updatedGuild.SystemChannelFlags; + if (RulesChannelId != null) + RulesChannelId = updatedGuild.RulesChannelId; + if (updatedGuild.JoinedAt != null) + JoinedAt = updatedGuild.JoinedAt; + if (updatedGuild.Large != null) + Large = updatedGuild.Large; + if (updatedGuild.Unavailable != null && (!Unavailable.HasValue || Unavailable.Value)) + Unavailable = updatedGuild.Unavailable; + if (updatedGuild.MemberCount != null) + MemberCount = updatedGuild.MemberCount; + if (updatedGuild.VoiceStates != null) + VoiceStates = updatedGuild.VoiceStates; + if (updatedGuild.Members != null) + Members = updatedGuild.Members; + if (updatedGuild.Channels != null) + Channels = updatedGuild.Channels; + if (updatedGuild.Threads != null) + Threads = updatedGuild.Threads; + if (updatedGuild.Presences != null) + Presences = updatedGuild.Presences; + if (updatedGuild.MaxPresences != null) + MaxPresences = updatedGuild.MaxPresences; + if (updatedGuild.MaxMembers != null) + MaxMembers = updatedGuild.MaxMembers; + if (updatedGuild.VanityUrlCode != null) + VanityUrlCode = updatedGuild.VanityUrlCode; + if (updatedGuild.Description != null) + Description = updatedGuild.Description; + if (updatedGuild.Banner != null) + Banner = updatedGuild.Banner; + if (updatedGuild.PremiumTier != null) + PremiumTier = updatedGuild.PremiumTier; + if (updatedGuild.PremiumSubscriptionCount != null) + PremiumSubscriptionCount = updatedGuild.PremiumSubscriptionCount; + if (updatedGuild.PreferredLocale != null) + PreferredLocale = updatedGuild.PreferredLocale; + if (updatedGuild.PublicUpdatesChannelId != null) + PublicUpdatesChannelId = updatedGuild.PublicUpdatesChannelId; + if (updatedGuild.MaxVideoChannelUsers != null) + MaxVideoChannelUsers = updatedGuild.MaxVideoChannelUsers; + if (updatedGuild.ApproximateMemberCount != null) + ApproximateMemberCount = updatedGuild.ApproximateMemberCount; + if (updatedGuild.ApproximatePresenceCount != null) + ApproximatePresenceCount = updatedGuild.ApproximatePresenceCount; + if (updatedGuild.WelcomeScreen != null) + WelcomeScreen = updatedGuild.WelcomeScreen; + NsfwLevel = updatedGuild.NsfwLevel; + if (updatedGuild.StageInstances != null) + StageInstances = updatedGuild.StageInstances; + if (updatedGuild.Stickers != null) + Stickers = updatedGuild.Stickers; + if (updatedGuild.ScheduledEvents != null) + ScheduledEvents = updatedGuild.ScheduledEvents; + PremiumProgressBarEnabled = updatedGuild.PremiumProgressBarEnabled; + if (updatedGuild.SafetyAlertsChannelId != null) + SafetyAlertsChannelId = updatedGuild.SafetyAlertsChannelId; + return previous; } -} + #endregion +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ExplicitContentFilterLevel.cs b/Oxide.Ext.Discord/Entities/Guilds/ExplicitContentFilterLevel.cs index 3d96cab83..69d67d88c 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ExplicitContentFilterLevel.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ExplicitContentFilterLevel.cs @@ -1,28 +1,27 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Explicit Content Filter Level +/// +public enum ExplicitContentFilterLevel : byte { /// - /// Represents Explicit Content Filter Level + /// Disable explicit content filter /// - public enum ExplicitContentFilterLevel : byte - { - /// - /// Disable explicit content filter - /// - [DiscordEnum("DISABLED")] - Disabled = 0, + [DiscordEnum("DISABLED")] + Disabled = 0, - /// - /// Filter for only members without roles - /// - [DiscordEnum("MEMBERS_WITHOUT_ROLES")] - MembersWithoutRoles = 1, + /// + /// Filter for only members without roles + /// + [DiscordEnum("MEMBERS_WITHOUT_ROLES")] + MembersWithoutRoles = 1, - /// - /// Filter for all members - /// - [DiscordEnum("ALL_MEMBERS")] - AllMembers = 2 - } + /// + /// Filter for all members + /// + [DiscordEnum("ALL_MEMBERS")] + AllMembers = 2 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildBan.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildBan.cs index 7caff6f31..5dbab320c 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildBan.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildBan.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Ban Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildBan { /// - /// Represents Guild Ban Structure + /// The reason for the ban /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildBan - { - /// - /// The reason for the ban - /// - [JsonProperty("reason")] - public string Reason { get; set; } + [JsonProperty("reason")] + public string Reason { get; set; } - /// - /// The banned user - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } - } -} + /// + /// The banned user + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildBanCreate.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildBanCreate.cs index 77c118186..72b638801 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildBanCreate.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildBanCreate.cs @@ -2,24 +2,23 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Ban Create Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildBanCreate : IDiscordValidation { /// - /// Represents Guild Ban Create Structure + /// Number of seconds to delete messages for, between 0 and 604800 (7 days) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildBanCreate : IDiscordValidation - { - /// - /// Number of seconds to delete messages for, between 0 and 604800 (7 days) - /// - [JsonProperty("delete_message_seconds")] - public int? DeleteMessageSeconds { get; set; } + [JsonProperty("delete_message_seconds")] + public int? DeleteMessageSeconds { get; set; } - /// - public void Validate() - { - InvalidGuildBanException.ThrowIfInvalidDeleteMessageSeconds(DeleteMessageSeconds); - } + /// + public void Validate() + { + InvalidGuildBanException.ThrowIfInvalidDeleteMessageSeconds(DeleteMessageSeconds); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildBansRequest.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildBansRequest.cs index 27061b0f0..fe56ee3e6 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildBansRequest.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildBansRequest.cs @@ -1,49 +1,47 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Get Guild Bans Query String Params +/// +public class GuildBansRequest : IDiscordQueryString { /// - /// Represents a Get Guild Bans Query String Params + /// Number of users to return (up to maximum 1000) /// - public class GuildBansRequest : IDiscordQueryString - { - /// - /// Number of users to return (up to maximum 1000) - /// - public int? Limit { get; set; } = 1000; + public int? Limit { get; set; } = 1000; - /// - /// Get bans before this user ID - /// - public Snowflake? Before { get; set; } + /// + /// Get bans before this user ID + /// + public Snowflake? Before { get; set; } - /// - /// Get bans after this user ID - /// - public Snowflake? After { get; set; } + /// + /// Get bans after this user ID + /// + public Snowflake? After { get; set; } - /// - public string ToQueryString() - { - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); + /// + public string ToQueryString() + { + QueryStringBuilder builder = new(); - if (Limit.HasValue) - { - builder.Add("limit", Limit.Value.ToString()); - } - - if (Before.HasValue) - { - builder.Add("before", Before.Value.ToString()); - } - else if (After.HasValue) - { - builder.Add("after", After.Value.ToString()); - } + if (Limit.HasValue) + { + builder.Add("limit", Limit.Value.ToString()); + } - return builder.ToStringAndFree(); + if (Before.HasValue) + { + builder.Add("before", Before.Value.ToString()); } + else if (After.HasValue) + { + builder.Add("after", After.Value.ToString()); + } + + return builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildChannelPosition.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildChannelPosition.cs index 4b6aed8ef..bbf900bea 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildChannelPosition.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildChannelPosition.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Modify Guild Channel Position +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildChannelPosition { /// - /// Represents Modify Guild Channel Position + /// ID of the channel or role /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildChannelPosition - { - /// - /// ID of the channel or role - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// New position for the role / channel - /// - [JsonProperty("position")] - public int Position { get; set; } - } -} + /// + /// New position for the role / channel + /// + [JsonProperty("position")] + public int Position { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildCreate.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildCreate.cs index e83d80c72..da5ae2417 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildCreate.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildCreate.cs @@ -3,86 +3,85 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Create Guild Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildCreate : IDiscordValidation { /// - /// Represents Create Guild Structure + /// Name of the guild (2-100 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildCreate : IDiscordValidation - { - /// - /// Name of the guild (2-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Base64 128x128 image for the guild icon - /// - [JsonProperty("icon")] - public DiscordImageData? Icon { get; set; } + /// + /// Base64 128x128 image for the guild icon + /// + [JsonProperty("icon")] + public DiscordImageData? Icon { get; set; } - /// - /// Verification level - /// - [JsonProperty("verification_level")] - public GuildVerificationLevel? VerificationLevel { get; set; } + /// + /// Verification level + /// + [JsonProperty("verification_level")] + public GuildVerificationLevel? VerificationLevel { get; set; } - /// - /// Default message notification level - /// - [JsonProperty("default_message_notifications")] - public DefaultNotificationLevel? DefaultMessageNotifications { get; set; } + /// + /// Default message notification level + /// + [JsonProperty("default_message_notifications")] + public DefaultNotificationLevel? DefaultMessageNotifications { get; set; } - /// - /// Explicit content filter level - /// - [JsonProperty("explicit_content_filter")] - public ExplicitContentFilterLevel? ExplicitContentFilter { get; set; } + /// + /// Explicit content filter level + /// + [JsonProperty("explicit_content_filter")] + public ExplicitContentFilterLevel? ExplicitContentFilter { get; set; } - /// - /// Roles in the guild - /// - [JsonProperty("roles")] - public List Roles { get; set; } + /// + /// Roles in the guild + /// + [JsonProperty("roles")] + public List Roles { get; set; } - /// - /// Channels in the guild - /// - [JsonProperty("channels")] - public List Channels { get; set; } + /// + /// Channels in the guild + /// + [JsonProperty("channels")] + public List Channels { get; set; } - /// - /// ID of afk channel - /// - [JsonProperty("afk_channel_id")] - public Snowflake? AfkChannelId { get; set; } + /// + /// ID of afk channel + /// + [JsonProperty("afk_channel_id")] + public Snowflake? AfkChannelId { get; set; } - /// - /// Afk timeout in seconds - /// Can be set to: null, 60, 300, 900, 1800, 3600 - /// - [JsonProperty("afk_timeout")] - public int? AfkTimeout { get; set; } + /// + /// Afk timeout in seconds + /// Can be set to: null, 60, 300, 900, 1800, 3600 + /// + [JsonProperty("afk_timeout")] + public int? AfkTimeout { get; set; } - /// - /// The id of the channel where guild notices such as welcome messages and boost events are posted - /// - [JsonProperty("system_channel_id")] - public Snowflake? SystemChannelId { get; set; } + /// + /// The id of the channel where guild notices such as welcome messages and boost events are posted + /// + [JsonProperty("system_channel_id")] + public Snowflake? SystemChannelId { get; set; } - /// - /// System channel flags - /// - [JsonProperty("system_channel_flags")] - public SystemChannelFlags? SystemChannelFlags { get; set; } + /// + /// System channel flags + /// + [JsonProperty("system_channel_flags")] + public SystemChannelFlags? SystemChannelFlags { get; set; } - /// - public void Validate() - { - InvalidGuildException.ThrowIfInvalidName(Name, false); - InvalidImageDataException.ThrowIfInvalidImageData(Icon); - } + /// + public void Validate() + { + InvalidGuildException.ThrowIfInvalidName(Name, false); + InvalidImageDataException.ThrowIfInvalidImageData(Icon); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildCurrentUserVoiceStateUpdate.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildCurrentUserVoiceStateUpdate.cs index 3874407a4..7c7ad68ff 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildCurrentUserVoiceStateUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildCurrentUserVoiceStateUpdate.cs @@ -3,35 +3,34 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Modify Current User Voice State +/// +public class GuildCurrentUserVoiceStateUpdate : IDiscordValidation { /// - /// Represents a Modify Current User Voice State + /// The id of the channel the user is currently in /// - public class GuildCurrentUserVoiceStateUpdate : IDiscordValidation - { - /// - /// The id of the channel the user is currently in - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } - /// - /// Toggles the user's suppress state - /// - [JsonProperty("suppress")] - public bool Suppress { get; set; } + /// + /// Toggles the user's suppress state + /// + [JsonProperty("suppress")] + public bool Suppress { get; set; } - /// - /// Sets the user's request to speak - /// - [JsonProperty("request_to_speak_timestamp")] - public DateTime RequestToSpeakTimestamp { get; set; } + /// + /// Sets the user's request to speak + /// + [JsonProperty("request_to_speak_timestamp")] + public DateTime RequestToSpeakTimestamp { get; set; } - /// - public void Validate() - { - InvalidSnowflakeException.ThrowIfInvalid(ChannelId, nameof(ChannelId)); - } + /// + public void Validate() + { + InvalidSnowflakeException.ThrowIfInvalid(ChannelId); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildFeatures.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildFeatures.cs index a1f28f950..f22ede089 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildFeatures.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildFeatures.cs @@ -2,179 +2,178 @@ using Oxide.Ext.Discord.Attributes; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Features +/// +[JsonConverter(typeof(DiscordEnumConverter))] +public enum GuildFeatures : byte { /// - /// Represents Guild Features - /// - [JsonConverter(typeof(DiscordEnumConverter))] - public enum GuildFeatures : byte - { - /// - /// Discord Extension doesn't currently support a guild features - /// - Unknown, - - /// - /// Guild has access to set an animated guild banner image - /// - [DiscordEnum("ANIMATED_BANNER")] - AnimatedBanner, - - /// - /// Guild has access to set an animated guild icon - /// - [DiscordEnum("ANIMATED_ICON")] - AnimatedIcon, - - /// - /// Guild is using the old permissions configuration behavior - /// - [DiscordEnum("APPLICATION_COMMAND_PERMISSIONS_V2")] - ApplicationCommandPermissionsV2, - - /// - /// Guild has set up auto moderation rules - /// - [DiscordEnum("AUTO_MODERATION")] - AutoModeration, - - /// - /// Guild has access to set a guild banner image - /// - [DiscordEnum("BANNER")] - Banner, + /// Discord Extension doesn't currently support a guild features + /// + Unknown, + + /// + /// Guild has access to set an animated guild banner image + /// + [DiscordEnum("ANIMATED_BANNER")] + AnimatedBanner, + + /// + /// Guild has access to set an animated guild icon + /// + [DiscordEnum("ANIMATED_ICON")] + AnimatedIcon, + + /// + /// Guild is using the old permissions configuration behavior + /// + [DiscordEnum("APPLICATION_COMMAND_PERMISSIONS_V2")] + ApplicationCommandPermissionsV2, + + /// + /// Guild has set up auto moderation rules + /// + [DiscordEnum("AUTO_MODERATION")] + AutoModeration, + + /// + /// Guild has access to set a guild banner image + /// + [DiscordEnum("BANNER")] + Banner, - /// - /// Guild can enable welcome screen and discovery, and receives community updates - /// - [DiscordEnum("COMMUNITY")] - Community, - - /// - /// Guild has enabled monetization - /// - [DiscordEnum("CREATOR_MONETIZABLE_PROVISIONAL")] - CreatorMonetizableProvisional, - - /// - /// Guild has enabled the role subscription promo page - /// - [DiscordEnum("CREATOR_STORE_PAGE")] - CreatorStorePage, - - /// - /// Guild has been set as a support server on the App Directory - /// - [DiscordEnum("DEVELOPER_SUPPORT_SERVER")] - DeveloperSupportServer, - - /// - /// Guild is lurkable and able to be discovered in the directory - /// - [DiscordEnum("DISCOVERABLE")] - Discoverable, - - /// - /// Guild is able to be featured in the directory - /// - [DiscordEnum("FEATURABLE")] - Featurable, - - /// - /// Guild has paused invites, preventing new users from joining - /// - [DiscordEnum("INVITES_DISABLED")] - InvitesDisabled, - - /// - /// Guild has access to set an invite splash background - /// - [DiscordEnum("INVITE_SPLASH")] - InviteSplash, - - /// - /// Guild has enabled Membership Screening - /// - [DiscordEnum("MEMBER_VERIFICATION_GATE_ENABLED")] - MemberVerificationGateEnabled, - - /// - /// Guild has increased custom sticker slots - /// - [DiscordEnum("MORE_STICKERS")] - MoreStickers, + /// + /// Guild can enable welcome screen and discovery, and receives community updates + /// + [DiscordEnum("COMMUNITY")] + Community, + + /// + /// Guild has enabled monetization + /// + [DiscordEnum("CREATOR_MONETIZABLE_PROVISIONAL")] + CreatorMonetizableProvisional, + + /// + /// Guild has enabled the role subscription promo page + /// + [DiscordEnum("CREATOR_STORE_PAGE")] + CreatorStorePage, + + /// + /// Guild has been set as a support server on the App Directory + /// + [DiscordEnum("DEVELOPER_SUPPORT_SERVER")] + DeveloperSupportServer, + + /// + /// Guild is lurkable and able to be discovered in the directory + /// + [DiscordEnum("DISCOVERABLE")] + Discoverable, + + /// + /// Guild is able to be featured in the directory + /// + [DiscordEnum("FEATURABLE")] + Featurable, + + /// + /// Guild has paused invites, preventing new users from joining + /// + [DiscordEnum("INVITES_DISABLED")] + InvitesDisabled, + + /// + /// Guild has access to set an invite splash background + /// + [DiscordEnum("INVITE_SPLASH")] + InviteSplash, + + /// + /// Guild has enabled Membership Screening + /// + [DiscordEnum("MEMBER_VERIFICATION_GATE_ENABLED")] + MemberVerificationGateEnabled, + + /// + /// Guild has increased custom sticker slots + /// + [DiscordEnum("MORE_STICKERS")] + MoreStickers, - /// - /// Guild has access to create news channels - /// - [DiscordEnum("NEWS")] - News, - - /// - /// Guild is partnered - /// - [DiscordEnum("PARTNERED")] - Partnered, - - /// - /// Guild can be previewed before joining via Membership Screening or the directory - /// - [DiscordEnum("PREVIEW_ENABLED")] - PreviewEnabled, - - /// - /// Guild has disabled alerts for join raids in the configured safety alerts channel - /// - [DiscordEnum("RAID_ALERTS_DISABLED")] - RaidAlertsDisabled, - - /// - /// Guild can be previewed before joining via Membership Screening or the directory - /// - [DiscordEnum("ROLE_ICONS")] - RoleIcons, + /// + /// Guild has access to create news channels + /// + [DiscordEnum("NEWS")] + News, + + /// + /// Guild is partnered + /// + [DiscordEnum("PARTNERED")] + Partnered, + + /// + /// Guild can be previewed before joining via Membership Screening or the directory + /// + [DiscordEnum("PREVIEW_ENABLED")] + PreviewEnabled, + + /// + /// Guild has disabled alerts for join raids in the configured safety alerts channel + /// + [DiscordEnum("RAID_ALERTS_DISABLED")] + RaidAlertsDisabled, + + /// + /// Guild can be previewed before joining via Membership Screening or the directory + /// + [DiscordEnum("ROLE_ICONS")] + RoleIcons, - /// - /// Guild has role subscriptions that can be purchased - /// - [DiscordEnum("ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE")] - RoleSubscriptionsAvailableForPurchase, - - /// - /// Guild has enabled role subscriptions - /// - [DiscordEnum("ROLE_SUBSCRIPTIONS_ENABLED")] - RoleSubscriptionsEnabled, - - /// - /// Guild has enabled ticketed events - /// - [DiscordEnum("TICKETED_EVENTS_ENABLED")] - TicketedEventsEnabled, - - /// - /// Guild has access to set a vanity URL - /// - [DiscordEnum("VANITY_URL")] - VanityUrl, - - /// - /// Guild is verified - /// - [DiscordEnum("VERIFIED")] - Verified, - - /// - /// Guild has access to set 384kbps bitrate in voice (previously VIP voice servers) - /// - [DiscordEnum("VIP_REGIONS")] - VipRegions, - - /// - /// Guild has enabled the welcome screen - /// - [DiscordEnum("WELCOME_SCREEN_ENABLED")] - WelcomeScreenEnabled, - } + /// + /// Guild has role subscriptions that can be purchased + /// + [DiscordEnum("ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE")] + RoleSubscriptionsAvailableForPurchase, + + /// + /// Guild has enabled role subscriptions + /// + [DiscordEnum("ROLE_SUBSCRIPTIONS_ENABLED")] + RoleSubscriptionsEnabled, + + /// + /// Guild has enabled ticketed events + /// + [DiscordEnum("TICKETED_EVENTS_ENABLED")] + TicketedEventsEnabled, + + /// + /// Guild has access to set a vanity URL + /// + [DiscordEnum("VANITY_URL")] + VanityUrl, + + /// + /// Guild is verified + /// + [DiscordEnum("VERIFIED")] + Verified, + + /// + /// Guild has access to set 384kbps bitrate in voice (previously VIP voice servers) + /// + [DiscordEnum("VIP_REGIONS")] + VipRegions, + + /// + /// Guild has enabled the welcome screen + /// + [DiscordEnum("WELCOME_SCREEN_ENABLED")] + WelcomeScreenEnabled, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildListMembers.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildListMembers.cs index 014e5d84f..aa3201e03 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildListMembers.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildListMembers.cs @@ -1,48 +1,46 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a List Guild Members Stucture +/// +public class GuildListMembers : IDiscordQueryString, IDiscordValidation { /// - /// Represents a List Guild Members Stucture + /// Max number of members to return (1-1000) + /// Default is 1 /// - public class GuildListMembers : IDiscordQueryString, IDiscordValidation - { - /// - /// Max number of members to return (1-1000) - /// Default is 1 - /// - public int? Limit { get; set; } + public int? Limit { get; set; } - /// - /// The highest user id in the previous page - /// - public Snowflake? After { get; set; } + /// + /// The highest user id in the previous page + /// + public Snowflake? After { get; set; } - /// - public string ToQueryString() + /// + public string ToQueryString() + { + Validate(); + QueryStringBuilder builder = new(); + if (Limit.HasValue) { - Validate(); - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); - if (Limit.HasValue) - { - builder.Add("limit", Limit.Value.ToString()); - } - - if (After.HasValue) - { - builder.Add("after", After.Value.ToString()); - } - - return builder.ToStringAndFree(); + builder.Add("limit", Limit.Value.ToString()); } - /// - public void Validate() + if (After.HasValue) { - InvalidGuildListMembersException.ThrowIfInvalidLimit(Limit); + builder.Add("after", After.Value.ToString()); } + + return builder.ToString(); + } + + /// + public void Validate() + { + InvalidGuildListMembersException.ThrowIfInvalidLimit(Limit); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildMFALevel.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildMFALevel.cs index b3325ee50..d154b437c 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildMFALevel.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildMFALevel.cs @@ -1,22 +1,21 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents MFA Level +/// +public enum GuildMfaLevel : byte { /// - /// Represents MFA Level + /// Guild does not require MFA /// - public enum GuildMfaLevel : byte - { - /// - /// Guild does not require MFA - /// - [DiscordEnum("NONE")] - None = 0, + [DiscordEnum("NONE")] + None = 0, - /// - /// Guild requires elevated MFA - /// - [DiscordEnum("ELEVATED")] - Elevated = 1 - } -} + /// + /// Guild requires elevated MFA + /// + [DiscordEnum("ELEVATED")] + Elevated = 1 +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildMember.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildMember.cs index 89087f46f..2d8a52f8c 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildMember.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildMember.cs @@ -4,141 +4,146 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Member Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildMember : ISnowflakeEntity { + #region Discord Fields /// - /// Represents Guild Member Structure + /// Id for guild member /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildMember : ISnowflakeEntity - { - #region Discord Fields - /// - /// Id for guild member - /// - public Snowflake Id => User?.Id ?? default(Snowflake); + public Snowflake Id => User?.Id ?? default(Snowflake); - /// - /// The user this guild member represents - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } + /// + /// The user this guild member represents + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } - /// - /// This users guild nickname - /// - [JsonProperty("nick")] - public string Nickname { get; set; } + /// + /// This users guild nickname + /// + [JsonProperty("nick")] + public string Nickname { get; set; } - /// - /// The member's guild avatar hash - /// - [JsonProperty("avatar")] - public string Avatar { get; set; } + /// + /// The member's guild avatar hash + /// + [JsonProperty("avatar")] + public string Avatar { get; set; } - /// - /// List of member roles - /// - [JsonProperty("roles")] - public List Roles { get; set; } + /// + /// List of member roles + /// + [JsonProperty("roles")] + public List Roles { get; set; } - /// - /// When the user joined the guild - /// - [JsonProperty("joined_at")] - public DateTime? JoinedAt { get; set; } + /// + /// When the user joined the guild + /// + [JsonProperty("joined_at")] + public DateTime? JoinedAt { get; set; } - /// - /// When the user started boosting the guild - /// - [JsonProperty("premium_since")] - public DateTime? PremiumSince { get; set; } + /// + /// When the user started boosting the guild + /// + [JsonProperty("premium_since")] + public DateTime? PremiumSince { get; set; } - /// - /// Total permissions of the member in the channel, including overrides, returned when in the interaction object - /// - [JsonConverter(typeof(PermissionFlagsStringConverter))] - [JsonProperty("permissions")] - public PermissionFlags? Permissions { get; set; } + /// + /// Total permissions of the member in the channel, including overrides, returned when in the interaction object + /// + [JsonConverter(typeof(PermissionFlagsStringConverter))] + [JsonProperty("permissions")] + public PermissionFlags? Permissions { get; set; } - /// - /// Whether the user is deafened in voice channels - /// - [JsonProperty("deaf")] - public bool Deaf { get; set; } + /// + /// Whether the user is deafened in voice channels + /// + [JsonProperty("deaf")] + public bool Deaf { get; set; } - /// - /// Whether the user is muted in voice channels - /// - [JsonProperty("mute")] - public bool Mute { get; set; } + /// + /// Whether the user is muted in voice channels + /// + [JsonProperty("mute")] + public bool Mute { get; set; } - /// - /// Flags for the GuildMember - /// - [JsonProperty("flags")] - public GuildMemberFlags Flags { get; set; } + /// + /// Flags for the GuildMember + /// + [JsonProperty("flags")] + public GuildMemberFlags Flags { get; set; } - /// - /// Whether the user has not yet passed the guild's Membership Screening requirements - /// - [JsonProperty("pending")] - public bool? Pending { get; set; } + /// + /// Whether the user has not yet passed the guild's Membership Screening requirements + /// + [JsonProperty("pending")] + public bool? Pending { get; set; } + + /// + /// When the user's timeout will expire and the user will be able to communicate in the guild again, null or a time in the past if the user is not timed out + /// + [JsonProperty("communication_disabled_until")] + public DateTime? CommunicationDisabledUntil { get; set; } - /// - /// When the user's timeout will expire and the user will be able to communicate in the guild again, null or a time in the past if the user is not timed out - /// - [JsonProperty("communication_disabled_until")] - public DateTime? CommunicationDisabledUntil { get; set; } - #endregion + /// + /// Data for the member's guild avatar decoration + /// + [JsonProperty("avatar_decoration_data")] + public AvatarDecorationData AvatarDecoration { get; set; } + #endregion - #region Extension Fields - /// - /// When the Nickname was last updated UTC. Null if we haven't seen a nickname update yet - /// - public DateTime? NickNameLastUpdated { get; internal set; } + #region Extension Fields + /// + /// When the Nickname was last updated UTC. Null if we haven't seen a nickname update yet + /// + public DateTime? NickNameLastUpdated { get; internal set; } - /// - /// Returns if the has left the it belongs to - /// - public bool HasLeftGuild { get; internal set; } - #endregion + /// + /// Returns if the has left the it belongs to + /// + public bool HasLeftGuild { get; internal set; } + #endregion - #region Helper Properties - /// - /// Returns the display name show for the user in a guild - /// - public string DisplayName => string.IsNullOrEmpty(Nickname) ? User?.DisplayName : Nickname; + #region Helper Properties + /// + /// Returns the display name show for the user in a guild + /// + public string DisplayName => string.IsNullOrEmpty(Nickname) ? User?.DisplayName : Nickname; - /// - /// Returns if the GuildMember is a bot - /// - public bool IsBot => User.Bot.HasValue && User.Bot.Value; - #endregion + /// + /// Returns if the GuildMember is a bot + /// + public bool IsBot => User.Bot.HasValue && User.Bot.Value; + #endregion - #region Helper Methods - /// - /// Returns if member has the given role - /// - /// Role to check - /// Return true if has role; False otherwise; - /// Thrown if role is null - public bool HasRole(DiscordRole role) + #region Helper Methods + /// + /// Returns if member has the given role + /// + /// Role to check + /// Return true if has role; False otherwise; + /// Thrown if role is null + public bool HasRole(DiscordRole role) + { + if (role == null) { - if (role == null) - { - throw new ArgumentNullException(nameof(role)); - } - - return HasRole(role.Id); + throw new ArgumentNullException(nameof(role)); } - - /// - /// Returns if member has the given role - /// - /// Role ID to check - /// Return true if has role; False otherwise; - public bool HasRole(Snowflake roleId) => Roles.Contains(roleId); - #endregion + + return HasRole(role.Id); } -} + + /// + /// Returns if member has the given role + /// + /// Role ID to check + /// Return true if has role; False otherwise; + public bool HasRole(Snowflake roleId) => Roles.Contains(roleId); + #endregion +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildMemberAdd.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildMemberAdd.cs index 3163f5d15..d5f38fc56 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildMemberAdd.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildMemberAdd.cs @@ -1,46 +1,45 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Member Add +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildMemberAdd { /// - /// Represents Guild Member Add + /// An oauth2 access token granted with the guilds.join to the bot's application for the user you want to add to the guild /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildMemberAdd - { - /// - /// An oauth2 access token granted with the guilds.join to the bot's application for the user you want to add to the guild - /// - [JsonProperty("access_token")] - public string AccessToken { get; set; } + [JsonProperty("access_token")] + public string AccessToken { get; set; } - /// - /// Value to set users nickname to - /// Requires permission MANAGE_NICKNAMES - /// - [JsonProperty("nick")] - public string Nick { get; set; } + /// + /// Value to set users nickname to + /// Requires permission MANAGE_NICKNAMES + /// + [JsonProperty("nick")] + public string Nick { get; set; } - /// - /// Role ids the member is assigned - /// Requires permission MANAGE_ROLES - /// - [JsonProperty("roles")] - public List Roles { get; set; } + /// + /// Role ids the member is assigned + /// Requires permission MANAGE_ROLES + /// + [JsonProperty("roles")] + public List Roles { get; set; } - /// - /// Whether the user is muted in voice channels - /// Requires permission MUTE_MEMBERS - /// - [JsonProperty("mute")] - public bool Mute { get; set; } + /// + /// Whether the user is muted in voice channels + /// Requires permission MUTE_MEMBERS + /// + [JsonProperty("mute")] + public bool Mute { get; set; } - /// - /// Whether the user is deafened in voice channels - /// Requires permission DEAFEN_MEMBERS - /// - [JsonProperty("deaf")] - public bool Deaf { get; set; } - } + /// + /// Whether the user is deafened in voice channels + /// Requires permission DEAFEN_MEMBERS + /// + [JsonProperty("deaf")] + public bool Deaf { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildMemberFlags.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildMemberFlags.cs index 36280b559..4e54e6b04 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildMemberFlags.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildMemberFlags.cs @@ -1,45 +1,44 @@ using System; using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Member Flags +/// +[Flags] +public enum GuildMemberFlags { /// - /// Represents Guild Member Flags + /// No Flags /// - [Flags] - public enum GuildMemberFlags - { - /// - /// No Flags - /// - None = 0, + None = 0, - /// - /// Member has left and rejoined the guild - /// Editable: False - /// - [DiscordEnum("DID_REJOIN")] - DidRejoin = 1 << 0, + /// + /// Member has left and rejoined the guild + /// Editable: False + /// + [DiscordEnum("DID_REJOIN")] + DidRejoin = 1 << 0, - /// - /// Member has completed onboarding - /// Editable: False - /// - [DiscordEnum("COMPLETED_ONBOARDING")] - CompletedOnboarding = 1 << 1, + /// + /// Member has completed onboarding + /// Editable: False + /// + [DiscordEnum("COMPLETED_ONBOARDING")] + CompletedOnboarding = 1 << 1, - /// - /// Member is exempt from guild verification requirements - /// Editable: True - /// - [DiscordEnum("BYPASSES_VERIFICATION")] - BypassesVerification = 1 << 2, + /// + /// Member is exempt from guild verification requirements + /// Editable: True + /// + [DiscordEnum("BYPASSES_VERIFICATION")] + BypassesVerification = 1 << 2, - /// - /// Member has started onboarding - /// Editable: False - /// - [DiscordEnum("STARTED_ONBOARDING")] - StartedOnboarding = 1 << 3, - } + /// + /// Member has started onboarding + /// Editable: False + /// + [DiscordEnum("STARTED_ONBOARDING")] + StartedOnboarding = 1 << 3, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildMemberUpdate.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildMemberUpdate.cs index abb1eec6f..48544bb51 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildMemberUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildMemberUpdate.cs @@ -4,61 +4,60 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Member Update Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildMemberUpdate : IDiscordValidation { /// - /// Represents Guild Member Update Structure + /// The nickname to give the user + /// Requires MANAGE_NICKNAMES Permission /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildMemberUpdate : IDiscordValidation - { - /// - /// The nickname to give the user - /// Requires MANAGE_NICKNAMES Permission - /// - [JsonProperty("nick")] - public string Nick { get; set; } + [JsonProperty("nick")] + public string Nick { get; set; } - /// - /// New list of guild members roles - /// Will replaces all roles with the ones in this list - /// Requires MANAGE_ROLES Permission - /// - [JsonProperty("roles")] - public List Roles { get; set; } + /// + /// New list of guild members roles + /// Will replaces all roles with the ones in this list + /// Requires MANAGE_ROLES Permission + /// + [JsonProperty("roles")] + public List Roles { get; set; } - /// - /// Deafen the guild member - /// Requires DEAFEN_MEMBERS Permission - /// - [JsonProperty("deaf")] - public bool? Deaf { get; set; } + /// + /// Deafen the guild member + /// Requires DEAFEN_MEMBERS Permission + /// + [JsonProperty("deaf")] + public bool? Deaf { get; set; } - /// - /// Mute the guild member - /// Requires MUTE_MEMBERS Permission - /// - [JsonProperty("mute")] - public bool? Mute { get; set; } + /// + /// Mute the guild member + /// Requires MUTE_MEMBERS Permission + /// + [JsonProperty("mute")] + public bool? Mute { get; set; } - /// - /// The channel to move the user to - /// Requires MOVE_MEMBERS Permission - /// Setting to null will remove that member from a voice channel - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } + /// + /// The channel to move the user to + /// Requires MOVE_MEMBERS Permission + /// Setting to null will remove that member from a voice channel + /// + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } - /// - /// When the user's timeout will expire and the user will be able to communicate in the guild again (up to 28 days in the future), set to null to remove timeout - /// - [JsonProperty("communication_disabled_until")] - public DateTime? CommunicationDisabledUntil { get; set; } + /// + /// When the user's timeout will expire and the user will be able to communicate in the guild again (up to 28 days in the future), set to null to remove timeout + /// + [JsonProperty("communication_disabled_until")] + public DateTime? CommunicationDisabledUntil { get; set; } - /// - public void Validate() - { - InvalidGuildMemberException.ThrowIfInvalidNickname(Nick); - } + /// + public void Validate() + { + InvalidGuildMemberException.ThrowIfInvalidNickname(Nick); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildNavigationType.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildNavigationType.cs index 34e18088e..008107f96 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildNavigationType.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildNavigationType.cs @@ -1,23 +1,22 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Navigation Types +/// +public enum GuildNavigationType { /// - /// Represents Guild Navigation Types + /// Customize tab with the server's onboarding prompts /// - public enum GuildNavigationType - { - /// - /// Customize tab with the server's onboarding prompts - /// - Customize, + Customize, - /// - /// Browse Channels tab - /// - Browse, + /// + /// Browse Channels tab + /// + Browse, - /// - /// Server Guide - /// - Guide - } + /// + /// Server Guide + /// + Guide } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildNsfwLevel.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildNsfwLevel.cs index 8a2212ef1..216a9fe75 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildNsfwLevel.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildNsfwLevel.cs @@ -1,34 +1,33 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild NSFW Level +/// +public enum GuildNsfwLevel : byte { /// - /// Represents Guild NSFW Level + /// Default NSFW Level /// - public enum GuildNsfwLevel : byte - { - /// - /// Default NSFW Level - /// - [DiscordEnum("DEFAULT")] - Default = 0, + [DiscordEnum("DEFAULT")] + Default = 0, - /// - /// Guild is explicitly NSFW - /// - [DiscordEnum("EXPLICIT")] - Explicit = 1, + /// + /// Guild is explicitly NSFW + /// + [DiscordEnum("EXPLICIT")] + Explicit = 1, - /// - /// Guild is safe from NSFW - /// - [DiscordEnum("SAFE")] - Safe = 2, + /// + /// Guild is safe from NSFW + /// + [DiscordEnum("SAFE")] + Safe = 2, - /// - /// Guild is age restricted - /// - [DiscordEnum("AGE_RESTRICTED")] - AgeRestricted = 3 - } + /// + /// Guild is age restricted + /// + [DiscordEnum("AGE_RESTRICTED")] + AgeRestricted = 3 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildPremiumTier.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildPremiumTier.cs index 430bf2ae1..d07f17b69 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildPremiumTier.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildPremiumTier.cs @@ -1,34 +1,33 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Verification Level +/// +public enum GuildPremiumTier : byte { /// - /// Represents Verification Level + /// Guild does not have any premium tier /// - public enum GuildPremiumTier : byte - { - /// - /// Guild does not have any premium tier - /// - [DiscordEnum("NONE")] - None = 0, + [DiscordEnum("NONE")] + None = 0, - /// - /// Guild is premium tier 1 - /// - [DiscordEnum("TIER_1")] - Tier1 = 1, + /// + /// Guild is premium tier 1 + /// + [DiscordEnum("TIER_1")] + Tier1 = 1, - /// - /// Guild is premium tier 2 - /// - [DiscordEnum("TIER_2")] - Tier2 = 2, + /// + /// Guild is premium tier 2 + /// + [DiscordEnum("TIER_2")] + Tier2 = 2, - /// - /// Guild is premium tier 3 - /// - [DiscordEnum("TIER_3")] - Tier3 = 3 - } -} + /// + /// Guild is premium tier 3 + /// + [DiscordEnum("TIER_3")] + Tier3 = 3 +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildPreview.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildPreview.cs index efca6eba2..6cdfed585 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildPreview.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildPreview.cs @@ -1,80 +1,79 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Preview Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildPreview { /// - /// Represents Guild Preview Structure + /// Guild id /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildPreview - { - /// - /// Guild id - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Name of the guild (2-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the guild (2-100 characters) + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Base64 128x128 image for the guild icon - /// - [JsonProperty("icon")] - public string Icon { get; set; } + /// + /// Base64 128x128 image for the guild icon + /// + [JsonProperty("icon")] + public string Icon { get; set; } - /// - /// Splash hash - /// - [JsonProperty("splash")] - public string Splash { get; set; } + /// + /// Splash hash + /// + [JsonProperty("splash")] + public string Splash { get; set; } - /// - /// Discovery splash hash - /// Only present for guilds with the "DISCOVERABLE" feature - /// - [JsonProperty("discovery_splash")] - public string DiscoverySplash { get; set; } + /// + /// Discovery splash hash + /// Only present for guilds with the "DISCOVERABLE" feature + /// + [JsonProperty("discovery_splash")] + public string DiscoverySplash { get; set; } - /// - /// Custom guild emojis - /// - [JsonProperty("emojis")] - public List Emojis { get; set; } + /// + /// Custom guild emojis + /// + [JsonProperty("emojis")] + public List Emojis { get; set; } - /// - /// Enabled guild features - /// See - /// - [JsonProperty("features")] - public List Features { get; set; } + /// + /// Enabled guild features + /// See + /// + [JsonProperty("features")] + public List Features { get; set; } - /// - /// Approximate number of members in this guild - /// - [JsonProperty("approximate_member_count")] - public int? ApproximateMemberCount { get; set; } + /// + /// Approximate number of members in this guild + /// + [JsonProperty("approximate_member_count")] + public int? ApproximateMemberCount { get; set; } - /// - /// Approximate number of non-offline members in this guild - /// - [JsonProperty("approximate_presence_count")] - public int? ApproximatePresenceCount { get; set; } + /// + /// Approximate number of non-offline members in this guild + /// + [JsonProperty("approximate_presence_count")] + public int? ApproximatePresenceCount { get; set; } - /// - /// The description of a guild - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// The description of a guild + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Custom guild stickers - /// - [JsonProperty("stickers")] - public List Stickers { get; set; } - } + /// + /// Custom guild stickers + /// + [JsonProperty("stickers")] + public List Stickers { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildPruneBegin.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildPruneBegin.cs index c6ab0823e..52eab46dc 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildPruneBegin.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildPruneBegin.cs @@ -1,54 +1,52 @@ using System; using Newtonsoft.Json; using Oxide.Ext.Discord.Builders; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Prune Begin +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildPruneBegin : GuildPruneGet { /// - /// Represents Guild Prune Begin + /// Whether 'pruned' is returned, discouraged for large guilds /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildPruneBegin : GuildPruneGet - { - /// - /// Whether 'pruned' is returned, discouraged for large guilds - /// - [JsonProperty("compute_prune_count")] - public bool ComputePruneCount { get; set; } + [JsonProperty("compute_prune_count")] + public bool ComputePruneCount { get; set; } - /// - /// Reason for the prune (Deprecated) - /// - [Obsolete("This field is deprecated and may be removed in a future update")] - [JsonProperty("reason")] - public string Reason { get; set; } + /// + /// Reason for the prune (Deprecated) + /// + [Obsolete("This field is deprecated and may be removed in a future update")] + [JsonProperty("reason")] + public string Reason { get; set; } - /// - /// Returns Guild Prune Begin query string for the API Endpoint - /// - /// Guild Prune Begin Query String - public override string ToQueryString() - { - Validate(); - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); + /// + /// Returns Guild Prune Begin query string for the API Endpoint + /// + /// Guild Prune Begin Query String + public override string ToQueryString() + { + Validate(); + QueryStringBuilder builder = new(); - builder.Add("days", Days.ToString()); - builder.Add("compute_prune_count", ComputePruneCount.ToString()); + builder.Add("days", Days.ToString()); + builder.Add("compute_prune_count", ComputePruneCount.ToString()); - if (IncludeRoles != null) - { - builder.AddList("include_roles", IncludeRoles, ","); - } + if (IncludeRoles != null) + { + builder.AddList("include_roles", IncludeRoles, ","); + } #pragma warning disable CS0618 - if (!string.IsNullOrEmpty(Reason)) - { - builder.Add("reason", Reason); - } + if (!string.IsNullOrEmpty(Reason)) + { + builder.Add("reason", Reason); + } #pragma warning restore CS0618 - return builder.ToStringAndFree(); - } + return builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildPruneGet.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildPruneGet.cs index 1d20162ec..82a03f1c2 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildPruneGet.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildPruneGet.cs @@ -3,46 +3,44 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Prune Get +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildPruneGet : IDiscordQueryString, IDiscordValidation { /// - /// Represents Guild Prune Get + /// Number of days to count prune for (1 - 30) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildPruneGet : IDiscordQueryString, IDiscordValidation - { - /// - /// Number of days to count prune for (1 - 30) - /// - [JsonProperty("days")] - public int Days { get; set; } = 7; + [JsonProperty("days")] + public int Days { get; set; } = 7; - /// - /// List of roles to include - /// - [JsonProperty("include_roles")] - public List IncludeRoles { get; set; } + /// + /// List of roles to include + /// + [JsonProperty("include_roles")] + public List IncludeRoles { get; set; } - /// - public virtual string ToQueryString() + /// + public virtual string ToQueryString() + { + Validate(); + QueryStringBuilder builder = new(); + builder.Add("days", Days.ToString()); + if (IncludeRoles != null) { - Validate(); - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); - builder.Add("days", Days.ToString()); - if (IncludeRoles != null) - { - builder.AddList("include_roles", IncludeRoles, ","); - } - - return builder.ToStringAndFree(); + builder.AddList("include_roles", IncludeRoles, ","); } - /// - public void Validate() - { - InvalidGuildPruneException.ThrowIfInvalidDays(Days); - } + return builder.ToString(); + } + + /// + public void Validate() + { + InvalidGuildPruneException.ThrowIfInvalidDays(Days); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildPruneResult.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildPruneResult.cs index df622bd8c..805db3690 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildPruneResult.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildPruneResult.cs @@ -1,18 +1,17 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Prune Count Response +/// Represents Guild Prune Begin Response +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildPruneResult { /// - /// Represents Guild Prune Count Response - /// Represents Guild Prune Begin Response + /// Number of members pruned /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildPruneResult - { - /// - /// Number of members pruned - /// - [JsonProperty("pruned")] - public int Pruned { get; set; } - } + [JsonProperty("pruned")] + public int Pruned { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildRolePosition.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildRolePosition.cs index 61def8146..857c22ed4 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildRolePosition.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildRolePosition.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Role Position +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildRolePosition { /// - /// Represents Guild Role Position + /// ID of the channel or role /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildRolePosition - { - /// - /// ID of the channel or role - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// New position for the role / channel - /// - [JsonProperty("position")] - public int Position { get; set; } - } -} + /// + /// New position for the role / channel + /// + [JsonProperty("position")] + public int Position { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildSearchMembers.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildSearchMembers.cs index 9d4e10d6c..0b03290be 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildSearchMembers.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildSearchMembers.cs @@ -1,46 +1,44 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Search Guild Members Structure +/// +public class GuildSearchMembers : IDiscordQueryString, IDiscordValidation { /// - /// Represents Search Guild Members Structure + /// Query string to match username(s) and nickname(s) against. /// - public class GuildSearchMembers : IDiscordQueryString, IDiscordValidation - { - /// - /// Query string to match username(s) and nickname(s) against. - /// - public string Query { get; set; } + public string Query { get; set; } - /// - /// Max number of members to return (1-1000) - /// Default is 1 - /// - public int? Limit { get; set; } + /// + /// Max number of members to return (1-1000) + /// Default is 1 + /// + public int? Limit { get; set; } - /// - public string ToQueryString() - { - Validate(); - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); - builder.Add("query", Query); + /// + public string ToQueryString() + { + Validate(); + QueryStringBuilder builder = new(); + builder.Add("query", Query); - if (Limit.HasValue) - { - builder.Add("limit", Limit.Value.ToString()); - } - - return builder.ToStringAndFree(); - } - - /// - public void Validate() + if (Limit.HasValue) { - InvalidGuildSearchMembersException.ThrowIfInvalidQuery(Query); - InvalidGuildSearchMembersException.ThrowIfInvalidLimit(Limit); + builder.Add("limit", Limit.Value.ToString()); } + + return builder.ToString(); + } + + /// + public void Validate() + { + InvalidGuildSearchMembersException.ThrowIfInvalidQuery(Query); + InvalidGuildSearchMembersException.ThrowIfInvalidLimit(Limit); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildUpdate.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildUpdate.cs index edf30045f..45e5a99e6 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildUpdate.cs @@ -4,152 +4,151 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Update Guild Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildUpdate : IDiscordValidation { /// - /// Represents Update Guild Structure + /// Name of the guild (2-100 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildUpdate : IDiscordValidation - { - /// - /// Name of the guild (2-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Voice region id - /// - [Obsolete("Deprecated in Discord API")] - [JsonProperty("region")] - public string Region { get; set; } + /// + /// Voice region id + /// + [Obsolete("Deprecated in Discord API")] + [JsonProperty("region")] + public string Region { get; set; } - /// - /// Verification level - /// - [JsonProperty("verification_level")] - public GuildVerificationLevel? VerificationLevel { get; set; } + /// + /// Verification level + /// + [JsonProperty("verification_level")] + public GuildVerificationLevel? VerificationLevel { get; set; } - /// - /// Default message notification level - /// - [JsonProperty("default_message_notifications")] - public DefaultNotificationLevel? DefaultMessageNotifications { get; set; } + /// + /// Default message notification level + /// + [JsonProperty("default_message_notifications")] + public DefaultNotificationLevel? DefaultMessageNotifications { get; set; } - /// - /// Explicit content filter level - /// - [JsonProperty("explicit_content_filter")] - public ExplicitContentFilterLevel? ExplicitContentFilter { get; set; } + /// + /// Explicit content filter level + /// + [JsonProperty("explicit_content_filter")] + public ExplicitContentFilterLevel? ExplicitContentFilter { get; set; } - /// - /// ID of afk channel - /// - [JsonProperty("afk_channel_id")] - public Snowflake? AfkChannelId { get; set; } + /// + /// ID of afk channel + /// + [JsonProperty("afk_channel_id")] + public Snowflake? AfkChannelId { get; set; } - /// - /// Afk timeout in seconds - /// Can be set to: null, 60, 300, 900, 1800, 3600 - /// - [JsonProperty("afk_timeout")] - public int? AfkTimeout { get; set; } + /// + /// Afk timeout in seconds + /// Can be set to: null, 60, 300, 900, 1800, 3600 + /// + [JsonProperty("afk_timeout")] + public int? AfkTimeout { get; set; } - /// - /// Base64 128x128 image for the guild icon - /// - [JsonProperty("icon")] - public DiscordImageData? Icon { get; set; } + /// + /// Base64 128x128 image for the guild icon + /// + [JsonProperty("icon")] + public DiscordImageData? Icon { get; set; } - /// - /// User id to transfer guild ownership to (must be owner) - /// - [JsonProperty("owner_id")] - public Snowflake? OwnerId { get; set; } + /// + /// User id to transfer guild ownership to (must be owner) + /// + [JsonProperty("owner_id")] + public Snowflake? OwnerId { get; set; } - /// - /// Image for the guild splash (when the server has the INVITE_SPLASH feature) - /// - [JsonProperty("splash")] - public DiscordImageData? Splash { get; set; } + /// + /// Image for the guild splash (when the server has the INVITE_SPLASH feature) + /// + [JsonProperty("splash")] + public DiscordImageData? Splash { get; set; } - /// - /// Image for the guild discovery splash (when the server has the DISCOVERABLE feature) - /// - [JsonProperty("discovery_splash")] - public DiscordImageData? DiscoverySplash { get; set; } + /// + /// Image for the guild discovery splash (when the server has the DISCOVERABLE feature) + /// + [JsonProperty("discovery_splash")] + public DiscordImageData? DiscoverySplash { get; set; } - /// - /// Image for the guild banner (when the server has the BANNER feature; can be animated gif when the server has the ANIMATED_BANNER feature) - /// - [JsonProperty("banner")] - public DiscordImageData? Banner { get; set; } + /// + /// Image for the guild banner (when the server has the BANNER feature; can be animated gif when the server has the ANIMATED_BANNER feature) + /// + [JsonProperty("banner")] + public DiscordImageData? Banner { get; set; } - /// - /// The id of the channel where guild notices such as welcome messages and boost events are posted - /// - [JsonProperty("system_channel_id")] - public Snowflake? SystemChannelId { get; set; } + /// + /// The id of the channel where guild notices such as welcome messages and boost events are posted + /// + [JsonProperty("system_channel_id")] + public Snowflake? SystemChannelId { get; set; } - /// - /// System channel flags - /// - [JsonProperty("system_channel_flags")] - public SystemChannelFlags? SystemChannelFlags { get; set; } + /// + /// System channel flags + /// + [JsonProperty("system_channel_flags")] + public SystemChannelFlags? SystemChannelFlags { get; set; } - /// - /// The id of the channel where Community guilds display rules and/or guidelines - /// - [JsonProperty("rules_channel_id")] - public SystemChannelFlags? RulesChannelId { get; set; } + /// + /// The id of the channel where Community guilds display rules and/or guidelines + /// + [JsonProperty("rules_channel_id")] + public SystemChannelFlags? RulesChannelId { get; set; } - /// - /// The id of the channel where admins and moderators of Community guilds receive notices from Discord - /// - [JsonProperty("public_updates_channel_id")] - public SystemChannelFlags? PublicUpdatesChannelId { get; set; } + /// + /// The id of the channel where admins and moderators of Community guilds receive notices from Discord + /// + [JsonProperty("public_updates_channel_id")] + public SystemChannelFlags? PublicUpdatesChannelId { get; set; } - /// - /// The preferred locale of a Community guild used in server discovery and notices from Discord; defaults to "en-US" - /// - [JsonProperty("preferred_locale")] - public string PreferredLocale { get; set; } + /// + /// The preferred locale of a Community guild used in server discovery and notices from Discord; defaults to "en-US" + /// + [JsonProperty("preferred_locale")] + public string PreferredLocale { get; set; } - /// - /// Enabled guild features - /// - [JsonProperty("features")] - public List Features { get; set; } + /// + /// Enabled guild features + /// + [JsonProperty("features")] + public List Features { get; set; } - /// - /// The description for the guild - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// The description for the guild + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Whether the guild's boost progress bar should be enabled - /// - [JsonProperty("premium_progress_bar_enabled")] - public bool? PremiumProgressBarEnabled { get; set; } + /// + /// Whether the guild's boost progress bar should be enabled + /// + [JsonProperty("premium_progress_bar_enabled")] + public bool? PremiumProgressBarEnabled { get; set; } - /// - /// The id of the channel where admins and moderators of Community guilds receive safety alerts from Discord - /// - [JsonProperty("safety_alerts_channel_id")] - public SystemChannelFlags? SafetyAlertsChannelId { get; set; } + /// + /// The id of the channel where admins and moderators of Community guilds receive safety alerts from Discord + /// + [JsonProperty("safety_alerts_channel_id")] + public SystemChannelFlags? SafetyAlertsChannelId { get; set; } - /// - public void Validate() - { - InvalidGuildException.ThrowIfInvalidName(Name, true); - InvalidImageDataException.ThrowIfInvalidImageData(Icon); - InvalidImageDataException.ThrowIfInvalidImageData(Splash); - InvalidImageDataException.ThrowIfInvalidImageData(DiscoverySplash); - InvalidImageDataException.ThrowIfInvalidImageData(Banner); - InvalidSnowflakeException.ThrowIfInvalid(AfkChannelId, false, nameof(AfkChannelId)); - InvalidSnowflakeException.ThrowIfInvalid(SystemChannelId, false, nameof(SystemChannelId)); - } + /// + public void Validate() + { + InvalidGuildException.ThrowIfInvalidName(Name, true); + InvalidImageDataException.ThrowIfInvalidImageData(Icon); + InvalidImageDataException.ThrowIfInvalidImageData(Splash); + InvalidImageDataException.ThrowIfInvalidImageData(DiscoverySplash); + InvalidImageDataException.ThrowIfInvalidImageData(Banner); + InvalidSnowflakeException.ThrowIfInvalid(AfkChannelId, false); + InvalidSnowflakeException.ThrowIfInvalid(SystemChannelId, false); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildUpdateMfaLevel.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildUpdateMfaLevel.cs index 337bf69c9..a2c23df7b 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildUpdateMfaLevel.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildUpdateMfaLevel.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild MFA Level Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildUpdateMfaLevel { /// - /// Represents Guild MFA Level Update + /// /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildUpdateMfaLevel - { - /// - /// - /// - [JsonProperty("level")] - public GuildMfaLevel Level { get; set; } - } + [JsonProperty("level")] + public GuildMfaLevel Level { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildUserVoiceStateUpdate.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildUserVoiceStateUpdate.cs index 60fcbf302..332c7224c 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildUserVoiceStateUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildUserVoiceStateUpdate.cs @@ -2,29 +2,28 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Modify User Voice State +/// +public class GuildUserVoiceStateUpdate : IDiscordValidation { /// - /// Represents a Modify User Voice State + /// The id of the channel the user is currently in /// - public class GuildUserVoiceStateUpdate : IDiscordValidation - { - /// - /// The id of the channel the user is currently in - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// Toggles the user's suppress state - /// - [JsonProperty("suppress")] - public bool Suppress { get; set; } + /// + /// Toggles the user's suppress state + /// + [JsonProperty("suppress")] + public bool Suppress { get; set; } - /// - public void Validate() - { - InvalidSnowflakeException.ThrowIfInvalid(ChannelId, nameof(ChannelId)); - } + /// + public void Validate() + { + InvalidSnowflakeException.ThrowIfInvalid(ChannelId); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildVerificationLevel.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildVerificationLevel.cs index 821c52b16..80dee1b88 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildVerificationLevel.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildVerificationLevel.cs @@ -1,40 +1,39 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Verification Level +/// +public enum GuildVerificationLevel : byte { /// - /// Represents Verification Level + /// Unrestricted /// - public enum GuildVerificationLevel : byte - { - /// - /// Unrestricted - /// - [DiscordEnum("NONE")] - None = 0, + [DiscordEnum("NONE")] + None = 0, - /// - /// Must have verified email on account - /// - [DiscordEnum("LOW")] - Low = 1, + /// + /// Must have verified email on account + /// + [DiscordEnum("LOW")] + Low = 1, - /// - /// Must be registered on Discord for longer than 5 minutes - /// - [DiscordEnum("MEDIUM")] - Medium = 2, + /// + /// Must be registered on Discord for longer than 5 minutes + /// + [DiscordEnum("MEDIUM")] + Medium = 2, - /// - /// Must be a member of the server for longer than 10 minutes - /// - [DiscordEnum("HIGH")] - High = 3, + /// + /// Must be a member of the server for longer than 10 minutes + /// + [DiscordEnum("HIGH")] + High = 3, - /// - /// Must have a verified phone number - /// - [DiscordEnum("VERY_HIGH")] - VeryHigh = 4 - } -} + /// + /// Must have a verified phone number + /// + [DiscordEnum("VERY_HIGH")] + VeryHigh = 4 +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildWelcomeScreen.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildWelcomeScreen.cs index 6a3d22ce0..2214a7ffa 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildWelcomeScreen.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildWelcomeScreen.cs @@ -1,25 +1,24 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Welcome Screen Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildWelcomeScreen { /// - /// Represents Welcome Screen Structure + /// The server description shown in the welcome screen /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildWelcomeScreen - { - /// - /// The server description shown in the welcome screen - /// - [JsonProperty("description")] - public string Description { get; set; } + [JsonProperty("description")] + public string Description { get; set; } - /// - /// The channels shown in the welcome screen - /// Up to 5 - /// - [JsonProperty("welcome_channels")] - public List WelcomeChannels { get; set; } - } + /// + /// The channels shown in the welcome screen + /// Up to 5 + /// + [JsonProperty("welcome_channels")] + public List WelcomeChannels { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildWelcomeScreenChannel.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildWelcomeScreenChannel.cs index f065622eb..e81518ae0 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildWelcomeScreenChannel.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildWelcomeScreenChannel.cs @@ -1,35 +1,34 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Welcome Screen Channel Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildWelcomeScreenChannel { /// - /// Represents Welcome Screen Channel Structure + /// Channel ID for the channel /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildWelcomeScreenChannel - { - /// - /// Channel ID for the channel - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } - /// - /// The description shown for the channel - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// The description shown for the channel + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// The emoji id, if the emoji is custom - /// - [JsonProperty("emoji_id")] - public Snowflake EmojiId { get; set; } + /// + /// The emoji id, if the emoji is custom + /// + [JsonProperty("emoji_id")] + public Snowflake EmojiId { get; set; } - /// - /// The emoji name if custom, the unicode character if standard, or null if no emoji is set - /// - [JsonProperty("emoji_name")] - public string EmojiName { get; set; } - } + /// + /// The emoji name if custom, the unicode character if standard, or null if no emoji is set + /// + [JsonProperty("emoji_name")] + public string EmojiName { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildWidget.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildWidget.cs index 78287ffd1..2bc7a5baf 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildWidget.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildWidget.cs @@ -1,48 +1,47 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildWidget { /// - /// Represents + /// Guild id /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildWidget - { - /// - /// Guild id - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Guild name (2-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Guild name (2-100 characters) + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Instant invite for the guilds specified widget invite channel - /// - [JsonProperty("instant_invite")] - public string InstantInvite { get; set; } + /// + /// Instant invite for the guilds specified widget invite channel + /// + [JsonProperty("instant_invite")] + public string InstantInvite { get; set; } - /// - /// Voice and stage channels which are accessible by @everyone - /// - [JsonProperty("channels")] - public List Channels { get; set; } + /// + /// Voice and stage channels which are accessible by @everyone + /// + [JsonProperty("channels")] + public List Channels { get; set; } - /// - /// Special widget user objects that includes users presence (Limit 100) - /// - [JsonProperty("members")] - public List Members { get; set; } + /// + /// Special widget user objects that includes users presence (Limit 100) + /// + [JsonProperty("members")] + public List Members { get; set; } - /// - /// Number of online members in this guild - /// - [JsonProperty("presence_count")] - public int PresenceCount { get; set; } - } + /// + /// Number of online members in this guild + /// + [JsonProperty("presence_count")] + public int PresenceCount { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/GuildWidgetSettings.cs b/Oxide.Ext.Discord/Entities/Guilds/GuildWidgetSettings.cs index 9f43f75f0..855bd77ff 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/GuildWidgetSettings.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/GuildWidgetSettings.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Widget Settings Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildWidgetSettings { /// - /// Represents Guild Widget Settings Structure + /// Whether the widget is enabled /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildWidgetSettings - { - /// - /// Whether the widget is enabled - /// - [JsonProperty("enabled")] - public bool Enabled { get; set; } + [JsonProperty("enabled")] + public bool Enabled { get; set; } - /// - /// The widget channel id - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } - } -} + /// + /// The widget channel id + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboarding.cs b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboarding.cs index d62e2e7c8..813ad1963 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboarding.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboarding.cs @@ -1,42 +1,41 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Onboarding Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildOnboarding { /// - /// Represents Guild Onboarding Structure + /// ID of the guild this onboarding is part of /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildOnboarding - { - /// - /// ID of the guild this onboarding is part of - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// Prompts shown during onboarding and in customize community - /// - [JsonProperty("prompts")] - public List Prompts { get; set; } + /// + /// Prompts shown during onboarding and in customize community + /// + [JsonProperty("prompts")] + public List Prompts { get; set; } - /// - /// Channel IDs that members get opted into automatically - /// - [JsonProperty("default_channel_ids")] - public List DefaultChannelIds { get; set; } + /// + /// Channel IDs that members get opted into automatically + /// + [JsonProperty("default_channel_ids")] + public List DefaultChannelIds { get; set; } - /// - /// Whether onboarding is enabled in the guild - /// - [JsonProperty("enabled")] - public bool Enabled { get; set; } + /// + /// Whether onboarding is enabled in the guild + /// + [JsonProperty("enabled")] + public bool Enabled { get; set; } - /// - /// Current mode of onboarding - /// - [JsonProperty("mode")] - public GuildOnboardingMode Mode { get; set; } - } + /// + /// Current mode of onboarding + /// + [JsonProperty("mode")] + public GuildOnboardingMode Mode { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboardingMode.cs b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboardingMode.cs index 8f5b9ddc0..f81d9178a 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboardingMode.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboardingMode.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Onboarding Mode Structure +/// +public enum GuildOnboardingMode { /// - /// Represents Guild Onboarding Mode Structure + /// Counts only Default Channels towards constraints /// - public enum GuildOnboardingMode - { - /// - /// Counts only Default Channels towards constraints - /// - OnboardingDefault = 0, + OnboardingDefault = 0, - /// - /// Counts Default Channels and Questions towards constraints - /// - OnboardingAdvanced = 1 - } + /// + /// Counts Default Channels and Questions towards constraints + /// + OnboardingAdvanced = 1 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboardingUpdate.cs b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboardingUpdate.cs index 7ada24199..bc62a3a00 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboardingUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/GuildOnboardingUpdate.cs @@ -1,36 +1,35 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Onboarding Update Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildOnboardingUpdate { /// - /// Represents Guild Onboarding Update Structure + /// Prompts shown during onboarding and in customize community /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildOnboardingUpdate - { - /// - /// Prompts shown during onboarding and in customize community - /// - [JsonProperty("prompts")] - public List Prompts { get; set; } + [JsonProperty("prompts")] + public List Prompts { get; set; } - /// - /// Channel IDs that members get opted into automatically - /// - [JsonProperty("default_channel_ids")] - public List DefaultChannelIds { get; set; } + /// + /// Channel IDs that members get opted into automatically + /// + [JsonProperty("default_channel_ids")] + public List DefaultChannelIds { get; set; } - /// - /// Whether onboarding is enabled in the guild - /// - [JsonProperty("enabled")] - public bool Enabled { get; set; } + /// + /// Whether onboarding is enabled in the guild + /// + [JsonProperty("enabled")] + public bool Enabled { get; set; } - /// - /// Current mode of onboarding - /// - [JsonProperty("mode")] - public GuildOnboardingMode Mode { get; set; } - } + /// + /// Current mode of onboarding + /// + [JsonProperty("mode")] + public GuildOnboardingMode Mode { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPrompt.cs b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPrompt.cs index 2a6f60d77..c4c9967a4 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPrompt.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPrompt.cs @@ -1,55 +1,54 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Onboarding Prompt Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class OnboardingPrompt { /// - /// Represents Onboarding Prompt Structure + /// ID of the prompt /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class OnboardingPrompt - { - /// - /// ID of the prompt - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Type of prompt - /// - [JsonProperty("type")] - public OnboardingPromptType Type { get; set; } + /// + /// Type of prompt + /// + [JsonProperty("type")] + public OnboardingPromptType Type { get; set; } - /// - /// Options available within the prompt - /// - [JsonProperty("options")] - public List Options { get; set; } + /// + /// Options available within the prompt + /// + [JsonProperty("options")] + public List Options { get; set; } - /// - /// Title of the prompt - /// - [JsonProperty("title")] - public string Title { get; set; } + /// + /// Title of the prompt + /// + [JsonProperty("title")] + public string Title { get; set; } - /// - /// Indicates whether users are limited to selecting one option for the prompt - /// - [JsonProperty("single_select")] - public bool SingleSelect { get; set; } + /// + /// Indicates whether users are limited to selecting one option for the prompt + /// + [JsonProperty("single_select")] + public bool SingleSelect { get; set; } - /// - /// Indicates whether the prompt is required before a user completes the onboarding flow - /// - [JsonProperty("required")] - public bool Required { get; set; } + /// + /// Indicates whether the prompt is required before a user completes the onboarding flow + /// + [JsonProperty("required")] + public bool Required { get; set; } - /// - /// Indicates whether the prompt is present in the onboarding flow. - /// If false, the prompt will only appear in the Channels and Roles tab - /// - [JsonProperty("in_onboarding")] - public bool InOnboarding { get; set; } - } + /// + /// Indicates whether the prompt is present in the onboarding flow. + /// If false, the prompt will only appear in the Channels and Roles tab + /// + [JsonProperty("in_onboarding")] + public bool InOnboarding { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPromptOption.cs b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPromptOption.cs index 7eed77ab2..1ac82716b 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPromptOption.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPromptOption.cs @@ -1,48 +1,47 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Prompt Option Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class OnboardingPromptOption { /// - /// Represents Prompt Option Structure + /// ID of the prompt option /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class OnboardingPromptOption - { - /// - /// ID of the prompt option - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// IDs for channels a member is added to when the option is selected - /// - [JsonProperty("channel_ids")] - public List ChannelIds { get; set; } + /// + /// IDs for channels a member is added to when the option is selected + /// + [JsonProperty("channel_ids")] + public List ChannelIds { get; set; } - /// - /// IDs for roles assigned to a member when the option is selected - /// - [JsonProperty("role_ids")] - public List RoleIds { get; set; } + /// + /// IDs for roles assigned to a member when the option is selected + /// + [JsonProperty("role_ids")] + public List RoleIds { get; set; } - /// - /// Emoji of the option - /// - [JsonProperty("emoji")] - public DiscordEmoji Emoji { get; set; } + /// + /// Emoji of the option + /// + [JsonProperty("emoji")] + public DiscordEmoji Emoji { get; set; } - /// - /// Title of the option - /// - [JsonProperty("title")] - public string Title { get; set; } + /// + /// Title of the option + /// + [JsonProperty("title")] + public string Title { get; set; } - /// - /// Description of the option - /// - [JsonProperty("description")] - public string Description { get; set; } - } + /// + /// Description of the option + /// + [JsonProperty("description")] + public string Description { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPromptType.cs b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPromptType.cs index cc6ccbe25..d44626edf 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPromptType.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/Onboarding/OnboardingPromptType.cs @@ -1,22 +1,21 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Prompt Types +/// +public enum OnboardingPromptType : byte { /// - /// Represents Prompt Types + /// Multiple Choice Prompt Type /// - public enum OnboardingPromptType : byte - { - /// - /// Multiple Choice Prompt Type - /// - [DiscordEnum("MULTIPLE_CHOICE")] - MultipleChoice = 0, + [DiscordEnum("MULTIPLE_CHOICE")] + MultipleChoice = 0, - /// - /// Dropdown Prompt Type - /// - [DiscordEnum("DROPDOWN")] - Dropdown = 1, - } + /// + /// Dropdown Prompt Type + /// + [DiscordEnum("DROPDOWN")] + Dropdown = 1, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/GuildScheduledEvent.cs b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/GuildScheduledEvent.cs index be5528770..3b0225e32 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/GuildScheduledEvent.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/GuildScheduledEvent.cs @@ -5,230 +5,229 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Scheduled Event Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildScheduledEvent : ISnowflakeEntity { /// - /// Represents Guild Scheduled Event Structure + /// The ID of the scheduled event /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildScheduledEvent : ISnowflakeEntity - { - /// - /// The ID of the scheduled event - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The guild ID which the scheduled event belongs to - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + /// + /// The guild ID which the scheduled event belongs to + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// The channel ID in which the scheduled event will be hosted, or null if scheduled entity type is EXTERNAL - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } + /// + /// The channel ID in which the scheduled event will be hosted, or null if scheduled entity type is EXTERNAL + /// + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } - /// - /// The ID of the user that created the scheduled event - /// - [JsonProperty("creator_id")] - public Snowflake? CreatorId { get; set; } + /// + /// The ID of the user that created the scheduled event + /// + [JsonProperty("creator_id")] + public Snowflake? CreatorId { get; set; } - /// - /// The name of the scheduled event (1-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// The name of the scheduled event (1-100 characters) + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// The description of the scheduled event (1-1000 characters) - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// The description of the scheduled event (1-1000 characters) + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// The time the scheduled event will start - /// - [JsonProperty("scheduled_start_time")] - public DateTime ScheduledStartTime { get; set; } + /// + /// The time the scheduled event will start + /// + [JsonProperty("scheduled_start_time")] + public DateTime ScheduledStartTime { get; set; } - /// - /// The time the scheduled event will end, required if EntityType is EXTERNAL - /// - [JsonProperty("scheduled_end_time ")] - public DateTime? ScheduledEndTime { get; set; } + /// + /// The time the scheduled event will end, required if EntityType is EXTERNAL + /// + [JsonProperty("scheduled_end_time ")] + public DateTime? ScheduledEndTime { get; set; } - /// - /// The privacy level of the scheduled event - /// - [JsonProperty("privacy_level")] - public ScheduledEventPrivacyLevel PrivacyLevel { get; set; } + /// + /// The privacy level of the scheduled event + /// + [JsonProperty("privacy_level")] + public ScheduledEventPrivacyLevel PrivacyLevel { get; set; } - /// - /// The status of the scheduled event - /// - [JsonProperty("status")] - public ScheduledEventStatus Status { get; set; } + /// + /// The status of the scheduled event + /// + [JsonProperty("status")] + public ScheduledEventStatus Status { get; set; } - /// - /// The type of the scheduled event - /// - [JsonProperty("entity_type")] - public ScheduledEventEntityType EntityType { get; set; } + /// + /// The type of the scheduled event + /// + [JsonProperty("entity_type")] + public ScheduledEventEntityType EntityType { get; set; } - /// - /// The id of an entity associated with a guild scheduled event - /// - [JsonProperty("entity_id")] - public Snowflake? EntityId { get; set; } + /// + /// The id of an entity associated with a guild scheduled event + /// + [JsonProperty("entity_id")] + public Snowflake? EntityId { get; set; } - /// - /// Additional metadata for the guild scheduled event - /// - [JsonProperty("entity_metadata")] - public ScheduledEventEntityMetadata EntityMetadata { get; set; } + /// + /// Additional metadata for the guild scheduled event + /// + [JsonProperty("entity_metadata")] + public ScheduledEventEntityMetadata EntityMetadata { get; set; } - /// - /// The user that created the scheduled event - /// - [JsonProperty("creator")] - public DiscordUser Creator { get; set; } + /// + /// The user that created the scheduled event + /// + [JsonProperty("creator")] + public DiscordUser Creator { get; set; } - /// - /// The number of users subscribed to the scheduled event - /// - [JsonProperty("user_count")] - public int? UserCount { get; set; } + /// + /// The number of users subscribed to the scheduled event + /// + [JsonProperty("user_count")] + public int? UserCount { get; set; } - /// - /// Returns a list of guild scheduled event objects for the given guild. - /// See List Scheduled Events for Guild - /// - /// Client to use - /// Guild to get events for - /// Query string parameters - public static IPromise> GetGuildEvents(DiscordClient client, Snowflake guildId, ScheduledEventLookup lookup = null) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Get>(client,$"guilds/{guildId}/scheduled-events{lookup?.ToQueryString()}"); - } + /// + /// Returns a list of guild scheduled event objects for the given guild. + /// See List Scheduled Events for Guild + /// + /// Client to use + /// Guild to get events for + /// Query string parameters + public static IPromise> GetGuildEvents(DiscordClient client, Snowflake guildId, ScheduledEventLookup lookup = null) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Get>(client,$"guilds/{guildId}/scheduled-events{lookup?.ToQueryString()}"); + } - /// - /// Create a guild scheduled event in the guild. - /// Returns a guild scheduled event object on success. - /// See Create Guild Scheduled Event - /// - /// Client to use - /// Guild to create event in - /// Guild Scheduled Event to create - public static IPromise Create(DiscordClient client, Snowflake guildId, ScheduledEventCreate create) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Post(client,$"guilds/{guildId}/scheduled-events", create); - } + /// + /// Create a guild scheduled event in the guild. + /// Returns a guild scheduled event object on success. + /// See Create Guild Scheduled Event + /// + /// Client to use + /// Guild to create event in + /// Guild Scheduled Event to create + public static IPromise Create(DiscordClient client, Snowflake guildId, ScheduledEventCreate create) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Post(client,$"guilds/{guildId}/scheduled-events", create); + } - /// - /// Get a guild scheduled event. - /// Returns a guild scheduled event object on success. - /// See Get Guild Scheduled Event - /// - /// Client to use - /// Guild to get events for - /// Id of the scheduled event - /// Query string parameters - public static IPromise Get(DiscordClient client, Snowflake guildId, Snowflake eventId, ScheduledEventLookup lookup = null) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - InvalidSnowflakeException.ThrowIfInvalid(eventId, nameof(eventId)); - return client.Bot.Rest.Get(client,$"guilds/{guildId}/scheduled-events/{eventId}{lookup?.ToQueryString()}"); - } + /// + /// Get a guild scheduled event. + /// Returns a guild scheduled event object on success. + /// See Get Guild Scheduled Event + /// + /// Client to use + /// Guild to get events for + /// Id of the scheduled event + /// Query string parameters + public static IPromise Get(DiscordClient client, Snowflake guildId, Snowflake eventId, ScheduledEventLookup lookup = null) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + InvalidSnowflakeException.ThrowIfInvalid(eventId); + return client.Bot.Rest.Get(client,$"guilds/{guildId}/scheduled-events/{eventId}{lookup?.ToQueryString()}"); + } - /// - /// Modify a guild scheduled event. - /// Returns the modified guild scheduled event object on success. - /// See Modify Guild Scheduled Event - /// - /// Client to use - /// Guild to modify event in - /// Id of the event to update - /// Guild Scheduled Event to update - public IPromise Edit(DiscordClient client, Snowflake guildId, Snowflake eventId, ScheduledEventUpdate update) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - InvalidSnowflakeException.ThrowIfInvalid(eventId, nameof(eventId)); - return client.Bot.Rest.Patch(client,$"guilds/{guildId}/scheduled-events/{eventId}", update); - } + /// + /// Modify a guild scheduled event. + /// Returns the modified guild scheduled event object on success. + /// See Modify Guild Scheduled Event + /// + /// Client to use + /// Guild to modify event in + /// Id of the event to update + /// Guild Scheduled Event to update + public IPromise Edit(DiscordClient client, Snowflake guildId, Snowflake eventId, ScheduledEventUpdate update) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + InvalidSnowflakeException.ThrowIfInvalid(eventId); + return client.Bot.Rest.Patch(client,$"guilds/{guildId}/scheduled-events/{eventId}", update); + } - /// - /// Delete a guild scheduled event - /// See Delete Guild Scheduled Event - /// - /// Client to use - /// Guild to modify event in - /// Id of the event to delete - public IPromise Delete(DiscordClient client, Snowflake guildId, Snowflake eventId) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - InvalidSnowflakeException.ThrowIfInvalid(eventId, nameof(eventId)); - return client.Bot.Rest.Delete(client,$"guilds/{guildId}/scheduled-events/{eventId}"); - } + /// + /// Delete a guild scheduled event + /// See Delete Guild Scheduled Event + /// + /// Client to use + /// Guild to modify event in + /// Id of the event to delete + public IPromise Delete(DiscordClient client, Snowflake guildId, Snowflake eventId) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + InvalidSnowflakeException.ThrowIfInvalid(eventId); + return client.Bot.Rest.Delete(client,$"guilds/{guildId}/scheduled-events/{eventId}"); + } - /// - /// Get a list of guild scheduled event users subscribed to a guild scheduled event. - /// Returns a list of guild scheduled event user objects on success. - /// Guild member data, if it exists, is included if the WithMember query parameter is set. - /// See Get Guild Scheduled Event Users - /// - /// Client to use - /// Guild to get event users for - /// Id of the event to get users for - /// Query string parameters - public static IPromise> GetUsers(DiscordClient client, Snowflake guildId, Snowflake eventId, ScheduledEventUsersLookup lookup = null) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - InvalidSnowflakeException.ThrowIfInvalid(eventId, nameof(eventId)); + /// + /// Get a list of guild scheduled event users subscribed to a guild scheduled event. + /// Returns a list of guild scheduled event user objects on success. + /// Guild member data, if it exists, is included if the WithMember query parameter is set. + /// See Get Guild Scheduled Event Users + /// + /// Client to use + /// Guild to get event users for + /// Id of the event to get users for + /// Query string parameters + public static IPromise> GetUsers(DiscordClient client, Snowflake guildId, Snowflake eventId, ScheduledEventUsersLookup lookup = null) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + InvalidSnowflakeException.ThrowIfInvalid(eventId); - return client.Bot.Rest.Get>(client,$"guilds/{guildId}/scheduled-events/{eventId}{lookup?.ToQueryString()}"); - } + return client.Bot.Rest.Get>(client,$"guilds/{guildId}/scheduled-events/{eventId}{lookup?.ToQueryString()}"); + } - internal void Update(GuildScheduledEvent scheduledEvent) + internal void Update(GuildScheduledEvent scheduledEvent) + { + if (scheduledEvent.ChannelId.HasValue) { - if (scheduledEvent.ChannelId.HasValue) - { - ChannelId = scheduledEvent.ChannelId; - } + ChannelId = scheduledEvent.ChannelId; + } - if (scheduledEvent.EntityMetadata != null) + if (scheduledEvent.EntityMetadata != null) + { + if (EntityMetadata == null) { - if (EntityMetadata == null) - { - EntityMetadata = scheduledEvent.EntityMetadata; - } - else - { - EntityMetadata.Update(scheduledEvent.EntityMetadata); - } + EntityMetadata = scheduledEvent.EntityMetadata; } - - if (scheduledEvent.Name != null) + else { - Name = scheduledEvent.Name; + EntityMetadata.Update(scheduledEvent.EntityMetadata); } + } + + if (scheduledEvent.Name != null) + { + Name = scheduledEvent.Name; + } - if (scheduledEvent.Description != null) - { - Description = scheduledEvent.Description; - } - - PrivacyLevel = scheduledEvent.PrivacyLevel; - EntityType = scheduledEvent.EntityType; - Status = scheduledEvent.Status; - ScheduledStartTime = scheduledEvent.ScheduledStartTime; - ScheduledEndTime = scheduledEvent.ScheduledEndTime; + if (scheduledEvent.Description != null) + { + Description = scheduledEvent.Description; } + + PrivacyLevel = scheduledEvent.PrivacyLevel; + EntityType = scheduledEvent.EntityType; + Status = scheduledEvent.Status; + ScheduledStartTime = scheduledEvent.ScheduledStartTime; + ScheduledEndTime = scheduledEvent.ScheduledEndTime; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventCreate.cs b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventCreate.cs index ceed58bf2..7bca0237b 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventCreate.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventCreate.cs @@ -3,74 +3,73 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Scheduled Event Create within discord +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ScheduledEventCreate : IDiscordValidation { /// - /// Represents Guild Scheduled Event Create within discord + /// The channel ID in which the scheduled event will be hosted, or null if scheduled entity type is External /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ScheduledEventCreate : IDiscordValidation - { - /// - /// The channel ID in which the scheduled event will be hosted, or null if scheduled entity type is External - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } - /// - /// Additional metadata for the guild scheduled event - /// - [JsonProperty("entity_metadata")] - public ScheduledEventEntityMetadata EntityMetadata { get; set; } + /// + /// Additional metadata for the guild scheduled event + /// + [JsonProperty("entity_metadata")] + public ScheduledEventEntityMetadata EntityMetadata { get; set; } - /// - /// The name of the scheduled event (1-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// The name of the scheduled event (1-100 characters) + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// The privacy level of the scheduled event - /// - [JsonProperty("privacy_level")] - public ScheduledEventPrivacyLevel PrivacyLevel { get; set; } + /// + /// The privacy level of the scheduled event + /// + [JsonProperty("privacy_level")] + public ScheduledEventPrivacyLevel PrivacyLevel { get; set; } - /// - /// The time the scheduled event will start - /// - [JsonProperty("scheduled_start_time")] - public DateTime ScheduledStartTime { get; set; } + /// + /// The time the scheduled event will start + /// + [JsonProperty("scheduled_start_time")] + public DateTime ScheduledStartTime { get; set; } - /// - /// The time the scheduled event will end, required if EntityType is EXTERNAL - /// - [JsonProperty("scheduled_end_time ")] - public DateTime? ScheduledEndTime { get; set; } + /// + /// The time the scheduled event will end, required if EntityType is EXTERNAL + /// + [JsonProperty("scheduled_end_time ")] + public DateTime? ScheduledEndTime { get; set; } - /// - /// The description of the scheduled event (1-1000 characters) - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// The description of the scheduled event (1-1000 characters) + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// The type of the scheduled event - /// - [JsonProperty("entity_type")] - public ScheduledEventEntityType EntityType { get; set; } + /// + /// The type of the scheduled event + /// + [JsonProperty("entity_type")] + public ScheduledEventEntityType EntityType { get; set; } - /// - /// The cover image of the scheduled event - /// - [JsonProperty("image")] - public DiscordImageData Image { get; set; } + /// + /// The cover image of the scheduled event + /// + [JsonProperty("image")] + public DiscordImageData Image { get; set; } - /// - public void Validate() - { - InvalidGuildScheduledEventException.ThrowIfInvalidName(Name, false); - InvalidGuildScheduledEventException.ThrowIfInvalidDescription(Description); - EntityMetadata?.Validate(); - } + /// + public void Validate() + { + InvalidGuildScheduledEventException.ThrowIfInvalidName(Name, false); + InvalidGuildScheduledEventException.ThrowIfInvalidDescription(Description); + EntityMetadata?.Validate(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventEntityMetadata.cs b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventEntityMetadata.cs index 2d0b170ea..cc7573222 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventEntityMetadata.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventEntityMetadata.cs @@ -2,32 +2,31 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Scheduled Event Entity Metadata +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ScheduledEventEntityMetadata : IDiscordValidation { /// - /// Represents Guild Scheduled Event Entity Metadata + /// Location of the event (1-100 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ScheduledEventEntityMetadata : IDiscordValidation - { - /// - /// Location of the event (1-100 characters) - /// - [JsonProperty("location")] - public string Location { get; set; } + [JsonProperty("location")] + public string Location { get; set; } - internal void Update(ScheduledEventEntityMetadata metadata) + internal void Update(ScheduledEventEntityMetadata metadata) + { + if (metadata.Location != null) { - if (metadata.Location != null) - { - Location = metadata.Location; - } + Location = metadata.Location; } + } - /// - public void Validate() - { - InvalidGuildScheduledEventException.ThrowIfInvalidLocation(Location); - } + /// + public void Validate() + { + InvalidGuildScheduledEventException.ThrowIfInvalidLocation(Location); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventEntityType.cs b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventEntityType.cs index 243011ef3..e4c567c83 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventEntityType.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventEntityType.cs @@ -1,23 +1,22 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Scheduled Entity Type +/// +public enum ScheduledEventEntityType : byte { /// - /// Represents Scheduled Entity Type + /// Event will be held in a stage instance /// - public enum ScheduledEventEntityType : byte - { - /// - /// Event will be held in a stage instance - /// - StageInstance = 1, + StageInstance = 1, - /// - /// Event will be held in a voice channel - /// - Voice = 2, + /// + /// Event will be held in a voice channel + /// + Voice = 2, - /// - /// Event will be held externally outside of discord. - /// - External = 3, - } + /// + /// Event will be held externally outside of discord. + /// + External = 3, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventLookup.cs b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventLookup.cs index 09b83a706..0a7a3a098 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventLookup.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventLookup.cs @@ -1,29 +1,27 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Scheduled Event Lookup Structure within Discord. +/// +public class ScheduledEventLookup : IDiscordQueryString { /// - /// Represents a Scheduled Event Lookup Structure within Discord. + /// Include number of users subscribed to each event /// - public class ScheduledEventLookup : IDiscordQueryString - { - /// - /// Include number of users subscribed to each event - /// - public bool? WithUserCount { get; set; } + public bool? WithUserCount { get; set; } - /// - public string ToQueryString() + /// + public string ToQueryString() + { + QueryStringBuilder builder = new(); + if (WithUserCount.HasValue) { - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); - if (WithUserCount.HasValue) - { - builder.Add("with_user_count", WithUserCount.Value.ToString()); - } - - return builder.ToStringAndFree(); + builder.Add("with_user_count", WithUserCount.Value.ToString()); } + + return builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventPrivacyLevel.cs b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventPrivacyLevel.cs index 4158f96e5..4f89b19ac 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventPrivacyLevel.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventPrivacyLevel.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Scheduled Event Privacy Level +/// +public enum ScheduledEventPrivacyLevel : byte { /// - /// Represents Guild Scheduled Event Privacy Level + /// No Privacy Level /// - public enum ScheduledEventPrivacyLevel : byte - { - /// - /// No Privacy Level - /// - None = 0, + None = 0, - /// - /// The scheduled event is only accessible to guild members - /// - GuildOnly = 2 - } + /// + /// The scheduled event is only accessible to guild members + /// + GuildOnly = 2 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventStatus.cs b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventStatus.cs index 3558f046e..eb75da6cf 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventStatus.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventStatus.cs @@ -1,28 +1,27 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Scheduled Event Status +/// +public enum ScheduledEventStatus : byte { /// - /// Represents Guild Scheduled Event Status + /// Scheduled Event is scheduled and has not happened yet. /// - public enum ScheduledEventStatus : byte - { - /// - /// Scheduled Event is scheduled and has not happened yet. - /// - Scheduled = 1, + Scheduled = 1, - /// - /// Scheduled event is currently occuring - /// - Active = 2, + /// + /// Scheduled event is currently occuring + /// + Active = 2, - /// - /// Scheduled event has completed - /// - Completed = 3, + /// + /// Scheduled event has completed + /// + Completed = 3, - /// - /// Scheduled event was canceled. - /// - Canceled = 4, - } + /// + /// Scheduled event was canceled. + /// + Canceled = 4, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUpdate.cs b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUpdate.cs index b5d21880d..54e2a81ce 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUpdate.cs @@ -3,74 +3,73 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Scheduled Event Update within discord +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ScheduledEventUpdate : IDiscordValidation { /// - /// Represents Guild Scheduled Event Update within discord + /// The channel ID in which the scheduled event will be hosted, or null if scheduled entity type is External /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ScheduledEventUpdate : IDiscordValidation - { - /// - /// The channel ID in which the scheduled event will be hosted, or null if scheduled entity type is External - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } - /// - /// Additional metadata for the guild scheduled event - /// - [JsonProperty("entity_metadata")] - public ScheduledEventEntityMetadata EntityMetadata { get; set; } + /// + /// Additional metadata for the guild scheduled event + /// + [JsonProperty("entity_metadata")] + public ScheduledEventEntityMetadata EntityMetadata { get; set; } - /// - /// The name of the scheduled event (1-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// The name of the scheduled event (1-100 characters) + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// The privacy level of the scheduled event - /// - [JsonProperty("privacy_level")] - public ScheduledEventPrivacyLevel? PrivacyLevel { get; set; } + /// + /// The privacy level of the scheduled event + /// + [JsonProperty("privacy_level")] + public ScheduledEventPrivacyLevel? PrivacyLevel { get; set; } - /// - /// The time the scheduled event will start - /// - [JsonProperty("scheduled_start_time")] - public DateTime? ScheduledStartTime { get; set; } + /// + /// The time the scheduled event will start + /// + [JsonProperty("scheduled_start_time")] + public DateTime? ScheduledStartTime { get; set; } - /// - /// The time the scheduled event will end, required if EntityType is EXTERNAL - /// - [JsonProperty("scheduled_end_time ")] - public DateTime? ScheduledEndTime { get; set; } + /// + /// The time the scheduled event will end, required if EntityType is EXTERNAL + /// + [JsonProperty("scheduled_end_time ")] + public DateTime? ScheduledEndTime { get; set; } - /// - /// The description of the scheduled event (1-1000 characters) - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// The description of the scheduled event (1-1000 characters) + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// The type of the scheduled event - /// - [JsonProperty("entity_type")] - public ScheduledEventEntityType? EntityType { get; set; } + /// + /// The type of the scheduled event + /// + [JsonProperty("entity_type")] + public ScheduledEventEntityType? EntityType { get; set; } - /// - /// The status of the scheduled event - /// - [JsonProperty("status")] - public ScheduledEventStatus? Status { get; set; } + /// + /// The status of the scheduled event + /// + [JsonProperty("status")] + public ScheduledEventStatus? Status { get; set; } - /// - public void Validate() - { - InvalidGuildScheduledEventException.ThrowIfInvalidName(Name, true); - InvalidGuildScheduledEventException.ThrowIfInvalidDescription(Description); - EntityMetadata?.Validate(); - } + /// + public void Validate() + { + InvalidGuildScheduledEventException.ThrowIfInvalidName(Name, true); + InvalidGuildScheduledEventException.ThrowIfInvalidDescription(Description); + EntityMetadata?.Validate(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUser.cs b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUser.cs index a95fcb4cd..d1a075416 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUser.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUser.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Guild Scheduled Event User Object within discord +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ScheduledEventUser { /// - /// Represents Guild Scheduled Event User Object within discord + /// The scheduled event id which the user subscribed to /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ScheduledEventUser - { - /// - /// The scheduled event id which the user subscribed to - /// - [JsonProperty("guild_scheduled_event_id")] - public Snowflake GuildScheduledEventId { get; set; } + [JsonProperty("guild_scheduled_event_id")] + public Snowflake GuildScheduledEventId { get; set; } - /// - /// User which subscribed to an event - /// - [JsonProperty("guild_scheduled_event_id")] - public DiscordUser User { get; set; } + /// + /// User which subscribed to an event + /// + [JsonProperty("guild_scheduled_event_id")] + public DiscordUser User { get; set; } - /// - /// Guild member data for this user for the guild which this event belongs to, if any - /// - [JsonProperty("member")] - public GuildMember Member { get; set; } - } + /// + /// Guild member data for this user for the guild which this event belongs to, if any + /// + [JsonProperty("member")] + public GuildMember Member { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUsersLookup.cs b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUsersLookup.cs index 674e0828b..9d145c5e5 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUsersLookup.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/ScheduledEvents/ScheduledEventUsersLookup.cs @@ -1,75 +1,73 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Scheduled Event Lookup Structure within Discord. +/// +/// Provide a user id to before and after for pagination. +/// Users will always be returned in ascending order by user_id. +/// If both before and after are provided, only before is respected. +/// Fetching users in-between before and after is not supported. +/// +public class ScheduledEventUsersLookup : IDiscordQueryString, IDiscordValidation { /// - /// Represents a Scheduled Event Lookup Structure within Discord. - /// - /// Provide a user id to before and after for pagination. - /// Users will always be returned in ascending order by user_id. - /// If both before and after are provided, only before is respected. - /// Fetching users in-between before and after is not supported. + /// Number of users to return (up to maximum 100) /// - public class ScheduledEventUsersLookup : IDiscordQueryString, IDiscordValidation - { - /// - /// Number of users to return (up to maximum 100) - /// - public int? Limit { get; set; } + public int? Limit { get; set; } - /// - /// Include guild member data if it exists - /// Default false - /// - public bool? WithMember { get; set; } + /// + /// Include guild member data if it exists + /// Default false + /// + public bool? WithMember { get; set; } - /// - /// Consider only users before given user id - /// Default null - /// - public Snowflake? Before { get; set; } + /// + /// Consider only users before given user id + /// Default null + /// + public Snowflake? Before { get; set; } - /// - /// Consider only users after given user id - /// Default null - /// - public Snowflake? After { get; set; } + /// + /// Consider only users after given user id + /// Default null + /// + public Snowflake? After { get; set; } - /// - public string ToQueryString() + /// + public string ToQueryString() + { + Validate(); + QueryStringBuilder builder = new(); + if (Limit.HasValue) { - Validate(); - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); - if (Limit.HasValue) - { - builder.Add("limit", Limit.Value.ToString()); - } - - if (WithMember.HasValue) - { - builder.Add("with_member", WithMember.Value.ToString()); - } + builder.Add("limit", Limit.Value.ToString()); + } - if (Before.HasValue) - { - builder.Add("before", Before.Value.ToString()); - } + if (WithMember.HasValue) + { + builder.Add("with_member", WithMember.Value.ToString()); + } - if (After.HasValue) - { - builder.Add("after", After.Value.ToString()); - } - - return builder.ToStringAndFree(); + if (Before.HasValue) + { + builder.Add("before", Before.Value.ToString()); } - - /// - public void Validate() + + if (After.HasValue) { - InvalidGuildScheduledEventLookupException.ThrowIfInvalidLimit(Limit); + builder.Add("after", After.Value.ToString()); } + + return builder.ToString(); + } + + /// + public void Validate() + { + InvalidGuildScheduledEventLookupException.ThrowIfInvalidLimit(Limit); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/SystemChannelFlags.cs b/Oxide.Ext.Discord/Entities/Guilds/SystemChannelFlags.cs index b4d5605c0..b6e2ffbd0 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/SystemChannelFlags.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/SystemChannelFlags.cs @@ -1,48 +1,47 @@ using System; using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents System Channel Flags +/// +[Flags] +public enum SystemChannelFlags { /// - /// Represents System Channel Flags + /// Suppress member join notifications /// - [Flags] - public enum SystemChannelFlags - { - /// - /// Suppress member join notifications - /// - [DiscordEnum("SUPPRESS_JOIN_NOTIFICATIONS")] - SuppressJoinNotifications = 1 << 0, + [DiscordEnum("SUPPRESS_JOIN_NOTIFICATIONS")] + SuppressJoinNotifications = 1 << 0, - /// - /// Suppress server boost notifications - /// - [DiscordEnum("SUPPRESS_PREMIUM_SUBSCRIPTIONS")] - SuppressPremiumSubscriptions = 1 << 1, + /// + /// Suppress server boost notifications + /// + [DiscordEnum("SUPPRESS_PREMIUM_SUBSCRIPTIONS")] + SuppressPremiumSubscriptions = 1 << 1, - /// - /// Suppress server setup tips - /// - [DiscordEnum("SUPPRESS_GUILD_REMINDER_NOTIFICATIONS")] - SuppressGuildReminderNotifications = 1 << 2, + /// + /// Suppress server setup tips + /// + [DiscordEnum("SUPPRESS_GUILD_REMINDER_NOTIFICATIONS")] + SuppressGuildReminderNotifications = 1 << 2, - /// - /// Hide member join sticker reply buttons - /// - [DiscordEnum("SUPPRESS_JOIN_NOTIFICATION_REPLIES")] - SuppressJoinNotificationReplies = 1 << 3, + /// + /// Hide member join sticker reply buttons + /// + [DiscordEnum("SUPPRESS_JOIN_NOTIFICATION_REPLIES")] + SuppressJoinNotificationReplies = 1 << 3, - /// - /// Suppress role subscription purchase and renewal notifications - /// - [DiscordEnum("SUPPRESS_ROLE_SUBSCRIPTION_PURCHASE_NOTIFICATIONS")] - SuppressRoleSubscriptionPurchaseNotifications = 1 << 4, + /// + /// Suppress role subscription purchase and renewal notifications + /// + [DiscordEnum("SUPPRESS_ROLE_SUBSCRIPTION_PURCHASE_NOTIFICATIONS")] + SuppressRoleSubscriptionPurchaseNotifications = 1 << 4, - /// - /// Hide role subscription sticker reply buttons - /// - [DiscordEnum("SUPPRESS_ROLE_SUBSCRIPTION_PURCHASE_NOTIFICATION_REPLIES")] - SuppressRoleSubscriptionPurchaseNotificationReplies = 1 << 5, - } + /// + /// Hide role subscription sticker reply buttons + /// + [DiscordEnum("SUPPRESS_ROLE_SUBSCRIPTION_PURCHASE_NOTIFICATION_REPLIES")] + SuppressRoleSubscriptionPurchaseNotificationReplies = 1 << 5, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Guilds/WelcomeScreenUpdate.cs b/Oxide.Ext.Discord/Entities/Guilds/WelcomeScreenUpdate.cs index 003e7bf28..791f0ae75 100644 --- a/Oxide.Ext.Discord/Entities/Guilds/WelcomeScreenUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Guilds/WelcomeScreenUpdate.cs @@ -1,30 +1,29 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents +/// +public class WelcomeScreenUpdate { /// - /// Represents + /// Whether the welcome screen is enabled /// - public class WelcomeScreenUpdate - { - /// - /// Whether the welcome screen is enabled - /// - [JsonProperty("enabled")] - public bool Enabled { get; set; } + [JsonProperty("enabled")] + public bool Enabled { get; set; } - /// - /// Channels linked in the welcome screen and their display options - /// Up to 5 - /// - [JsonProperty("welcome_channels")] - public List WelcomeChannels { get; set; } + /// + /// Channels linked in the welcome screen and their display options + /// Up to 5 + /// + [JsonProperty("welcome_channels")] + public List WelcomeChannels { get; set; } - /// - /// The server description shown in the welcome screen - /// - [JsonProperty("description")] - public string Description { get; set; } - } + /// + /// The server description shown in the welcome screen + /// + [JsonProperty("description")] + public string Description { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Images/DiscordImageData.cs b/Oxide.Ext.Discord/Entities/Images/DiscordImageData.cs index 477bf507f..64b11ace5 100644 --- a/Oxide.Ext.Discord/Entities/Images/DiscordImageData.cs +++ b/Oxide.Ext.Discord/Entities/Images/DiscordImageData.cs @@ -8,154 +8,149 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Json; using Oxide.Ext.Discord.Libraries; +using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Discord Image Data +/// +[JsonConverter(typeof(DiscordImageDataConverter))] +public readonly struct DiscordImageData { /// - /// Represents Discord Image Data + /// The type of image /// - [JsonConverter(typeof(DiscordImageDataConverter))] - public struct DiscordImageData - { - /// - /// The type of image - /// - public readonly DiscordImageFormat Type; + public readonly DiscordImageFormat Type; - /// - /// The image data - /// - public readonly byte[] Image; + /// + /// The image data + /// + public readonly byte[] Image; - private static readonly Regex ImageDataRegex = new Regex("^data:image\\/(jpeg|png|gif){1};base64,([A-Za-z\\d+\\/]+)$", RegexOptions.Compiled); - private static readonly byte[] Gif = Encoding.ASCII.GetBytes("GIF"); - private static readonly byte[] Png = {137, 80, 78, 71}; - private static readonly byte[] Jpeg = {255, 216, 255, 224}; - private static readonly byte[] Jpeg2 = {255, 216, 255, 225}; + private static readonly Regex ImageDataRegex = new(@"^data:image\/(jpeg|png|gif){1};base64,([A-Za-z\d+\/]+)$", RegexOptions.Compiled); + private static readonly byte[] Gif = "GIF"u8.ToArray(); + private static readonly byte[] Png = [137, 80, 78, 71]; + private static readonly byte[] Jpeg = [255, 216, 255, 224]; + private static readonly byte[] Jpeg2 = [255, 216, 255, 225]; - private const double KiloBytes = 1024; - private const double MegaBytes = KiloBytes * 1024; - private const double Gigabytes = MegaBytes * 1024; + private const double KiloBytes = 1024; + private const double MegaBytes = KiloBytes * 1024; + private const double Gigabytes = MegaBytes * 1024; - /// - /// Constructor from a byte[] of the image - /// - /// Image bytes - public DiscordImageData(byte[] image) - { - InvalidImageDataException.ThrowIfInvalidImageBytes(image); - Type = GetType(image); - Image = image; - } + /// + /// Constructor from a byte[] of the image + /// + /// Image bytes + public DiscordImageData(byte[] image) + { + InvalidImageDataException.ThrowIfInvalidImageBytes(image); + Type = GetType(image); + Image = image; + } - /// - /// Creates DiscordImageData from a stream - /// - /// - public DiscordImageData(Stream stream) + /// + /// Creates DiscordImageData from a stream + /// + /// + public DiscordImageData(Stream stream) + { + MemoryStream memoryStream = DiscordPool.Internal.GetMemoryStream(); + stream.CopyToPooled(memoryStream); + byte[] image = memoryStream.ToArray(); + Type = GetType(image); + Image = image; + DiscordPool.Internal.FreeMemoryStream(memoryStream); + } + + /// + /// Constructor from the discord image data format + /// + /// string base64 image + /// Thrown if the image is not a valid base64 image string + public DiscordImageData(string image) + { + Match match = ImageDataRegex.Match(image); + InvalidImageDataException.ThrowIfInvalidBase64String(match, image); + Type = (DiscordImageFormat)Enum.Parse(typeof(DiscordImageFormat), match.Groups[0].Value, true); + Image = Convert.FromBase64String(match.Groups[1].Value); + } + + /// + /// Returns the Base64 Image string for the image. + /// + /// + public string GetBase64Image() + { + ValueStringBuilder sb = new(); + sb.Append("data:image/"); + sb.Append(EnumCache.Instance.ToLower(Type)); + sb.Append(";base64,"); + sb.Append(Convert.ToBase64String(Image)); + return sb.ToString(); + } + + /// + /// Returns the image size in the given format + /// + /// + /// + /// + public double GetImageSize(DiscordImageSize size) + { + return size switch { - MemoryStream memoryStream = DiscordPool.Internal.GetMemoryStream(); - stream.CopyToPooled(memoryStream); - byte[] image = memoryStream.ToArray(); - Type = GetType(image); - Image = image; - DiscordPool.Internal.FreeMemoryStream(memoryStream); - } + DiscordImageSize.Bytes => Image.Length, + DiscordImageSize.KiloBytes => Image.Length / KiloBytes, + DiscordImageSize.MegaBytes => Image.Length / MegaBytes, + DiscordImageSize.GigaBytes => Image.Length / Gigabytes, + _ => throw new ArgumentOutOfRangeException(nameof(size), size, null) + }; + } - /// - /// Constructor from the discord image data format - /// - /// string base64 image - /// Thrown if the image is not a valid base64 image string - public DiscordImageData(string image) + /// + /// Returns if this struct has a valid image + /// + /// + public bool IsValid() => Image != null && Image.Length != 0; + + /// + /// Returns the type of image for the given bytes[] + /// + /// byte[] of the image + /// + /// Thrown if the byte[] image is not a valid supported type + private static DiscordImageFormat GetType(byte[] image) + { + byte first = image[0]; + if (first == Gif[0] && StartsWith(Gif, image)) { - Match match = ImageDataRegex.Match(image); - InvalidImageDataException.ThrowIfInvalidBase64String(match, image); - Type = (DiscordImageFormat)Enum.Parse(typeof(DiscordImageFormat), match.Groups[0].Value, true); - Image = Convert.FromBase64String(match.Groups[1].Value); + return DiscordImageFormat.Gif; } - - /// - /// Returns the Base64 Image string for the image. - /// - /// - public string GetBase64Image() + + if (first == Png[0] && StartsWith(Png, image)) { - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); - sb.Append("data:image/"); - sb.Append(EnumCache.Instance.ToLower(Type)); - sb.Append(";base64,"); - sb.Append(Convert.ToBase64String(Image)); - return DiscordPool.Internal.ToStringAndFree(sb); + return DiscordImageFormat.Png; } - /// - /// Returns the image size in the given format - /// - /// - /// - /// - public double GetImageSize(DiscordImageSize size) + if (first == Jpeg[0] && StartsWith(Jpeg, image) || StartsWith(Jpeg2, image)) { - switch (size) - { - case DiscordImageSize.Bytes: - return Image.Length; - case DiscordImageSize.KiloBytes: - return Image.Length / KiloBytes; - case DiscordImageSize.MegaBytes: - return Image.Length / MegaBytes; - case DiscordImageSize.GigaBytes: - return Image.Length / Gigabytes; - default: - throw new ArgumentOutOfRangeException(nameof(size), size, null); - } + return DiscordImageFormat.Jpg; } - /// - /// Returns if this struct has a valid image - /// - /// - public bool IsValid() => Image != null && Image.Length != 0; + throw new InvalidImageDataException("Image does not appear to be a support image of type GIF, PNG, or JPEG"); + } - /// - /// Returns the type of image for the given bytes[] - /// - /// byte[] of the image - /// - /// Thrown if the byte[] image is not a valid supported type - private static DiscordImageFormat GetType(byte[] image) + private static bool StartsWith(byte[] type, byte[] image) + { + for (int index = 1; index < type.Length; index++) { - byte first = image[0]; - if (first == Gif[0] && StartsWith(Gif, image)) - { - return DiscordImageFormat.Gif; - } - - if (first == Png[0] && StartsWith(Png, image)) - { - return DiscordImageFormat.Png; - } - - if (first == Jpeg[0] && StartsWith(Jpeg, image) || StartsWith(Jpeg2, image)) + if (type[index] != image[index]) { - return DiscordImageFormat.Jpg; + return false; } - - throw new InvalidImageDataException("Image does not appear to be a support image of type GIF, PNG, or JPEG"); } - private static bool StartsWith(byte[] type, byte[] image) - { - for (int index = 1; index < type.Length; index++) - { - if (type[index] != image[index]) - { - return false; - } - } - - return true; - } + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Images/DiscordImageFormat.cs b/Oxide.Ext.Discord/Entities/Images/DiscordImageFormat.cs index 38f59f787..60782ccb1 100644 --- a/Oxide.Ext.Discord/Entities/Images/DiscordImageFormat.cs +++ b/Oxide.Ext.Discord/Entities/Images/DiscordImageFormat.cs @@ -1,38 +1,37 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Image Formats +/// +public enum DiscordImageFormat : byte { /// - /// Represents Image Formats + /// Automatically pick the image format /// - public enum DiscordImageFormat : byte - { - /// - /// Automatically pick the image format - /// - Auto, + Auto, - /// - /// Return image as a JPG - /// - Jpg, + /// + /// Return image as a JPG + /// + Jpg, - /// - /// Return image as PNG - /// - Png, + /// + /// Return image as PNG + /// + Png, - /// - /// Return image as WebP - /// - WebP, + /// + /// Return image as WebP + /// + WebP, - /// - /// Return image as GIF - /// - Gif, + /// + /// Return image as GIF + /// + Gif, - /// - /// Lottie Image - /// - Lottie - } + /// + /// Lottie Image + /// + Lottie } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Images/DiscordImageSize.cs b/Oxide.Ext.Discord/Entities/Images/DiscordImageSize.cs index c91902a4c..eba292e89 100644 --- a/Oxide.Ext.Discord/Entities/Images/DiscordImageSize.cs +++ b/Oxide.Ext.Discord/Entities/Images/DiscordImageSize.cs @@ -1,28 +1,27 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents an image size +/// +public enum DiscordImageSize : byte { /// - /// Represents an image size + /// Image Size in bytes /// - public enum DiscordImageSize : byte - { - /// - /// Image Size in bytes - /// - Bytes, + Bytes, - /// - /// Image size in kilobytes - /// - KiloBytes, + /// + /// Image size in kilobytes + /// + KiloBytes, - /// - /// Image Size in megabytes - /// - MegaBytes, + /// + /// Image Size in megabytes + /// + MegaBytes, - /// - /// Image Size in gigabytes - /// - GigaBytes - } + /// + /// Image Size in gigabytes + /// + GigaBytes } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Integrations/Integration.cs b/Oxide.Ext.Discord/Entities/Integrations/Integration.cs index 347031f6c..7a5348cd1 100644 --- a/Oxide.Ext.Discord/Entities/Integrations/Integration.cs +++ b/Oxide.Ext.Discord/Entities/Integrations/Integration.cs @@ -2,85 +2,84 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Integration Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class Integration : IntegrationUpdate, ISnowflakeEntity { /// - /// Represents Integration Structure + /// Integration ID /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class Integration : IntegrationUpdate, ISnowflakeEntity - { - /// - /// Integration ID - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Integration Name - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Integration Name + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Integration type - /// See - /// - [JsonProperty("type")] - public IntegrationType Type { get; set; } + /// + /// Integration type + /// See + /// + [JsonProperty("type")] + public IntegrationType Type { get; set; } - /// - /// Is this integration enabled - /// - [JsonProperty("enabled")] - public bool? Enabled { get; set; } + /// + /// Is this integration enabled + /// + [JsonProperty("enabled")] + public bool? Enabled { get; set; } - /// - /// Is this integration syncing - /// - [JsonProperty("syncing")] - public bool? Syncing { get; set; } + /// + /// Is this integration syncing + /// + [JsonProperty("syncing")] + public bool? Syncing { get; set; } - /// - /// ID that this integration uses for "subscribers" - /// - [JsonProperty("role_id")] - public Snowflake? RoleId { get; set; } + /// + /// ID that this integration uses for "subscribers" + /// + [JsonProperty("role_id")] + public Snowflake? RoleId { get; set; } - /// - /// User for this integration - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } + /// + /// User for this integration + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } - /// - /// Integration account information - /// - [JsonProperty("account")] - public IntegrationAccount Account { get; set; } + /// + /// Integration account information + /// + [JsonProperty("account")] + public IntegrationAccount Account { get; set; } - /// - /// When this integration was last synced - /// - [JsonProperty("synced_at")] - public DateTime? SyncedAt { get; set; } + /// + /// When this integration was last synced + /// + [JsonProperty("synced_at")] + public DateTime? SyncedAt { get; set; } - /// - /// How many subscribers this integration has - /// - [JsonProperty("subscriber_count")] - public int? SubscriberCount { get; set; } + /// + /// How many subscribers this integration has + /// + [JsonProperty("subscriber_count")] + public int? SubscriberCount { get; set; } - /// - /// Has this integration been revoked - /// - [JsonProperty("revoked")] - public bool? Revoked { get; set; } + /// + /// Has this integration been revoked + /// + [JsonProperty("revoked")] + public bool? Revoked { get; set; } - /// - /// The bot/OAuth2 application for discord integrations - /// - [JsonProperty("application")] - public IntegrationApplication Application { get; set; } - } -} + /// + /// The bot/OAuth2 application for discord integrations + /// + [JsonProperty("application")] + public IntegrationApplication Application { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Integrations/IntegrationAccount.cs b/Oxide.Ext.Discord/Entities/Integrations/IntegrationAccount.cs index 4348fb22b..c71fc22b4 100644 --- a/Oxide.Ext.Discord/Entities/Integrations/IntegrationAccount.cs +++ b/Oxide.Ext.Discord/Entities/Integrations/IntegrationAccount.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Integration Account Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class IntegrationAccount { /// - /// Represents Integration Account Structure + /// ID of the account /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class IntegrationAccount - { - /// - /// ID of the account - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Name of the account - /// - [JsonProperty("name")] - public string Name { get; set; } - } -} + /// + /// Name of the account + /// + [JsonProperty("name")] + public string Name { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Integrations/IntegrationApplication.cs b/Oxide.Ext.Discord/Entities/Integrations/IntegrationApplication.cs index dbbf7dad9..79e25ceb9 100644 --- a/Oxide.Ext.Discord/Entities/Integrations/IntegrationApplication.cs +++ b/Oxide.Ext.Discord/Entities/Integrations/IntegrationApplication.cs @@ -1,41 +1,40 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Integration Application Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class IntegrationApplication { /// - /// Represents Integration Application Structure + /// The ID of the app /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class IntegrationApplication - { - /// - /// The ID of the app - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The name of the app - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// The name of the app + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// The icon hash of the app - /// - [JsonProperty("icon")] - public string Icon { get; set; } + /// + /// The icon hash of the app + /// + [JsonProperty("icon")] + public string Icon { get; set; } - /// - /// The description of the app - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// The description of the app + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// The bot associated with this application - /// - [JsonProperty("bot")] - public DiscordUser Bot { get; set; } - } + /// + /// The bot associated with this application + /// + [JsonProperty("bot")] + public DiscordUser Bot { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Integrations/IntegrationExpireBehaviors.cs b/Oxide.Ext.Discord/Entities/Integrations/IntegrationExpireBehaviors.cs index 40fb1d096..992e18a10 100644 --- a/Oxide.Ext.Discord/Entities/Integrations/IntegrationExpireBehaviors.cs +++ b/Oxide.Ext.Discord/Entities/Integrations/IntegrationExpireBehaviors.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Integration Expire Behaviors +/// +public enum IntegrationExpireBehaviors : byte { /// - /// Represents Integration Expire Behaviors + /// Remove the role when integration expires /// - public enum IntegrationExpireBehaviors : byte - { - /// - /// Remove the role when integration expires - /// - RemoveRole = 0, + RemoveRole = 0, - /// - /// Kick when integration expires - /// - Kick = 1 - } + /// + /// Kick when integration expires + /// + Kick = 1 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Integrations/IntegrationType.cs b/Oxide.Ext.Discord/Entities/Integrations/IntegrationType.cs index 3445467ab..c7813d772 100644 --- a/Oxide.Ext.Discord/Entities/Integrations/IntegrationType.cs +++ b/Oxide.Ext.Discord/Entities/Integrations/IntegrationType.cs @@ -2,36 +2,35 @@ using Oxide.Ext.Discord.Attributes; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Integrations types +/// +[JsonConverter(typeof(DiscordEnumConverter))] +public enum IntegrationType : byte { /// - /// Represents Integrations types + /// Integration is for twitch /// - [JsonConverter(typeof(DiscordEnumConverter))] - public enum IntegrationType : byte - { - /// - /// Integration is for twitch - /// - [DiscordEnum("twitch")] - Twitch, + [DiscordEnum("twitch")] + Twitch, - /// - /// Integration is for youtube - /// - [DiscordEnum("youtube")] - Youtube, + /// + /// Integration is for youtube + /// + [DiscordEnum("youtube")] + Youtube, - /// - /// integration is for discord - /// - [DiscordEnum("discord")] - Discord, + /// + /// integration is for discord + /// + [DiscordEnum("discord")] + Discord, - /// - /// integration is for guild subscription - /// - [DiscordEnum("guild_subscription")] - GuildSubscription - } + /// + /// integration is for guild subscription + /// + [DiscordEnum("guild_subscription")] + GuildSubscription } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Integrations/IntegrationUpdate.cs b/Oxide.Ext.Discord/Entities/Integrations/IntegrationUpdate.cs index 4ab58669c..f5539d3b7 100644 --- a/Oxide.Ext.Discord/Entities/Integrations/IntegrationUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Integrations/IntegrationUpdate.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Integration Update Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class IntegrationUpdate { /// - /// Represents Integration Update Structure + /// Whether emoticons should be synced for this integration (twitch only currently) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class IntegrationUpdate - { - /// - /// Whether emoticons should be synced for this integration (twitch only currently) - /// - [JsonProperty("enable_emoticons")] - public bool? EnableEmoticons { get; set; } + [JsonProperty("enable_emoticons")] + public bool? EnableEmoticons { get; set; } - /// - /// The behavior when an integration subscription lapses - /// - [JsonProperty("expire_behaviour")] - public IntegrationExpireBehaviors? ExpireBehaviour { get; set; } + /// + /// The behavior when an integration subscription lapses + /// + [JsonProperty("expire_behaviour")] + public IntegrationExpireBehaviors? ExpireBehaviour { get; set; } - /// - /// Period (in days) where the integration will ignore lapsed subscriptions - /// - [JsonProperty("expire_grace_period")] - public int? ExpireGracePeriod { get; set; } - } + /// + /// Period (in days) where the integration will ignore lapsed subscriptions + /// + [JsonProperty("expire_grace_period")] + public int? ExpireGracePeriod { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/ApplicationCommandType.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/ApplicationCommandType.cs index f40b78d90..27e1309b1 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/ApplicationCommandType.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/ApplicationCommandType.cs @@ -1,28 +1,27 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Command Type +/// +public enum ApplicationCommandType : byte { /// - /// Represents Application Command Type + /// Slash commands; a text-based command that shows up when a user types / /// - public enum ApplicationCommandType : byte - { - /// - /// Slash commands; a text-based command that shows up when a user types / - /// - [DiscordEnum("CHAT_INPUT")] - ChatInput = 1, + [DiscordEnum("CHAT_INPUT")] + ChatInput = 1, - /// - /// A UI-based command that shows up when you right click or tap on a user - /// - [DiscordEnum("USER")] - User = 2, + /// + /// A UI-based command that shows up when you right click or tap on a user + /// + [DiscordEnum("USER")] + User = 2, - /// - /// A UI-based command that shows up when you right click or tap on a messages - /// - [DiscordEnum("MESSAGE")] - Message = 3 - } + /// + /// A UI-based command that shows up when you right click or tap on a messages + /// + [DiscordEnum("MESSAGE")] + Message = 3 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandBulkOverwrite.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandBulkOverwrite.cs index 75e96e415..739e0d24b 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandBulkOverwrite.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandBulkOverwrite.cs @@ -3,73 +3,72 @@ using Oxide.Ext.Discord.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Bulk Overwrite Guild Application Commands +/// +public class CommandBulkOverwrite { /// - /// Represents Bulk Overwrite Guild Application Commands + /// ID of command, if known /// - public class CommandBulkOverwrite - { - /// - /// ID of command, if known - /// - [JsonProperty("id")] - public Snowflake? Id { get; set; } + [JsonProperty("id")] + public Snowflake? Id { get; set; } - /// - /// 1-32 lowercase character name matching ^[\w-]{1,32}$ - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// 1-32 lowercase character name matching ^[\w-]{1,32}$ + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Localization dictionary for the name field. Values follow the same restrictions as name - /// - [JsonProperty("name_localizations")] - public Hash NameLocalizations { get; set; } + /// + /// Localization dictionary for the name field. Values follow the same restrictions as name + /// + [JsonProperty("name_localizations")] + public Hash NameLocalizations { get; set; } - /// - /// Description of the command (1-100 characters) - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of the command (1-100 characters) + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Localization dictionary for the description field. Values follow the same restrictions as description - /// - [JsonProperty("description_localizations")] - public Hash DescriptionLocalizations { get; set; } + /// + /// Localization dictionary for the description field. Values follow the same restrictions as description + /// + [JsonProperty("description_localizations")] + public Hash DescriptionLocalizations { get; set; } - /// - /// The parameters for the command - /// See - /// - [JsonProperty("options")] - public List Options { get; set; } + /// + /// The parameters for the command + /// See + /// + [JsonProperty("options")] + public List Options { get; set; } - /// - /// Set of permissions represented as a bit set - /// - [JsonProperty("default_member_permissions")] - [JsonConverter(typeof(PermissionFlagsStringConverter))] - public PermissionFlags DefaultMemberPermissions { get; set; } + /// + /// Set of permissions represented as a bit set + /// + [JsonProperty("default_member_permissions")] + [JsonConverter(typeof(PermissionFlagsStringConverter))] + public PermissionFlags DefaultMemberPermissions { get; set; } - /// - /// Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. - /// - [JsonProperty("dm_permission")] - public bool? DmPermission { get; set; } + /// + /// Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. + /// + [JsonProperty("dm_permission")] + public bool? DmPermission { get; set; } - /// - /// Whether the command is enabled by default when the app is added to a guild - /// - [JsonProperty("default_permission")] - public bool? DefaultPermissions { get; set; } + /// + /// Whether the command is enabled by default when the app is added to a guild + /// + [JsonProperty("default_permission")] + public bool? DefaultPermissions { get; set; } - /// - /// Indicates whether the command is age-restricted - /// - [JsonProperty("nsfw")] - public bool? Nsfw { get; set; } - } + /// + /// Indicates whether the command is age-restricted + /// + [JsonProperty("nsfw")] + public bool? Nsfw { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandCreate.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandCreate.cs index b1f507a71..3736ae38b 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandCreate.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandCreate.cs @@ -1,96 +1,109 @@ +using System; using System.Collections.Generic; using Newtonsoft.Json; using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Command Create +/// Represents Application Command Create +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class CommandCreate : IDiscordValidation { /// - /// Represents Application Command Create - /// Represents Application Command Create + /// 1-32 lowercase character name matching ^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$ /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class CommandCreate : IDiscordValidation - { - /// - /// 1-32 lowercase character name matching ^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$ - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Localization dictionary for the name field. Values follow the same restrictions as name - /// - [JsonProperty("name_localizations")] - public Hash NameLocalizations { get; set; } + /// + /// Localization dictionary for the name field. Values follow the same restrictions as name + /// + [JsonProperty("name_localizations")] + public Hash NameLocalizations { get; set; } - /// - /// Description of the command (1-100 characters) - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of the command (1-100 characters) + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Localization dictionary for the description field. Values follow the same restrictions as description - /// - [JsonProperty("description_localizations")] - public Hash DescriptionLocalizations { get; set; } + /// + /// Localization dictionary for the description field. Values follow the same restrictions as description + /// + [JsonProperty("description_localizations")] + public Hash DescriptionLocalizations { get; set; } - /// - /// The parameters for the command - /// See - /// - [JsonProperty("options")] - public List Options { get; set; } + /// + /// The parameters for the command + /// See + /// + [JsonProperty("options")] + public List Options { get; set; } - /// - /// Set of permissions represented as a bit set - /// - [JsonProperty("default_member_permissions")] - public PermissionFlags DefaultMemberPermissions { get; set; } + /// + /// Set of permissions represented as a bit set + /// + [JsonProperty("default_member_permissions")] + public PermissionFlags DefaultMemberPermissions { get; set; } - /// - /// Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. - /// - [JsonProperty("dm_permission")] - public bool? DmPermission { get; set; } + /// + /// Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. + /// + [Obsolete("Deprecated (use Contexts instead)")] + [JsonProperty("dm_permission")] + public bool? DmPermission { get; set; } + + /// + /// Installation context(s) where the command is available + /// + [JsonProperty("integration_types")] + public List IntegrationTypes { get; set; } + + /// + /// Interaction context(s) where the command can be used + /// + [JsonProperty("contexts")] + public List Contexts { get; set; } - /// - /// Indicates whether the command is age-restricted - /// - [JsonProperty("nsfw")] - public bool? Nsfw { get; set; } + /// + /// The of the command + /// + [JsonProperty("type")] + public ApplicationCommandType Type { get; set; } - /// - /// The of the command - /// - [JsonProperty("type")] - public ApplicationCommandType Type { get; set; } + /// + /// Indicates whether the command is age-restricted + /// + [JsonProperty("nsfw")] + public bool? Nsfw { get; set; } - /// - /// Constructor - /// - public CommandCreate() { } + /// + /// Constructor + /// + public CommandCreate() { } - /// - /// Constructor - /// - public CommandCreate(string name, string description, ApplicationCommandType type = ApplicationCommandType.ChatInput, List options = null) - { - Name = name; - Description = description; - Type = type; - Options = options; - NameLocalizations = new Hash(); - DescriptionLocalizations = new Hash(); - } + /// + /// Constructor + /// + public CommandCreate(string name, string description, ApplicationCommandType type = ApplicationCommandType.ChatInput, List options = null) + { + Name = name; + Description = description; + Type = type; + Options = options; + NameLocalizations = new Hash(); + DescriptionLocalizations = new Hash(); + } - /// - public void Validate() - { - InvalidApplicationCommandException.ThrowIfInvalidName(Name, false); - InvalidApplicationCommandException.ThrowIfInvalidDescription(Description, Type); - } + /// + public void Validate() + { + InvalidApplicationCommandException.ThrowIfInvalidName(Name, false); + InvalidApplicationCommandException.ThrowIfInvalidDescription(Description, Type); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandFollowupCreate.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandFollowupCreate.cs index e8e66e361..ec1573bcf 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandFollowupCreate.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandFollowupCreate.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Command Followup within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class CommandFollowupCreate : BaseInteractionMessage { - /// - /// Represents a Command Followup within discord. - /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class CommandFollowupCreate : BaseInteractionMessage - { - } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandFollowupUpdate.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandFollowupUpdate.cs index 1a62ed499..db946fc55 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandFollowupUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandFollowupUpdate.cs @@ -1,18 +1,17 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Command Followup within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class CommandFollowupUpdate : WebhookEditMessage { /// - /// Represents a Command Followup within discord. + /// Callback data flags + /// Set to 64 to make your response ephemeral /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class CommandFollowupUpdate : WebhookEditMessage - { - /// - /// Callback data flags - /// Set to 64 to make your response ephemeral - /// - [JsonProperty("flags")] - public MessageFlags? Flags { get; set; } - } + [JsonProperty("flags")] + public MessageFlags? Flags { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOption.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOption.cs index ae8f97e4e..7ab9827b1 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOption.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOption.cs @@ -2,120 +2,119 @@ using Newtonsoft.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents ApplicationCommandOption +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class CommandOption { /// - /// Represents ApplicationCommandOption + /// Type of option + /// See /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class CommandOption - { - /// - /// Type of option - /// See - /// - [JsonProperty("type")] - public CommandOptionType Type { get; set; } + [JsonProperty("type")] + public CommandOptionType Type { get; set; } - /// - /// Name of the command option (1-32 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the command option (1-32 characters) + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Localization dictionary for the name field. Values follow the same restrictions as name - /// - [JsonProperty("name_localizations")] - public Hash NameLocalizations { get; set; } + /// + /// Localization dictionary for the name field. Values follow the same restrictions as name + /// + [JsonProperty("name_localizations")] + public Hash NameLocalizations { get; set; } - /// - /// Description the command option (1-100 characters) - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description the command option (1-100 characters) + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Localization dictionary for the description field. Values follow the same restrictions as description - /// - [JsonProperty("description_localizations")] - public Hash DescriptionLocalizations { get; set; } + /// + /// Localization dictionary for the description field. Values follow the same restrictions as description + /// + [JsonProperty("description_localizations")] + public Hash DescriptionLocalizations { get; set; } - /// - /// If the parameter is required or optional - /// Defaults to false - /// - [JsonProperty("required")] - public bool? Required { get; set; } + /// + /// If the parameter is required or optional + /// Defaults to false + /// + [JsonProperty("required")] + public bool? Required { get; set; } - /// - /// Choices for STRING, INTEGER, and NUMBER types for the user to pick from, max 25 - /// See - /// - [JsonProperty("choices")] - public List Choices { get; set; } + /// + /// Choices for STRING, INTEGER, and NUMBER types for the user to pick from, max 25 + /// See + /// + [JsonProperty("choices")] + public List Choices { get; set; } - /// - /// If the option is a subcommand or subcommand group type, these nested options will be the parameters - /// See - /// - [JsonProperty("options")] - public List Options { get; set; } + /// + /// If the option is a subcommand or subcommand group type, these nested options will be the parameters + /// See + /// + [JsonProperty("options")] + public List Options { get; set; } - /// - /// If the option is a channel type, the channels shown will be restricted to these types - /// See - /// - [JsonProperty("channel_types")] - public List ChannelTypes { get; set; } + /// + /// If the option is a channel type, the channels shown will be restricted to these types + /// See + /// + [JsonProperty("channel_types")] + public List ChannelTypes { get; set; } - /// - /// If the option is an INTEGER or NUMBER type, the minimum value permitted - /// - [JsonProperty("min_value")] - public double? MinValue { get; set; } + /// + /// If the option is an INTEGER or NUMBER type, the minimum value permitted + /// + [JsonProperty("min_value")] + public double? MinValue { get; set; } - /// - /// If the option is an INTEGER or NUMBER type, the maximum value permitted - /// - [JsonProperty("max_value")] - public double? MaxValue { get; set; } + /// + /// If the option is an INTEGER or NUMBER type, the maximum value permitted + /// + [JsonProperty("max_value")] + public double? MaxValue { get; set; } - /// - /// For option type STRING, the minimum allowed length (minimum of 0) - /// - [JsonProperty("min_length")] - public int? MinLength { get; set; } + /// + /// For option type STRING, the minimum allowed length (minimum of 0) + /// + [JsonProperty("min_length")] + public int? MinLength { get; set; } - /// - /// For option type STRING, the maximum allowed length (minimum of 1) - /// - [JsonProperty("max_length")] - public int? MaxLength { get; set; } + /// + /// For option type STRING, the maximum allowed length (minimum of 1) + /// + [JsonProperty("max_length")] + public int? MaxLength { get; set; } - /// - /// If autocomplete interactions are enabled for this `STRING`, `INTEGER`, or `NUMBER` type option - /// - [JsonProperty("autocomplete")] - public bool? Autocomplete { get; set; } + /// + /// If autocomplete interactions are enabled for this `STRING`, `INTEGER`, or `NUMBER` type option + /// + [JsonProperty("autocomplete")] + public bool? Autocomplete { get; set; } - /// - /// Constructor - /// - [JsonConstructor] - public CommandOption() { } + /// + /// Constructor + /// + [JsonConstructor] + public CommandOption() { } - /// - /// Constructor - /// - public CommandOption(string name, string description, CommandOptionType type, List options = null) - { - Name = name; - Description = description; - Type = type; - Options = options; - NameLocalizations = new Hash(); - DescriptionLocalizations = new Hash(); - } + /// + /// Constructor + /// + public CommandOption(string name, string description, CommandOptionType type, List options = null) + { + Name = name; + Description = description; + Type = type; + Options = options; + NameLocalizations = new Hash(); + DescriptionLocalizations = new Hash(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOptionChoice.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOptionChoice.cs index 8bd25a539..03410a389 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOptionChoice.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOptionChoice.cs @@ -1,51 +1,50 @@ using Newtonsoft.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents ApplicationCommandOptionChoice +/// If you specify choices for an option, they are the only valid values for a user to pick +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class CommandOptionChoice { /// - /// Represents ApplicationCommandOptionChoice - /// If you specify choices for an option, they are the only valid values for a user to pick + /// Choice name (1-100 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class CommandOptionChoice - { - /// - /// Choice name (1-100 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Localization dictionary for the name field. Values follow the same restrictions as name - /// - [JsonProperty("name_localizations")] - public Hash NameLocalizations { get; set; } + /// + /// Localization dictionary for the name field. Values follow the same restrictions as name + /// + [JsonProperty("name_localizations")] + public Hash NameLocalizations { get; set; } - /// - /// Type can be string, integer, double or boolean - /// Value of the choice, up to 100 characters if string - /// - [JsonProperty("value")] - public object Value { get; set; } + /// + /// Type can be string, integer, double or boolean + /// Value of the choice, up to 100 characters if string + /// + [JsonProperty("value")] + public object Value { get; set; } - /// - /// Default Constructor - /// - [JsonConstructor] - public CommandOptionChoice() { } + /// + /// Default Constructor + /// + [JsonConstructor] + public CommandOptionChoice() { } - /// - /// Creates a Command Option Choice - /// - /// Name of the choice - /// Value of the choice - /// Name localizations for the choice - public CommandOptionChoice(string name, object value, Hash nameLocalizations = null) - { - Name = name; - Value = value; - NameLocalizations = nameLocalizations; - } + /// + /// Creates a Command Option Choice + /// + /// Name of the choice + /// Value of the choice + /// Name localizations for the choice + public CommandOptionChoice(string name, object value, Hash nameLocalizations = null) + { + Name = name; + Value = value; + NameLocalizations = nameLocalizations; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOptionType.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOptionType.cs index 033a4bec2..958296afc 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOptionType.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandOptionType.cs @@ -1,64 +1,63 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents ApplicationCommandOptionType +/// +public enum CommandOptionType : byte { /// - /// Represents ApplicationCommandOptionType + /// The command option is a sub command /// - public enum CommandOptionType : byte - { - /// - /// The command option is a sub command - /// - SubCommand = 1, + SubCommand = 1, - /// - /// The command option is a sub command group - /// - SubCommandGroup = 2, + /// + /// The command option is a sub command group + /// + SubCommandGroup = 2, - /// - /// The sub command option is a string - /// - String = 3, + /// + /// The sub command option is a string + /// + String = 3, - /// - /// The sub command options is an integer - /// - Integer = 4, + /// + /// The sub command options is an integer + /// + Integer = 4, - /// - /// The sub command option is a boolean - /// - Boolean = 5, + /// + /// The sub command option is a boolean + /// + Boolean = 5, - /// - /// The sub command option is a user - /// - User = 6, + /// + /// The sub command option is a user + /// + User = 6, - /// - /// The sub command option is a channel - /// - Channel = 7, + /// + /// The sub command option is a channel + /// + Channel = 7, - /// - /// The sub command option is a Role - /// - Role = 8, + /// + /// The sub command option is a Role + /// + Role = 8, - /// - /// The sub command option is a Mentionable - /// Includes Users and Roles - /// - Mentionable = 9, + /// + /// The sub command option is a Mentionable + /// Includes Users and Roles + /// + Mentionable = 9, - /// - /// Any double between -2^53 and 2^53 - /// - Number = 10, + /// + /// Any double between -2^53 and 2^53 + /// + Number = 10, - /// - /// Attachment object - /// - Attachment = 11 - } + /// + /// Attachment object + /// + Attachment = 11 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandPermissionType.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandPermissionType.cs index 7b750ce40..7f279ef9d 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandPermissionType.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandPermissionType.cs @@ -1,28 +1,27 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents ApplicationCommandPermissionType +/// +public enum CommandPermissionType : byte { /// - /// Represents ApplicationCommandPermissionType + /// This permissions uses Role ID /// - public enum CommandPermissionType : byte - { - /// - /// This permissions uses Role ID - /// - [DiscordEnum("ROLE")] - Role = 1, + [DiscordEnum("ROLE")] + Role = 1, - /// - /// This permission uses User ID - /// - [DiscordEnum("USER")] - User = 2, + /// + /// This permission uses User ID + /// + [DiscordEnum("USER")] + User = 2, - /// - /// This permission uses Channel ID - /// - [DiscordEnum("CHANNEL")] - Channel = 3 - } + /// + /// This permission uses Channel ID + /// + [DiscordEnum("CHANNEL")] + Channel = 3 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandPermissions.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandPermissions.cs index 9839bdc09..c262bfa68 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandPermissions.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandPermissions.cs @@ -1,60 +1,59 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents ApplicationCommandPermissions +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class CommandPermissions { /// - /// Represents ApplicationCommandPermissions + /// The ID of the role or user /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class CommandPermissions - { - /// - /// The ID of the role or user - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The type of permissions - /// - /// - [JsonProperty("type")] - public CommandPermissionType Type { get; set; } + /// + /// The type of permissions + /// + /// + [JsonProperty("type")] + public CommandPermissionType Type { get; set; } - /// - /// True to allow, False to disallow - /// - [JsonProperty("permission")] - public bool Permission { get; set; } + /// + /// True to allow, False to disallow + /// + [JsonProperty("permission")] + public bool Permission { get; set; } - /// - /// Creates a new CommandPermissions that allows all guild members to use the application command - /// - /// Guild to allow the application command in - /// - public static CommandPermissions AllowAllGuildMembers(DiscordGuild guild) + /// + /// Creates a new CommandPermissions that allows all guild members to use the application command + /// + /// Guild to allow the application command in + /// + public static CommandPermissions AllowAllGuildMembers(DiscordGuild guild) + { + return new CommandPermissions { - return new CommandPermissions - { - Id = guild.Id, - Type = CommandPermissionType.Role, - Permission = true - }; - } + Id = guild.Id, + Type = CommandPermissionType.Role, + Permission = true + }; + } - /// - /// Creates a new CommandPermissions that allows the application command to be used in all guild channels - /// - /// Guild to allow the application command in - /// - public static CommandPermissions AllowAllGuildChannels(DiscordGuild guild) + /// + /// Creates a new CommandPermissions that allows the application command to be used in all guild channels + /// + /// Guild to allow the application command in + /// + public static CommandPermissions AllowAllGuildChannels(DiscordGuild guild) + { + return new CommandPermissions { - return new CommandPermissions - { - Id = new Snowflake(guild.Id.Id - 1), - Type = CommandPermissionType.Role, - Permission = true - }; - } + Id = new Snowflake(guild.Id.Id - 1), + Type = CommandPermissionType.Role, + Permission = true + }; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandUpdate.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandUpdate.cs index 5ee5f1e94..19e20d7e1 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandUpdate.cs @@ -1,70 +1,83 @@ +using System; using System.Collections.Generic; using Newtonsoft.Json; using Oxide.Ext.Discord.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Command Update +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class CommandUpdate { /// - /// Represents Application Command Update + /// 1-32 lowercase character name matching ^[\w-]{1,32}$ /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class CommandUpdate - { - /// - /// 1-32 lowercase character name matching ^[\w-]{1,32}$ - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Localization dictionary for the name field. Values follow the same restrictions as name - /// - [JsonProperty("name_localizations")] - public Hash NameLocalizations { get; set; } + /// + /// Localization dictionary for the name field. Values follow the same restrictions as name + /// + [JsonProperty("name_localizations")] + public Hash NameLocalizations { get; set; } - /// - /// Description of the command (1-100 characters) - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of the command (1-100 characters) + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Localization dictionary for the description field. Values follow the same restrictions as description - /// - [JsonProperty("description_localizations")] - public Hash DescriptionLocalizations { get; set; } + /// + /// Localization dictionary for the description field. Values follow the same restrictions as description + /// + [JsonProperty("description_localizations")] + public Hash DescriptionLocalizations { get; set; } - /// - /// The parameters for the command - /// See - /// - [JsonProperty("options")] - public List Options { get; set; } + /// + /// The parameters for the command + /// See + /// + [JsonProperty("options")] + public List Options { get; set; } - /// - /// Set of permissions represented as a bit set - /// - [JsonProperty("default_member_permissions")] - [JsonConverter(typeof(PermissionFlagsStringConverter))] - public PermissionFlags DefaultMemberPermissions { get; set; } + /// + /// Set of permissions represented as a bit set + /// + [JsonProperty("default_member_permissions")] + [JsonConverter(typeof(PermissionFlagsStringConverter))] + public PermissionFlags DefaultMemberPermissions { get; set; } - /// - /// Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. - /// - [JsonProperty("dm_permission")] - public bool? DmPermission { get; set; } + /// + /// Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. + /// + [Obsolete("Deprecated (use Contexts instead)")] + [JsonProperty("dm_permission")] + public bool? DmPermission { get; set; } + + /// + /// Whether the command is enabled by default when the app is added to a guild + /// + [JsonProperty("default_permission")] + public bool? DefaultPermissions { get; set; } - /// - /// Whether the command is enabled by default when the app is added to a guild - /// - [JsonProperty("default_permission")] - public bool? DefaultPermissions { get; set; } + /// + /// Installation context(s) where the command is available + /// + [JsonProperty("integration_types")] + public List IntegrationTypes { get; set; } - /// - /// Indicates whether the command is age-restricted - /// - [JsonProperty("nsfw")] - public bool? Nsfw { get; set; } - } + /// + /// Interaction context(s) where the command can be used + /// + [JsonProperty("contexts")] + public List Contexts { get; set; } + + /// + /// Indicates whether the command is age-restricted + /// + [JsonProperty("nsfw")] + public bool? Nsfw { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandUpdatePermissions.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandUpdatePermissions.cs index 8b37112cd..bff5bd5aa 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandUpdatePermissions.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/CommandUpdatePermissions.cs @@ -1,17 +1,16 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Edit Application Command Permissions +/// +public class CommandUpdatePermissions { /// - /// Represents Edit Application Command Permissions + /// Permissions for the command in the guild /// - public class CommandUpdatePermissions - { - /// - /// Permissions for the command in the guild - /// - [JsonProperty("permissions")] - public List Permissions { get; set; } - } + [JsonProperty("permissions")] + public List Permissions { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/DiscordApplicationCommand.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/DiscordApplicationCommand.cs index 39ee4d85e..ddab901f3 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/DiscordApplicationCommand.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/DiscordApplicationCommand.cs @@ -9,189 +9,202 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents ApplicationCommand +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordApplicationCommand { /// - /// Represents ApplicationCommand + /// Unique id of the command /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordApplicationCommand - { - /// - /// Unique id of the command - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The type of command, defaults to 1 - /// - [JsonProperty("type")] - public ApplicationCommandType? Type { get; set; } + /// + /// The type of command, defaults to 1 + /// + [JsonProperty("type")] + public ApplicationCommandType? Type { get; set; } - /// - /// ID of the parent application - /// - [JsonProperty("application_id")] - public Snowflake ApplicationId { get; set; } + /// + /// ID of the parent application + /// + [JsonProperty("application_id")] + public Snowflake ApplicationId { get; set; } - /// - /// Guild ID of the command, if not global - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// Guild ID of the command, if not global + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// 1-32 lowercase character name matching ^[\w-]{1,32}$ - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// 1-32 lowercase character name matching ^[\w-]{1,32}$ + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Localization dictionary for the name field. Values follow the same restrictions as name - /// - [JsonProperty("name_localizations")] - public Hash NameLocalizations { get; set; } + /// + /// Localization dictionary for the name field. Values follow the same restrictions as name + /// + [JsonProperty("name_localizations")] + public Hash NameLocalizations { get; set; } - /// - /// Description of the command (1-100 characters) - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of the command (1-100 characters) + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Localization dictionary for the description field. Values follow the same restrictions as description - /// - [JsonProperty("description_localizations")] - public Hash DescriptionLocalizations { get; set; } + /// + /// Localization dictionary for the description field. Values follow the same restrictions as description + /// + [JsonProperty("description_localizations")] + public Hash DescriptionLocalizations { get; set; } - /// - /// The parameters for the command - /// See - /// - [JsonProperty("options")] - public List Options { get; set; } + /// + /// The parameters for the command + /// See + /// + [JsonProperty("options")] + public List Options { get; set; } - [JsonProperty("default_member_permissions")] - private string _defaultMemberPermissions; + [JsonProperty("default_member_permissions")] + private string _defaultMemberPermissions; - /// - /// Set of permissions represented as a bit set - /// - public PermissionFlags DefaultMemberPermissions - { - get => !string.IsNullOrEmpty(_defaultMemberPermissions) ? (PermissionFlags)ulong.Parse(_defaultMemberPermissions) : default(PermissionFlags); - set => _defaultMemberPermissions = StringCache.Instance.ToString((ulong)value); - } + /// + /// Set of permissions represented as a bit set + /// + public PermissionFlags DefaultMemberPermissions + { + get => !string.IsNullOrEmpty(_defaultMemberPermissions) ? (PermissionFlags)ulong.Parse(_defaultMemberPermissions) : default; + set => _defaultMemberPermissions = StringCache.Instance.ToString((ulong)value); + } - /// - /// Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. - /// - [JsonProperty("dm_permission")] - public bool? DmPermission { get; set; } + /// + /// Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. + /// + [JsonProperty("dm_permission")] + public bool? DmPermission { get; set; } - /// - /// Indicates whether the command is age-restricted - /// - [JsonProperty("nsfw")] - public bool? Nsfw { get; set; } + /// + /// Indicates whether the command is age-restricted + /// + [JsonProperty("nsfw")] + public bool? Nsfw { get; set; } + + /// + /// Installation context(s) where the command is available, only for globally-scoped commands. + /// Defaults to GUILD_INSTALL (0) + /// + [JsonProperty("integration_types")] + public List IntegrationTypes { get; set; } + + /// + /// Interaction context(s) where the command can be used, only for globally-scoped commands. + /// By default, all interaction context types included for new commands.. + /// + [JsonProperty("contexts")] + public List Contexts { get; set; } - /// - /// Auto incrementing version identifier updated during substantial record changes - /// - [JsonProperty("version")] - public Snowflake Version { get; set; } + /// + /// Auto incrementing version identifier updated during substantial record changes + /// + [JsonProperty("version")] + public Snowflake Version { get; set; } - /// - /// Mention the - /// - public string Mention => DiscordFormatting.MentionApplicationCommand(Id, Name); + /// + /// Mention the + /// + public string Mention => DiscordFormatting.MentionApplicationCommand(Id, Name); - /// - /// Mention the using a custom command string - /// - /// Custom commands string - /// Mentioned Custom Command string - public string MentionCustom(string command) => DiscordFormatting.MentionApplicationCommandCustom(Id, command); + /// + /// Mention the using a custom command string + /// + /// Custom commands string + /// Mentioned Custom Command string + public string MentionCustom(string command) => DiscordFormatting.MentionApplicationCommandCustom(Id, command); - /// - /// Edit a command. - /// Updates will be available in all guilds after 1 hour. - /// See Edit Global Application Command - /// See Edit Guild Application Command - /// - /// Client to use - /// Command Update - public IPromise Edit(DiscordClient client, CommandUpdate update) + /// + /// Edit a command. + /// Updates will be available in all guilds after 1 hour. + /// See Edit Global Application Command + /// See Edit Guild Application Command + /// + /// Client to use + /// Command Update + public IPromise Edit(DiscordClient client, CommandUpdate update) + { + if (update == null) throw new ArgumentNullException(nameof(update)); + if (GuildId.HasValue) { - if (update == null) throw new ArgumentNullException(nameof(update)); - if (GuildId.HasValue) - { - return client.Bot.Rest.Patch(client,$"applications/{ApplicationId}/guilds/{GuildId}/commands/{Id}", update); - } - - return client.Bot.Rest.Patch(client,$"applications/{ApplicationId}/commands/{Id}", update); + return client.Bot.Rest.Patch(client,$"applications/{ApplicationId}/guilds/{GuildId}/commands/{Id}", update); } + + return client.Bot.Rest.Patch(client,$"applications/{ApplicationId}/commands/{Id}", update); + } - /// - /// Deletes a command - /// See Delete Global Application Command - /// See Delete Guild Application Command - /// - /// Client to use - public IPromise Delete(DiscordClient client) + /// + /// Deletes a command + /// See Delete Global Application Command + /// See Delete Guild Application Command + /// + /// Client to use + public IPromise Delete(DiscordClient client) + { + if (GuildId.HasValue) { - if (GuildId.HasValue) - { - return client.Bot.Rest.Delete(client,$"applications/{ApplicationId}/guilds/{GuildId}/commands/{Id}"); - } - - return client.Bot.Rest.Delete(client,$"applications/{ApplicationId}/commands/{Id}"); + return client.Bot.Rest.Delete(client,$"applications/{ApplicationId}/guilds/{GuildId}/commands/{Id}"); } + + return client.Bot.Rest.Delete(client,$"applications/{ApplicationId}/commands/{Id}"); + } - /// - /// Fetches command permissions for a specific command for your application in a guild. Returns a object. - /// See Get Application Command Permissions - /// - /// Client to use - /// Guild ID of the guild to get permissions for - public IPromise GetPermissions(DiscordClient client, Snowflake guildId) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - IPendingPromise promise = Promise.Create(); + /// + /// Fetches command permissions for a specific command for your application in a guild. Returns a object. + /// See Get Application Command Permissions + /// + /// Client to use + /// Guild ID of the guild to get permissions for + public IPromise GetPermissions(DiscordClient client, Snowflake guildId) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + IPendingPromise promise = Promise.Create(); - client.Bot.Rest.Get(client, $"applications/{ApplicationId}/guilds/{guildId}/commands/{Id}/permissions") - .Then(perms => promise.Resolve(perms)) - .Catch(ex => - { - if (ex.DiscordError?.Code != 10066) - { - promise.Reject(ex); - return; - } + client.Bot.Rest.Get(client, $"applications/{ApplicationId}/guilds/{guildId}/commands/{Id}/permissions") + .Then(perms => promise.Resolve(perms)) + .Catch(ex => + { + if (ex.DiscordError?.Code != 10066) + { + promise.Reject(ex); + return; + } - ex.SuppressErrorMessage(); - //If the command is synced we need to lookup by application ID instead - client.Bot.Rest.Get(client, $"applications/{ApplicationId}/guilds/{guildId}/commands/{ApplicationId}/permissions") - .Then(perms => promise.Resolve(perms)) - .Catch(ex1 => promise.Reject(ex1)); - }); - return promise; - } + ex.SuppressErrorMessage(); + //If the command is synced we need to lookup by application ID instead + client.Bot.Rest.Get(client, $"applications/{ApplicationId}/guilds/{guildId}/commands/{ApplicationId}/permissions") + .Then(perms => promise.Resolve(perms)) + .Catch(ex1 => promise.Reject(ex1)); + }); + return promise; + } - /// - /// Edits command permissions for a specific command for your application in a guild. - /// Warning: This endpoint will overwrite existing permissions for the command in that guild - /// Warning: Deleting or renaming a command will permanently delete all permissions for that command - /// See Edit Application Command Permissions - /// - /// Client to use - /// Guild ID of the guild to edit permissions for - /// List of permissions for the command - public IPromise EditPermissions(DiscordClient client, Snowflake guildId, CommandUpdatePermissions permissions) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Put(client,$"applications/{ApplicationId}/guilds/{guildId}/commands/{Id}/permissions", permissions); - } + /// + /// Edits command permissions for a specific command for your application in a guild. + /// Warning: This endpoint will overwrite existing permissions for the command in that guild + /// Warning: Deleting or renaming a command will permanently delete all permissions for that command + /// See Edit Application Command Permissions + /// + /// Client to use + /// Guild ID of the guild to edit permissions for + /// List of permissions for the command + public IPromise EditPermissions(DiscordClient client, Snowflake guildId, CommandUpdatePermissions permissions) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Put(client,$"applications/{ApplicationId}/guilds/{guildId}/commands/{Id}/permissions", permissions); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/GuildCommandPermissions.cs b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/GuildCommandPermissions.cs index 2c0e06008..7b015f5cd 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/GuildCommandPermissions.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/ApplicationCommands/GuildCommandPermissions.cs @@ -1,36 +1,35 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents ApplicationCommandPermissions +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildCommandPermissions { /// - /// Represents ApplicationCommandPermissions + /// ID of the command /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildCommandPermissions - { - /// - /// ID of the command - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// ID of the application the command belongs to - /// - [JsonProperty("application_id")] - public Snowflake ApplicationId { get; set; } + /// + /// ID of the application the command belongs to + /// + [JsonProperty("application_id")] + public Snowflake ApplicationId { get; set; } - /// - /// ID of the guild - /// - [JsonProperty("guild_id")] - public Snowflake GuildId { get; set; } + /// + /// ID of the guild + /// + [JsonProperty("guild_id")] + public Snowflake GuildId { get; set; } - /// - /// Permissions for the command in the guild - /// - [JsonProperty("permissions")] - public List Permissions { get; set; } - } + /// + /// Permissions for the command in the guild + /// + [JsonProperty("permissions")] + public List Permissions { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/DiscordInteraction.cs b/Oxide.Ext.Discord/Entities/Interactions/DiscordInteraction.cs index 0b40427b6..6eae0140e 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/DiscordInteraction.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/DiscordInteraction.cs @@ -9,563 +9,572 @@ using Oxide.Ext.Discord.Json; using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Rest; +using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Interaction Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordInteraction { /// - /// Represents Interaction Structure + /// Id of the interaction /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordInteraction - { - /// - /// Id of the interaction - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } - - /// - /// ID of the application this interaction is for - /// - [JsonProperty("application_id")] - public Snowflake ApplicationId { get; set; } - - /// - /// The type of interaction - /// See - /// - [JsonProperty("type")] - public InteractionType Type { get; set; } - - /// - /// Interaction data payload - /// See - /// - [JsonProperty("data")] - public InteractionData Data { get; set; } - - /// - /// Guild that the interaction was sent from - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } + + /// + /// ID of the application this interaction is for + /// + [JsonProperty("application_id")] + public Snowflake ApplicationId { get; set; } + + /// + /// The type of interaction + /// See + /// + [JsonProperty("type")] + public InteractionType Type { get; set; } + + /// + /// Interaction data payload + /// See + /// + [JsonProperty("data")] + public InteractionData Data { get; set; } + + /// + /// Guild that the interaction was sent from + /// + [JsonProperty("guild")] + public DiscordGuild Guild { get; set; } + + /// + /// Guild that the interaction was sent from + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// Channel that the interaction was sent from - /// - [JsonProperty("channel")] - public DiscordChannel Channel { get; set; } - - /// - /// Channel that the interaction was sent from - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } - - /// - /// Guild member data for the invoking user, including permissions - /// - [JsonProperty("member")] - public GuildMember Member { get; set; } - - [JsonProperty("user")] + /// + /// Channel that the interaction was sent from + /// + [JsonProperty("channel")] + public DiscordChannel Channel { get; set; } + + /// + /// Channel that the interaction was sent from + /// + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } + + /// + /// Guild member data for the invoking user, including permissions + /// + [JsonProperty("member")] + public GuildMember Member { get; set; } + + [JsonProperty("user")] #pragma warning disable CS0649 - private DiscordUser _user; + private DiscordUser _user; #pragma warning restore CS0649 - /// - /// User object. If in DM then DM user else GuildMember.User - /// - public DiscordUser User => _user ?? Member?.User; - - /// - /// Continuation token for responding to the interaction - /// Interaction tokens are valid for 15 minutes and can be used to send followup messages but you must send an initial response within 3 seconds of receiving the event. - /// If the 3 second deadline is exceeded, the token will be invalidated. - /// - [JsonProperty("token")] - public string Token { get; set; } - - /// - /// Read-only property, always 1 - /// - [JsonProperty("version")] - public int Version { get; set; } - - /// - /// For components, the message they were attached to - /// - [JsonProperty("message")] - public DiscordMessage Message { get; set; } - - /// - /// Bitwise set of permissions the app or bot has within the channel the interaction was sent from - /// - [JsonConverter(typeof(PermissionFlagsStringConverter))] - [JsonProperty("app_permissions")] - public PermissionFlags? AppPermissions { get; set; } + /// + /// User object. If in DM then DM user else GuildMember.User + /// + public DiscordUser User => _user ?? Member?.User; + + /// + /// Continuation token for responding to the interaction + /// Interaction tokens are valid for 15 minutes and can be used to send followup messages but you must send an initial response within 3 seconds of receiving the event. + /// If the 3 second deadline is exceeded, the token will be invalidated. + /// + [JsonProperty("token")] + public string Token { get; set; } + + /// + /// Read-only property, always 1 + /// + [JsonProperty("version")] + public int Version { get; set; } + + /// + /// For components, the message they were attached to + /// + [JsonProperty("message")] + public DiscordMessage Message { get; set; } + + /// + /// Bitwise set of permissions the app has in the source location of the interaction + /// + [JsonConverter(typeof(PermissionFlagsStringConverter))] + [JsonProperty("app_permissions")] + public PermissionFlags? AppPermissions { get; set; } - /// - /// The selected language of the invoking user - /// Discord Locale Values - /// - [JsonProperty("locale")] - public DiscordLocale Locale { get; set; } - - /// - /// The guild's preferred locale, if invoked in a guild - /// Discord Locale Values - /// - [JsonProperty("guild_locale")] - public DiscordLocale? GuildLocale { get; set; } + /// + /// The selected language of the invoking user + /// Discord Locale Values + /// + [JsonProperty("locale")] + public DiscordLocale Locale { get; set; } + + /// + /// The guild's preferred locale, if invoked in a guild + /// Discord Locale Values + /// + [JsonProperty("guild_locale")] + public DiscordLocale? GuildLocale { get; set; } - /// - /// For monetized apps, any entitlements for the invoking user, representing access to premium SKUs - /// - [JsonProperty("entitlements")] - public List Entitlements { get; set; } - - private InteractionDataParsed _parsed; - - /// - /// Returns the interaction parsed args to make it easier to process that interaction. - /// - public InteractionDataParsed Parsed => _parsed ?? (_parsed = new InteractionDataParsed(this)); - - private InteractionDataOption _focused; - - /// - /// Returns the Focused option for Auto Complete - /// - public InteractionDataOption Focused => _focused ?? (_focused = GetFocusedOption()); - - /// - /// The UTC DateTime this interaction was created - /// - public readonly DateTime CreatedDate = DateTime.UtcNow; - - /// - /// If CreateInteractionResponse has been successfully called for this interaction - /// - private bool _hasResponded; - - /// - /// Returns a localized string for this interaction - /// - /// Plugin the localization is for - /// Lang Key to return - /// Localized string if it is found; Empty string otherwise - public string GetLangMessage(Plugin plugin, string langKey) => DiscordLocales.Instance.GetDiscordInteractionLangMessage(plugin, this, langKey); + /// + /// For monetized apps, any entitlements for the invoking user, representing access to premium SKUs + /// + [JsonProperty("entitlements")] + public List Entitlements { get; set; } - /// - /// Returns a localized string for this interaction - /// - /// Plugin the localization is for - /// Lang Key to return - /// Localization args - /// Localized string if it is found; Empty string otherwise - public string GetLangMessage(Plugin plugin, string langKey, params object[] args) => DiscordLocales.Instance.GetDiscordInteractionLangMessage(plugin, this, langKey, args); + /// + /// Mapping of installation contexts that the interaction was authorized for to related user or guild IDs + /// + [JsonProperty("authorizing_integration_owners")] + public Hash AuthorizingIntegrationOwners { get; set; } - private InteractionDataOption GetFocusedOption() + /// + /// Context where the interaction was triggered from + /// + [JsonProperty("contexts")] + public List Contexts { get; set; } + + private InteractionDataParsed _parsed; + + /// + /// Returns the interaction parsed args to make it easier to process that interaction. + /// + public InteractionDataParsed Parsed => _parsed ?? (_parsed = new InteractionDataParsed(this)); + + private InteractionDataOption _focused; + + /// + /// Returns the Focused option for Auto Complete + /// + public InteractionDataOption Focused => _focused ?? (_focused = GetFocusedOption()); + + /// + /// The UTC DateTime this interaction was created + /// + public readonly DateTime CreatedDate = DateTime.UtcNow; + + /// + /// If CreateInteractionResponse has been successfully called for this interaction + /// + private bool _hasResponded; + + /// + /// Returns a localized string for this interaction + /// + /// Plugin the localization is for + /// Lang Key to return + /// Localized string if it is found; Empty string otherwise + public string GetLangMessage(Plugin plugin, string langKey) => DiscordLocales.Instance.GetDiscordInteractionLangMessage(plugin, this, langKey); + + /// + /// Returns a localized string for this interaction + /// + /// Plugin the localization is for + /// Lang Key to return + /// Localization args + /// Localized string if it is found; Empty string otherwise + public string GetLangMessage(Plugin plugin, string langKey, params object[] args) => DiscordLocales.Instance.GetDiscordInteractionLangMessage(plugin, this, langKey, args); + + private InteractionDataOption GetFocusedOption() + { + if (Type != InteractionType.ApplicationCommandAutoComplete) { - if (Type != InteractionType.ApplicationCommandAutoComplete) - { - return null; - } + return null; + } - List options = Data.Options; - if (options == null) - { - return null; - } + List options = Data.Options; + if (options == null) + { + return null; + } - for (int index = 0; index < options.Count;) + for (int index = 0; index < options.Count;) + { + InteractionDataOption option = options[index]; + if (option.Type == CommandOptionType.SubCommand || option.Type == CommandOptionType.SubCommandGroup) { - InteractionDataOption option = options[index]; - if (option.Type == CommandOptionType.SubCommand || option.Type == CommandOptionType.SubCommandGroup) - { - options = option.Options; - index = 0; - continue; - } - - if (option.Focused.HasValue && option.Focused.Value) - { - return option; - } + options = option.Options; + index = 0; + continue; + } - index++; + if (option.Focused.HasValue && option.Focused.Value) + { + return option; } - return null; + index++; } - internal AppCommandId GetCommandId() - { - string command = Data.Name; - string group = null; - string subCommand = null; - string argument = null; + return null; + } - switch (Type) - { - case InteractionType.MessageComponent: - case InteractionType.ModalSubmit: - return new AppCommandId(Type, Data.CustomId); - } + internal AppCommandId GetCommandId() + { + string command = Data.Name; + string group = null; + string subCommand = null; + string argument = null; + + switch (Type) + { + case InteractionType.MessageComponent: + case InteractionType.ModalSubmit: + return new AppCommandId(Type, Data.CustomId); + } - List options = Data.Options; - if (options != null) + List options = Data.Options; + if (options != null) + { + for (int index = 0; index < options.Count;) { - for (int index = 0; index < options.Count;) + InteractionDataOption option = options[index]; + switch (option.Type) { - InteractionDataOption option = options[index]; - switch (option.Type) - { - case CommandOptionType.SubCommandGroup: - group = option.Name; - options = option.Options; - index = 0; - break; - case CommandOptionType.SubCommand: - subCommand = option.Name; - options = option.Options; - index = 0; - break; + case CommandOptionType.SubCommandGroup: + group = option.Name; + options = option.Options; + index = 0; + break; + case CommandOptionType.SubCommand: + subCommand = option.Name; + options = option.Options; + index = 0; + break; - default: - if (option.Focused.HasValue && option.Focused.Value) - { - argument = option.Name; - } - index++; - break; - } + default: + if (option.Focused.HasValue && option.Focused.Value) + { + argument = option.Name; + } + index++; + break; } } - - return new AppCommandId(Type, command, group, subCommand, argument); } + + return new AppCommandId(Type, command, group, subCommand, argument); + } - /// - /// Returns a for this interaction - /// - /// - public InteractionResponseBuilder GetResponseBuilder() - { - InvalidInteractionResponseException.ThrowIfAlreadyResponded(_hasResponded); - return new InteractionResponseBuilder(this); - } + /// + /// Returns a for this interaction + /// + /// + public InteractionResponseBuilder GetResponseBuilder() + { + InvalidInteractionResponseException.ThrowIfAlreadyResponded(_hasResponded); + return new InteractionResponseBuilder(this); + } - /// - /// Returns a for this interaction - /// - /// - public InteractionFollowupBuilder GetFollowupBuilder() - { - InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); - return new InteractionFollowupBuilder(this); - } + /// + /// Returns a for this interaction + /// + /// + public InteractionFollowupBuilder GetFollowupBuilder() + { + InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); + return new InteractionFollowupBuilder(this); + } - /// - /// Returns a for this interaction - /// - /// - public InteractionAutoCompleteBuilder GetAutoCompleteBuilder() - { - InvalidInteractionResponseException.ThrowIfAlreadyResponded(_hasResponded); - return new InteractionAutoCompleteBuilder(this); - } + /// + /// Returns a for this interaction + /// + /// + public InteractionAutoCompleteBuilder GetAutoCompleteBuilder() + { + InvalidInteractionResponseException.ThrowIfAlreadyResponded(_hasResponded); + return new InteractionAutoCompleteBuilder(this); + } - /// - /// Returns a for this interaction - /// - /// - public InteractionModalBuilder GetModalBuilder() - { - InvalidInteractionResponseException.ThrowIfAlreadyResponded(_hasResponded); - return new InteractionModalBuilder(this); - } + /// + /// Returns a for this interaction + /// + /// + public InteractionModalBuilder GetModalBuilder() + { + InvalidInteractionResponseException.ThrowIfAlreadyResponded(_hasResponded); + return new InteractionModalBuilder(this); + } - /// - /// Create a response to an Interaction from the gateway. - /// See Create Interaction Response - /// - /// Client to use - /// Response to respond with - public IPromise CreateResponse(DiscordClient client, BaseInteractionResponse response) - { - if (response == null) throw new ArgumentNullException(nameof(response)); - InvalidInteractionResponseException.ThrowIfAlreadyResponded(_hasResponded); - InvalidInteractionResponseException.ThrowIfInitialResponseTimeElapsed(CreatedDate); - InvalidInteractionResponseException.ThrowIfInvalidResponseType(Type, response.Type); + /// + /// Create a response to an Interaction from the gateway. + /// See Create Interaction Response + /// + /// Client to use + /// Response to respond with + public IPromise CreateResponse(DiscordClient client, BaseInteractionResponse response) + { + if (response == null) throw new ArgumentNullException(nameof(response)); + InvalidInteractionResponseException.ThrowIfAlreadyResponded(_hasResponded); + InvalidInteractionResponseException.ThrowIfInitialResponseTimeElapsed(CreatedDate); + InvalidInteractionResponseException.ThrowIfInvalidResponseType(Type, response.Type); - _hasResponded = true; - return client.Bot.Rest.Post(client, $"interactions/{Id}/{Token}/callback", response, RequestOptions.SkipRateLimit()); - } + _hasResponded = true; + return client.Bot.Rest.Post(client, $"interactions/{Id}/{Token}/callback", response, RequestOptions.SkipRateLimit()); + } - /// - /// Create a response to an Interaction from the gateway. - /// See Create Interaction Response - /// - /// Client to use - /// Type of the interaction response - /// Interaction Callback Message Data - public IPromise CreateResponse(DiscordClient client, InteractionResponseType type, InteractionCallbackData response = null) - { - InteractionResponse data = new InteractionResponse(type, response); - return CreateResponse(client, data); - } + /// + /// Create a response to an Interaction from the gateway. + /// See Create Interaction Response + /// + /// Client to use + /// Type of the interaction response + /// Interaction Callback Message Data + public IPromise CreateResponse(DiscordClient client, InteractionResponseType type, InteractionCallbackData response = null) + { + InteractionResponse data = new(type, response); + return CreateResponse(client, data); + } - /// - /// Creates a interaction message response from a message template - /// - /// Client to use - /// Response type for the interaction - /// Name of the template - /// Message to send (optional) - /// Placeholders to apply (optional) - /// Thrown if plugin or templateName is null - public IPromise CreateTemplateResponse(DiscordClient client, InteractionResponseType type, TemplateKey templateName, InteractionCallbackData message = null, PlaceholderData placeholders = null) - { - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + /// + /// Creates a interaction message response from a message template + /// + /// Client to use + /// Response type for the interaction + /// Name of the template + /// Message to send (optional) + /// Placeholders to apply (optional) + /// Thrown if plugin or templateName is null + public IPromise CreateTemplateResponse(DiscordClient client, InteractionResponseType type, TemplateKey templateName, InteractionCallbackData message = null, PlaceholderData placeholders = null) + { + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - InteractionCallbackData template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, this).ToMessage(placeholders, message); - return CreateResponse(client, type, template); - } + InteractionCallbackData template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, this).ToMessage(placeholders, message); + return CreateResponse(client, type, template); + } - /// - /// Creates a interaction modal response from a modal template - /// - /// Client to use - /// - /// Message to use (optional) - /// Placeholders to apply (optional) - /// - public IPromise CreateModalResponse(DiscordClient client, TemplateKey templateName, InteractionModalMessage message = null, PlaceholderData placeholders = null) - { - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + /// + /// Creates a interaction modal response from a modal template + /// + /// Client to use + /// + /// Message to use (optional) + /// Placeholders to apply (optional) + /// + public IPromise CreateModalResponse(DiscordClient client, TemplateKey templateName, InteractionModalMessage message = null, PlaceholderData placeholders = null) + { + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - InteractionModalMessage template = DiscordExtension.DiscordModalTemplates.GetLocalizedTemplate(client.Plugin, templateName, this).ToModal(placeholders, message); - return CreateResponse(client, template); - } + InteractionModalMessage template = DiscordExtension.DiscordModalTemplates.GetLocalizedTemplate(client.Plugin, templateName, this).ToModal(placeholders, message); + return CreateResponse(client, template); + } - /// - /// Create a response to an Interaction from the gateway. - /// See Create Interaction Response - /// - /// Client to use - /// Type of the interaction response - /// Builder for this response - public IPromise CreateResponse(DiscordClient client, InteractionResponseType type, InteractionResponseBuilder builder) - { - InteractionResponse data = new InteractionResponse(type, builder.Build()); - return CreateResponse(client, data); - } + /// + /// Create a response to an Interaction from the gateway. + /// See Create Interaction Response + /// + /// Client to use + /// Type of the interaction response + /// Builder for this response + public IPromise CreateResponse(DiscordClient client, InteractionResponseType type, InteractionResponseBuilder builder) + { + InteractionResponse data = new(type, builder.Build()); + return CreateResponse(client, data); + } - /// - /// Create a Auto Complete response to an Interaction - /// See Create Interaction Response - /// - /// Client to use - /// Message for this response - public IPromise CreateResponse(DiscordClient client, InteractionAutoCompleteMessage message) - { - InteractionAutoCompleteResponse data = new InteractionAutoCompleteResponse(message); - return CreateResponse(client, data); - } + /// + /// Create a Auto Complete response to an Interaction + /// See Create Interaction Response + /// + /// Client to use + /// Message for this response + public IPromise CreateResponse(DiscordClient client, InteractionAutoCompleteMessage message) + { + InteractionAutoCompleteResponse data = new(message); + return CreateResponse(client, data); + } - /// - /// Create a Auto Complete response to an Interaction - /// See Create Interaction Response - /// - /// Client to use - /// Auto Complete Builder for this response - public IPromise CreateResponse(DiscordClient client, InteractionAutoCompleteBuilder builder) - { - return CreateResponse(client, builder.Build()); - } + /// + /// Create a Auto Complete response to an Interaction + /// See Create Interaction Response + /// + /// Client to use + /// Auto Complete Builder for this response + public IPromise CreateResponse(DiscordClient client, InteractionAutoCompleteBuilder builder) + { + return CreateResponse(client, builder.Build()); + } - /// - /// Create a Modal response to an Interaction - /// See Create Interaction Response - /// - /// Client to use - /// Message for this response - public IPromise CreateResponse(DiscordClient client, InteractionModalMessage message) - { - InteractionModalResponse data = new InteractionModalResponse(message); - return CreateResponse(client, data); - } + /// + /// Create a Modal response to an Interaction + /// See Create Interaction Response + /// + /// Client to use + /// Message for this response + public IPromise CreateResponse(DiscordClient client, InteractionModalMessage message) + { + InteractionModalResponse data = new(message); + return CreateResponse(client, data); + } - /// - /// Create a Modal response to an Interaction - /// See Create Interaction Response - /// - /// Client to use - /// Modal Builder for this response - public IPromise CreateResponse(DiscordClient client, InteractionModalBuilder builder) - { - return CreateResponse(client, builder.Build()); - } + /// + /// Create a Modal response to an Interaction + /// See Create Interaction Response + /// + /// Client to use + /// Modal Builder for this response + public IPromise CreateResponse(DiscordClient client, InteractionModalBuilder builder) + { + return CreateResponse(client, builder.Build()); + } - /// - /// Creates a response indicating that: - /// for application commands there will be an update in the future - /// for message component commands that you have acknowledged the command and there may be an update in the future - /// See Create Interaction Response - /// - /// Client to use - public IPromise DefferResponse(DiscordClient client) - { - InteractionResponseType type = Type == InteractionType.ApplicationCommand ? InteractionResponseType.DeferredChannelMessageWithSource : InteractionResponseType.DeferredUpdateMessage; - return CreateResponse(client, type); - } - - /// - /// Creates a response indication that the interaction requires premium to be purchased. - /// - /// Client to use - public IPromise CreatePremiumRequiredResponse(DiscordClient client) - { - return CreateResponse(client, new InteractionPremiumRequiredResponse()); - } + /// + /// Creates a response indicating that: + /// for application commands there will be an update in the future + /// for message component commands that you have acknowledged the command and there may be an update in the future + /// See Create Interaction Response + /// + /// Client to use + public IPromise DefferResponse(DiscordClient client) + { + InteractionResponseType type = Type == InteractionType.ApplicationCommand ? InteractionResponseType.DeferredChannelMessageWithSource : InteractionResponseType.DeferredUpdateMessage; + return CreateResponse(client, type); + } - /// - /// Gets the initial Interaction response - /// See Get Original Interaction Response - /// - /// Client to use - public IPromise GetOriginalResponse(DiscordClient client) - { - InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); - InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); - return client.Bot.Rest.Get(client, $"webhooks/{ApplicationId}/{Token}/messages/@original", RequestOptions.SkipRateLimit()); - } + /// + /// Gets the initial Interaction response + /// See Get Original Interaction Response + /// + /// Client to use + public IPromise GetOriginalResponse(DiscordClient client) + { + InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); + InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); + return client.Bot.Rest.Get(client, $"webhooks/{ApplicationId}/{Token}/messages/@original", RequestOptions.SkipRateLimit()); + } - /// - /// Edits the initial Interaction response - /// See Edit Original Interaction Response - /// - /// Client to use - /// /// Updated message - public IPromise EditOriginalResponse(DiscordClient client, MessageUpdate message) - { - InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); - InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); - return client.Bot.Rest.Patch(client, $"webhooks/{ApplicationId}/{Token}/messages/@original", message, RequestOptions.SkipRateLimit()); - } + /// + /// Edits the initial Interaction response + /// See Edit Original Interaction Response + /// + /// Client to use + /// /// Updated message + public IPromise EditOriginalResponse(DiscordClient client, MessageUpdate message) + { + InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); + InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); + return client.Bot.Rest.Patch(client, $"webhooks/{ApplicationId}/{Token}/messages/@original", message, RequestOptions.SkipRateLimit()); + } - /// - /// Edit a interaction response with a message template - /// - /// Client to use - /// Template Name - /// Message to use (optional) - /// Placeholders to apply (optional) - /// - public IPromise EditTemplateOriginalResponse(DiscordClient client, TemplateKey templateName, MessageUpdate message = null, PlaceholderData placeholders = null) - { - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + /// + /// Edit a interaction response with a message template + /// + /// Client to use + /// Template Name + /// Message to use (optional) + /// Placeholders to apply (optional) + /// + public IPromise EditTemplateOriginalResponse(DiscordClient client, TemplateKey templateName, MessageUpdate message = null, PlaceholderData placeholders = null) + { + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - MessageUpdate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, this).ToMessage(placeholders, message); - return EditOriginalResponse(client, template); - } + MessageUpdate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, this).ToMessage(placeholders, message); + return EditOriginalResponse(client, template); + } - /// - /// Deletes the initial Interaction response - /// See Delete Original Interaction Response - /// - /// Client to use - public IPromise DeleteOriginalResponse(DiscordClient client) - { - InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); - InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); - return client.Bot.Rest.Delete(client, $"webhooks/{ApplicationId}/{Token}/messages/@original", RequestOptions.SkipRateLimit()); - } + /// + /// Deletes the initial Interaction response + /// See Delete Original Interaction Response + /// + /// Client to use + public IPromise DeleteOriginalResponse(DiscordClient client) + { + InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); + InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); + return client.Bot.Rest.Delete(client, $"webhooks/{ApplicationId}/{Token}/messages/@original", RequestOptions.SkipRateLimit()); + } - /// - /// Create a followup message for an Interaction - /// See Create Followup Message - /// - /// Client to use - /// Message to follow up with - public IPromise CreateFollowUpMessage(DiscordClient client, CommandFollowupCreate message) - { - InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); - InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); - return client.Bot.Rest.Post(client, $"webhooks/{ApplicationId}/{Token}", message, RequestOptions.SkipRateLimit()); - } + /// + /// Create a followup message for an Interaction + /// See Create Followup Message + /// + /// Client to use + /// Message to follow up with + public IPromise CreateFollowUpMessage(DiscordClient client, CommandFollowupCreate message) + { + InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); + InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); + return client.Bot.Rest.Post(client, $"webhooks/{ApplicationId}/{Token}", message, RequestOptions.SkipRateLimit()); + } - /// - /// Create a followup message for an Interaction - /// See Create Followup Message - /// - /// Client to use - /// Builder for the follow up - public IPromise CreateFollowUpMessage(DiscordClient client, InteractionFollowupBuilder builder) - { - return CreateFollowUpMessage(client, builder.Build()); - } + /// + /// Create a followup message for an Interaction + /// See Create Followup Message + /// + /// Client to use + /// Builder for the follow up + public IPromise CreateFollowUpMessage(DiscordClient client, InteractionFollowupBuilder builder) + { + return CreateFollowUpMessage(client, builder.Build()); + } - /// - /// Creates a interaction follow up message response from a message template - /// - /// Client to use - /// Name of the template - /// Message to send (optional) - /// Placeholders to apply (optional) - /// Thrown if plugin or templateName is null - public IPromise CreateFollowUpTemplateResponse(DiscordClient client, TemplateKey templateName, CommandFollowupCreate message = null, PlaceholderData placeholders = null) - { - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + /// + /// Creates a interaction follow up message response from a message template + /// + /// Client to use + /// Name of the template + /// Message to send (optional) + /// Placeholders to apply (optional) + /// Thrown if plugin or templateName is null + public IPromise CreateFollowUpTemplateResponse(DiscordClient client, TemplateKey templateName, CommandFollowupCreate message = null, PlaceholderData placeholders = null) + { + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - CommandFollowupCreate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, this).ToMessage(placeholders, message); - return CreateFollowUpMessage(client, template); - } + CommandFollowupCreate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, this).ToMessage(placeholders, message); + return CreateFollowUpMessage(client, template); + } - /// - /// Get a followup message for an Interaction - /// See Get Followup Message - /// - /// Client to use - /// Message ID of the follow up message - /// Updated message - public IPromise GetFollowUpMessage(DiscordClient client, Snowflake messageId, CommandFollowupUpdate edit) - { - InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); - InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); - InvalidSnowflakeException.ThrowIfInvalid(messageId, nameof(messageId)); - return client.Bot.Rest.Patch(client, $"webhooks/{ApplicationId}/{Token}/messages/{messageId}", edit, RequestOptions.SkipRateLimit()); - } + /// + /// Get a followup message for an Interaction + /// See Get Followup Message + /// + /// Client to use + /// Message ID of the follow up message + /// Updated message + public IPromise GetFollowUpMessage(DiscordClient client, Snowflake messageId, CommandFollowupUpdate edit) + { + InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); + InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); + InvalidSnowflakeException.ThrowIfInvalid(messageId); + return client.Bot.Rest.Patch(client, $"webhooks/{ApplicationId}/{Token}/messages/{messageId}", edit, RequestOptions.SkipRateLimit()); + } - /// - /// Edits a followup message for an Interaction - /// See Edit Followup Message - /// - /// Client to use - /// Message ID of the follow up message - /// Updated message - public IPromise EditFollowUpMessage(DiscordClient client, Snowflake messageId, CommandFollowupUpdate edit) - { - InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); - InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); - InvalidSnowflakeException.ThrowIfInvalid(messageId, nameof(messageId)); - return client.Bot.Rest.Patch(client, $"webhooks/{ApplicationId}/{Token}/messages/{messageId}", edit, RequestOptions.SkipRateLimit()); - } + /// + /// Edits a followup message for an Interaction + /// See Edit Followup Message + /// + /// Client to use + /// Message ID of the follow up message + /// Updated message + public IPromise EditFollowUpMessage(DiscordClient client, Snowflake messageId, CommandFollowupUpdate edit) + { + InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); + InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); + InvalidSnowflakeException.ThrowIfInvalid(messageId); + return client.Bot.Rest.Patch(client, $"webhooks/{ApplicationId}/{Token}/messages/{messageId}", edit, RequestOptions.SkipRateLimit()); + } - /// - /// Deletes a followup message for an Interaction - /// See Delete Followup Message - /// - /// Client to use - /// Message ID to delete - public IPromise DeleteFollowUpMessage(DiscordClient client, Snowflake messageId) - { - InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); - InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); - InvalidSnowflakeException.ThrowIfInvalid(messageId, nameof(messageId)); - return client.Bot.Rest.Delete(client, $"webhooks/{ApplicationId}/{Token}/messages/{messageId}", RequestOptions.SkipRateLimit()); - } + /// + /// Deletes a followup message for an Interaction + /// See Delete Followup Message + /// + /// Client to use + /// Message ID to delete + public IPromise DeleteFollowUpMessage(DiscordClient client, Snowflake messageId) + { + InvalidInteractionResponseException.ThrowIfNotResponded(_hasResponded); + InvalidInteractionResponseException.ThrowIfMaxResponseTimeElapsed(CreatedDate); + InvalidSnowflakeException.ThrowIfInvalid(messageId); + return client.Bot.Rest.Delete(client, $"webhooks/{ApplicationId}/{Token}/messages/{messageId}", RequestOptions.SkipRateLimit()); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/InteractionContextTypes.cs b/Oxide.Ext.Discord/Entities/Interactions/InteractionContextTypes.cs new file mode 100644 index 000000000..b6eb397cd --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Interactions/InteractionContextTypes.cs @@ -0,0 +1,22 @@ +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Interaction Context Types +/// +public enum InteractionContextTypes +{ + /// + /// Interaction can be used within servers + /// + Guild = 0, + + /// + /// Interaction can be used within DMs with the app's bot user + /// + BotDm = 1, + + /// + /// Interaction can be used within Group DMs and DMs other than the app's bot user + /// + PrivateChannel = 2 +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/InteractionData.cs b/Oxide.Ext.Discord/Entities/Interactions/InteractionData.cs index 760370e69..540b1b393 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/InteractionData.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/InteractionData.cs @@ -1,100 +1,99 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents ApplicationCommandInteractionData +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class InteractionData { /// - /// Represents ApplicationCommandInteractionData + /// ID of the invoked command /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InteractionData - { - /// - /// ID of the invoked command - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The name of the invoked command - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// The name of the invoked command + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// The type of the invoked command - /// - [JsonProperty("type")] - public ApplicationCommandType? Type { get; set; } + /// + /// The type of the invoked command + /// + [JsonProperty("type")] + public ApplicationCommandType? Type { get; set; } - /// - /// Converted s, s, s, s, s s - /// - [JsonProperty("resolved")] - public InteractionDataResolved Resolved { get; set; } + /// + /// Converted s, s, s, s, s s + /// + [JsonProperty("resolved")] + public InteractionDataResolved Resolved { get; set; } - /// - /// The params + values from the user - /// - [JsonProperty("options")] - public List Options { get; set; } + /// + /// The params + values from the user + /// + [JsonProperty("options")] + public List Options { get; set; } - /// - /// The id of the guild the command is registered to - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// The id of the guild the command is registered to + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// For components, the custom_id of the component - /// - [JsonProperty("custom_id")] - public string CustomId { get; set; } + /// + /// For components, the custom_id of the component + /// + [JsonProperty("custom_id")] + public string CustomId { get; set; } - /// - /// For components, the type of the component - /// - [JsonProperty("component_type")] - public MessageComponentType? ComponentType { get; set; } + /// + /// For components, the type of the component + /// + [JsonProperty("component_type")] + public MessageComponentType? ComponentType { get; set; } - /// - /// For components, the values for the select menu component - /// - [JsonProperty("values")] - public List Values { get; set; } + /// + /// For components, the values for the select menu component + /// + [JsonProperty("values")] + public List Values { get; set; } - /// - /// Id the of user or message targeted by a user or message command - /// - [JsonProperty("target_id")] - public Snowflake? TargetId { get; set; } + /// + /// Id the of user or message targeted by a user or message command + /// + [JsonProperty("target_id")] + public Snowflake? TargetId { get; set; } - /// - /// The values submitted by the user (Modal Submit) - /// - [JsonProperty("components")] - public List Components { get; set; } + /// + /// The values submitted by the user (Modal Submit) + /// + [JsonProperty("components")] + public List Components { get; set; } - /// - /// Returns a Component of type {T} with a custom ID that equals customId - /// - /// Custom ID to match on - /// Type to return - /// - public T GetComponent(string customId) where T : BaseInteractableComponent + /// + /// Returns a Component of type {T} with a custom ID that equals customId + /// + /// Custom ID to match on + /// Type to return + /// + public T GetComponent(string customId) where T : BaseInteractableComponent + { + foreach (ActionRowComponent row in Components) { - foreach (ActionRowComponent row in Components) + foreach (BaseComponent baseComponent in row.Components) { - foreach (BaseComponent baseComponent in row.Components) + if (baseComponent is T component && component.CustomId == customId) { - if (baseComponent is T component && component.CustomId == customId) - { - return component; - } + return component; } } - - return null; } + + return null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/InteractionDataOption.cs b/Oxide.Ext.Discord/Entities/Interactions/InteractionDataOption.cs index bde3c4862..34aa76f53 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/InteractionDataOption.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/InteractionDataOption.cs @@ -2,74 +2,73 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Command Interaction Data Option +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class InteractionDataOption { /// - /// Represents Application Command Interaction Data Option + /// The name of the parameter /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InteractionDataOption - { - /// - /// The name of the parameter - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Value of ApplicationCommandOptionType - /// - [JsonProperty("type")] - public CommandOptionType Type { get; set; } + /// + /// Value of ApplicationCommandOptionType + /// + [JsonProperty("type")] + public CommandOptionType Type { get; set; } - /// - /// The value of the option resulting from user input - /// Value can be string, integer, or double, or boolean type - /// - [JsonProperty("value")] - private object Value { get; set; } + /// + /// The value of the option resulting from user input + /// Value can be string, integer, or double, or boolean type + /// + [JsonProperty("value")] + private object Value { get; set; } - /// - /// Returns the value as a string - /// - /// - public string GetString() => (string)Value ?? string.Empty; + /// + /// Returns the value as a string + /// + /// + public string GetString() => (string)Value ?? string.Empty; - /// - /// Returns the value as an int - /// - /// - public int GetInt() => Convert.ToInt32(Value); + /// + /// Returns the value as an int + /// + /// + public int GetInt() => Convert.ToInt32(Value); - /// - /// Returns the value as a bool - /// - /// - public bool GetBool() => Convert.ToBoolean(Value); + /// + /// Returns the value as a bool + /// + /// + public bool GetBool() => Convert.ToBoolean(Value); - /// - /// Returns the value as a double - /// - /// - public double GetNumber() => Convert.ToDouble(Value); + /// + /// Returns the value as a double + /// + /// + public double GetNumber() => Convert.ToDouble(Value); - /// - /// Returns the value as a Snowflake - /// - /// - public Snowflake GetSnowflake() => new Snowflake(Convert.ToUInt64(Value)); + /// + /// Returns the value as a Snowflake + /// + /// + public Snowflake GetSnowflake() => new(Convert.ToUInt64(Value)); - /// - /// Present if this option is a group or subcommand - /// See - /// - [JsonProperty("options")] - public List Options { get; set; } + /// + /// Present if this option is a group or subcommand + /// See + /// + [JsonProperty("options")] + public List Options { get; set; } - /// - /// True if this option is the currently focused option for autocomplete - /// - [JsonProperty("focused")] - public bool? Focused { get; set; } - } + /// + /// True if this option is the currently focused option for autocomplete + /// + [JsonProperty("focused")] + public bool? Focused { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/InteractionDataParsed.cs b/Oxide.Ext.Discord/Entities/Interactions/InteractionDataParsed.cs index f7d854155..0a57fe6ce 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/InteractionDataParsed.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/InteractionDataParsed.cs @@ -4,283 +4,282 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Parses Interaction Data to make it easier to process for application commands +/// +public class InteractionDataParsed { /// - /// Parses Interaction Data to make it easier to process for application commands + /// Interaction this data is for /// - public class InteractionDataParsed - { - /// - /// Interaction this data is for - /// - public readonly DiscordInteraction Interaction; + public readonly DiscordInteraction Interaction; - /// - /// for the Interaction - /// - public readonly InteractionData Data; + /// + /// for the Interaction + /// + public readonly InteractionData Data; - /// - /// The type of interaction that was triggered - /// - public readonly ApplicationCommandType? Type; + /// + /// The type of interaction that was triggered + /// + public readonly ApplicationCommandType? Type; - /// - /// Parsed command for the interaction if an application command - /// - public readonly string Command; + /// + /// Parsed command for the interaction if an application command + /// + public readonly string Command; - /// - /// Command group for the interaction if Command Type if an application command - /// Null if command group is not used for the command. - /// Defaults to empty string if command does not have a command group - /// - public string CommandGroup { get; private set; } = string.Empty; + /// + /// Command group for the interaction if Command Type if an application command + /// Null if command group is not used for the command. + /// Defaults to empty string if command does not have a command group + /// + public string CommandGroup { get; private set; } = string.Empty; - /// - /// Sub Command for the interaction if Command Typ if an application command - /// Null if sub command group is not used for the command. - /// Defaults to empty string if command does not have sub command - /// - public string SubCommand { get; private set; } = string.Empty; + /// + /// Sub Command for the interaction if Command Typ if an application command + /// Null if sub command group is not used for the command. + /// Defaults to empty string if command does not have sub command + /// + public string SubCommand { get; private set; } = string.Empty; - /// - /// Interaction Data Supplied Args if Command Type if an application command - /// - public InteractionDataArgs Args { get; private set; } + /// + /// Interaction Data Supplied Args if Command Type if an application command + /// + public InteractionDataArgs Args { get; private set; } - /// - /// Returns true if this command was used in a guild; false otherwise. - /// - public bool InGuild => Interaction.GuildId.HasValue; + /// + /// Returns true if this command was used in a guild; false otherwise. + /// + public bool InGuild => Interaction.GuildId.HasValue; - /// - /// The CustomId of the that triggered the interaction if a component triggered this interaction - /// - public readonly string TriggeredComponentId; + /// + /// The CustomId of the that triggered the interaction if a component triggered this interaction + /// + public readonly string TriggeredComponentId; - /// - /// If a triggered this interaction. The values selected from the select menu. - /// - public readonly List SelectMenuValues; + /// + /// If a triggered this interaction. The values selected from the select menu. + /// + public readonly List SelectMenuValues; - /// - /// Discord User's locale converted to oxide lang locale - /// - public readonly ServerLocale UserOxideLocale; + /// + /// Discord User's locale converted to oxide lang locale + /// + public readonly ServerLocale UserOxideLocale; - /// - /// Discord Guild's locale converted to oxide lang locale - /// - public readonly ServerLocale GuildOxideLocale; + /// + /// Discord Guild's locale converted to oxide lang locale + /// + public readonly ServerLocale GuildOxideLocale; - /// - /// Constructor for the data parser. - /// - /// Interaction to be parsed - public InteractionDataParsed(DiscordInteraction interaction) - { - Interaction = interaction; - Data = interaction.Data; + /// + /// Constructor for the data parser. + /// + /// Interaction to be parsed + public InteractionDataParsed(DiscordInteraction interaction) + { + Interaction = interaction; + Data = interaction.Data; - UserOxideLocale = DiscordLocales.Instance.GetServerLanguage(interaction.Locale); - if (interaction.GuildLocale.HasValue && interaction.GuildLocale.Value.IsValid) - { - GuildOxideLocale = DiscordLocales.Instance.GetServerLanguage(interaction.GuildLocale.Value); - } + UserOxideLocale = DiscordLocales.Instance.GetServerLanguage(interaction.Locale); + if (interaction.GuildLocale.HasValue && interaction.GuildLocale.Value.IsValid) + { + GuildOxideLocale = DiscordLocales.Instance.GetServerLanguage(interaction.GuildLocale.Value); + } - //Check if MessageComponent and parse data accordingly - if (Data.ComponentType.HasValue) + //Check if MessageComponent and parse data accordingly + if (Data.ComponentType.HasValue) + { + TriggeredComponentId = Data.CustomId; + if (Data.ComponentType == MessageComponentType.StringSelect) { - TriggeredComponentId = Data.CustomId; - if (Data.ComponentType == MessageComponentType.StringSelect) - { - SelectMenuValues = Data.Values; - } - return; + SelectMenuValues = Data.Values; } + return; + } - Type = Data.Type; - Command = Data.Name; + Type = Data.Type; + Command = Data.Name; - //If ApplicationCommand is Message or User it can't have arguments - if (Type == ApplicationCommandType.Message || Type == ApplicationCommandType.User) - { - return; - } - - //Parse the arguments for the application command - ParseCommand(Data.Options); + //If ApplicationCommand is Message or User it can't have arguments + if (Type == ApplicationCommandType.Message || Type == ApplicationCommandType.User) + { + return; } - private void ParseCommand(List options) + //Parse the arguments for the application command + ParseCommand(Data.Options); + } + + private void ParseCommand(List options) + { + if (options == null || options.Count == 0) { - if (options == null || options.Count == 0) - { - return; - } + return; + } - InteractionDataOption option = options[0]; - switch (option.Type) - { - case CommandOptionType.SubCommandGroup: - CommandGroup = option.Name; - ParseCommand(option.Options); - break; + InteractionDataOption option = options[0]; + switch (option.Type) + { + case CommandOptionType.SubCommandGroup: + CommandGroup = option.Name; + ParseCommand(option.Options); + break; - case CommandOptionType.SubCommand: - SubCommand = option.Name; - ParseCommand(option.Options); - break; + case CommandOptionType.SubCommand: + SubCommand = option.Name; + ParseCommand(option.Options); + break; - default: - Args = new InteractionDataArgs(Interaction, options); - break; - } + default: + Args = new InteractionDataArgs(Interaction, options); + break; } } +} - /// - /// Args supplied for the interaction - /// - public class InteractionDataArgs - { - private readonly Hash _args = new Hash(); - private readonly DiscordInteraction _interaction; +/// +/// Args supplied for the interaction +/// +public class InteractionDataArgs +{ + private readonly Hash _args = new(); + private readonly DiscordInteraction _interaction; - internal InteractionDataArgs(DiscordInteraction interaction, List options) + internal InteractionDataArgs(DiscordInteraction interaction, List options) + { + _interaction = interaction; + for (int index = 0; index < options.Count; index++) { - _interaction = interaction; - for (int index = 0; index < options.Count; index++) - { - InteractionDataOption option = options[index]; - _args[option.Name] = option; - } + InteractionDataOption option = options[index]; + _args[option.Name] = option; } + } - /// - /// Returns if a given arg exists - /// - /// - /// - public bool HasArg(string name) - { - return _args.ContainsKey(name); - } + /// + /// Returns if a given arg exists + /// + /// + /// + public bool HasArg(string name) + { + return _args.ContainsKey(name); + } - /// - /// Returns the string value supplied to command option matching the name. - /// If the arg was optional and wasn't supplied default supplied value will be used. - /// - /// Name of the command option - /// Default value to return if not supplied - /// String for the matching command option name - /// Thrown if the option type is not a string - public string GetString(string name, string @default = "") - { - return GetArg(name, CommandOptionType.String)?.GetString() ?? @default; - } + /// + /// Returns the string value supplied to command option matching the name. + /// If the arg was optional and wasn't supplied default supplied value will be used. + /// + /// Name of the command option + /// Default value to return if not supplied + /// String for the matching command option name + /// Thrown if the option type is not a string + public string GetString(string name, string @default = "") + { + return GetArg(name, CommandOptionType.String)?.GetString() ?? @default; + } - /// - /// Returns the int value supplied to command option matching the name. - /// If the arg was optional and wasn't supplied default supplied value will be used. - /// - /// Name of the command option - /// Default value to return if not supplied - /// Int for the matching command option name - /// Thrown if the option type is not an int - public int GetInt(string name, int @default = default(int)) - { - return GetArg(name, CommandOptionType.Integer)?.GetInt() ?? @default; - } + /// + /// Returns the int value supplied to command option matching the name. + /// If the arg was optional and wasn't supplied default supplied value will be used. + /// + /// Name of the command option + /// Default value to return if not supplied + /// Int for the matching command option name + /// Thrown if the option type is not an int + public int GetInt(string name, int @default = default) + { + return GetArg(name, CommandOptionType.Integer)?.GetInt() ?? @default; + } - /// - /// Returns the bool value supplied to command option matching the name. - /// If the arg was optional and wasn't supplied default supplied value will be used. - /// - /// Name of the command option - /// Default value to return if not supplied - /// Bool for the matching command option name - /// Thrown if the option type is not a bool - public bool GetBool(string name, bool @default = default(bool)) - { - return GetArg(name, CommandOptionType.Boolean)?.GetBool() ?? @default; - } + /// + /// Returns the bool value supplied to command option matching the name. + /// If the arg was optional and wasn't supplied default supplied value will be used. + /// + /// Name of the command option + /// Default value to return if not supplied + /// Bool for the matching command option name + /// Thrown if the option type is not a bool + public bool GetBool(string name, bool @default = default) + { + return GetArg(name, CommandOptionType.Boolean)?.GetBool() ?? @default; + } - /// - /// Returns the that was resolved from the command. - /// - /// Name of the command option - /// resolved for the matching command option name - /// Thrown if the option type is not a or mentionable - public DiscordUser GetUser(string name) - { - InteractionDataOption arg = GetArg(name, CommandOptionType.User); - return arg != null ? _interaction.Data.Resolved.Users[arg.GetSnowflake()] : null; - } + /// + /// Returns the that was resolved from the command. + /// + /// Name of the command option + /// resolved for the matching command option name + /// Thrown if the option type is not a or mentionable + public DiscordUser GetUser(string name) + { + InteractionDataOption arg = GetArg(name, CommandOptionType.User); + return arg != null ? _interaction.Data.Resolved.Users[arg.GetSnowflake()] : null; + } - /// - /// Returns the that was resolved from the command. - /// - /// Name of the command option - /// resolved for the matching command option name - /// Thrown if the option type is not a - public DiscordChannel GetChannel(string name) - { - InteractionDataOption arg = GetArg(name, CommandOptionType.Channel); - return arg != null ? _interaction.Data.Resolved.Channels[arg.GetSnowflake()] : null; - } + /// + /// Returns the that was resolved from the command. + /// + /// Name of the command option + /// resolved for the matching command option name + /// Thrown if the option type is not a + public DiscordChannel GetChannel(string name) + { + InteractionDataOption arg = GetArg(name, CommandOptionType.Channel); + return arg != null ? _interaction.Data.Resolved.Channels[arg.GetSnowflake()] : null; + } - /// - /// Returns the that was resolved from the command. - /// - /// Name of the command option - /// resolved for the matching command option name - /// Thrown if the option type is not a or mentionable - public DiscordRole GetRole(string name) - { - InteractionDataOption arg = GetArg(name, CommandOptionType.Role); - return arg != null ? _interaction.Data.Resolved.Roles[arg.GetSnowflake()] : null; - } + /// + /// Returns the that was resolved from the command. + /// + /// Name of the command option + /// resolved for the matching command option name + /// Thrown if the option type is not a or mentionable + public DiscordRole GetRole(string name) + { + InteractionDataOption arg = GetArg(name, CommandOptionType.Role); + return arg != null ? _interaction.Data.Resolved.Roles[arg.GetSnowflake()] : null; + } - /// - /// Returns the double value supplied to command option matching the name. - /// If the arg was optional and wasn't supplied default supplied value will be used. - /// - /// Name of the command option - /// Default value to return if not supplied - /// double for the matching command option name - /// Thrown if the option type is not a double - public double GetNumber(string name, double @default = default(double)) - { - return GetArg(name, CommandOptionType.Number)?.GetNumber() ?? @default; - } + /// + /// Returns the double value supplied to command option matching the name. + /// If the arg was optional and wasn't supplied default supplied value will be used. + /// + /// Name of the command option + /// Default value to return if not supplied + /// double for the matching command option name + /// Thrown if the option type is not a double + public double GetNumber(string name, double @default = default) + { + return GetArg(name, CommandOptionType.Number)?.GetNumber() ?? @default; + } - /// - /// Returns the float value supplied to command option matching the name. - /// If the arg was optional and wasn't supplied default supplied value will be used. - /// - /// Name of the command option - /// Default value to return if not supplied - /// double for the matching command option name - /// Thrown if the option type is not a double - public float GetFloat(string name, float @default = default(float)) - { - return (float?)GetArg(name, CommandOptionType.Number)?.GetNumber() ?? @default; - } + /// + /// Returns the float value supplied to command option matching the name. + /// If the arg was optional and wasn't supplied default supplied value will be used. + /// + /// Name of the command option + /// Default value to return if not supplied + /// double for the matching command option name + /// Thrown if the option type is not a double + public float GetFloat(string name, float @default = default) + { + return (float?)GetArg(name, CommandOptionType.Number)?.GetNumber() ?? @default; + } - private InteractionDataOption GetArg(string name, CommandOptionType requested) + private InteractionDataOption GetArg(string name, CommandOptionType requested) + { + InteractionDataOption arg = _args[name]; + if (arg == null) { - InteractionDataOption arg = _args[name]; - if (arg == null) - { - return null; - } + return null; + } - InteractionArgException.ThrowIfInvalidArgType(name, arg.Type, requested); + InteractionArgException.ThrowIfInvalidArgType(name, arg.Type, requested); - return arg; - } + return arg; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/InteractionDataResolved.cs b/Oxide.Ext.Discord/Entities/Interactions/InteractionDataResolved.cs index f4b504d71..940a11d2a 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/InteractionDataResolved.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/InteractionDataResolved.cs @@ -1,48 +1,47 @@ using Newtonsoft.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Application Command Interaction Data Option +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class InteractionDataResolved { /// - /// Represents Application Command Interaction Data Option + /// The IDs and User objects /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InteractionDataResolved - { - /// - /// The IDs and User objects - /// - [JsonProperty("users")] - public Hash Users { get; set; } + [JsonProperty("users")] + public Hash Users { get; set; } - /// - /// The IDs and partial Member objects - /// - [JsonProperty("members")] - public Hash Members { get; set; } + /// + /// The IDs and partial Member objects + /// + [JsonProperty("members")] + public Hash Members { get; set; } - /// - /// The IDs and Role objects - /// - [JsonProperty("roles")] - public Hash Roles { get; set; } + /// + /// The IDs and Role objects + /// + [JsonProperty("roles")] + public Hash Roles { get; set; } - /// - /// The IDs and partial Channel objects - /// - [JsonProperty("channels")] - public Hash Channels { get; set; } + /// + /// The IDs and partial Channel objects + /// + [JsonProperty("channels")] + public Hash Channels { get; set; } - /// - /// The ids and partial Message objects - /// - [JsonProperty("messages")] - public Hash Messages { get; set; } + /// + /// The ids and partial Message objects + /// + [JsonProperty("messages")] + public Hash Messages { get; set; } - /// - /// The ids and attachment objects - /// - [JsonProperty("attachments")] - public Hash Attachments { get; set; } - } + /// + /// The ids and attachment objects + /// + [JsonProperty("attachments")] + public Hash Attachments { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/InteractionResponseType.cs b/Oxide.Ext.Discord/Entities/Interactions/InteractionResponseType.cs index 0d3abba70..d0b9053c6 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/InteractionResponseType.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/InteractionResponseType.cs @@ -1,50 +1,44 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents InteractionResponseType +/// +public enum InteractionResponseType : byte { /// - /// Represents InteractionResponseType + /// Acknowledges a Ping /// - public enum InteractionResponseType : byte - { - /// - /// Acknowledges a Ping - /// - Pong = 1, + Pong = 1, - /// - /// Respond with a message, showing the user's input - /// - ChannelMessageWithSource = 4, - - /// - /// Acknowledge a command without sending a message, showing the user's input - /// - DeferredChannelMessageWithSource = 5, + /// + /// Respond with a message, showing the user's input + /// + ChannelMessageWithSource = 4, - /// - /// For components, Acknowledge an interaction and edit the original message later - /// The user does not see a loading state - /// - DeferredUpdateMessage = 6, + /// + /// Acknowledge a command without sending a message, showing the user's input + /// + DeferredChannelMessageWithSource = 5, - /// - /// For components, edit the message the component was attached to - /// - UpdateMessage = 7, + /// + /// For components, Acknowledge an interaction and edit the original message later + /// The user does not see a loading state + /// + DeferredUpdateMessage = 6, - /// - /// Respond to an autocomplete interaction with suggested choices - /// - ApplicationCommandAutocompleteResult = 8, + /// + /// For components, edit the message the component was attached to + /// + UpdateMessage = 7, - /// - /// Respond to an interaction with an modal for a user to fill-out - /// Note: You can't respond to a ModalSubmit with a new MODAL. - /// - Modal = 9, + /// + /// Respond to an autocomplete interaction with suggested choices + /// + ApplicationCommandAutocompleteResult = 8, - /// - /// Respond to an interaction with an upgrade button, only available for apps with monetization enabled - /// - PremiumRequired = 10 - } + /// + /// Respond to an interaction with an modal for a user to fill-out + /// Note: You can't respond to a ModalSubmit with a new MODAL. + /// + Modal = 9 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/InteractionType.cs b/Oxide.Ext.Discord/Entities/Interactions/InteractionType.cs index d3002ab7e..f277d5f3c 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/InteractionType.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/InteractionType.cs @@ -1,33 +1,32 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents InteractionType +/// +public enum InteractionType : byte { /// - /// Represents InteractionType + /// The interaction is a ping /// - public enum InteractionType : byte - { - /// - /// The interaction is a ping - /// - Ping = 1, + Ping = 1, - /// - /// The interaction is a user using a command - /// - ApplicationCommand = 2, + /// + /// The interaction is a user using a command + /// + ApplicationCommand = 2, - /// - /// The interaction is a message component - /// - MessageComponent = 3, + /// + /// The interaction is a message component + /// + MessageComponent = 3, - /// - /// The interaction is a application command autocomplete - /// - ApplicationCommandAutoComplete = 4, + /// + /// The interaction is a application command autocomplete + /// + ApplicationCommandAutoComplete = 4, - /// - /// The interaction is a modal - /// - ModalSubmit = 5 - } + /// + /// The interaction is a modal + /// + ModalSubmit = 5 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ActionRowComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ActionRowComponent.cs index d9811d5f8..1f8194616 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ActionRowComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ActionRowComponent.cs @@ -3,39 +3,38 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Action Row Component within discord +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ActionRowComponent : BaseComponent { /// - /// Represents Action Row Component within discord + /// The components on the action row /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ActionRowComponent : BaseComponent - { - /// - /// The components on the action row - /// - [JsonConverter(typeof(MessageComponentsConverter))] - [JsonProperty("components")] - public List Components { get; } = new List(); + [JsonConverter(typeof(MessageComponentsConverter))] + [JsonProperty("components")] + public List Components { get; } = new(); - /// - /// Constructor for ActionRowComponent - /// Sets the Type to ActionRow - /// - public ActionRowComponent() - { - Type = MessageComponentType.ActionRow; - } + /// + /// Constructor for ActionRowComponent + /// Sets the Type to ActionRow + /// + public ActionRowComponent() + { + Type = MessageComponentType.ActionRow; + } - /// - public override void Validate() + /// + public override void Validate() + { + InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(Components.Count); + for (int index = 0; index < Components.Count; index++) { - InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(Components.Count); - for (int index = 0; index < Components.Count; index++) - { - BaseComponent component = Components[index]; - component.Validate(); - } + BaseComponent component = Components[index]; + component.Validate(); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/BaseComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/BaseComponent.cs index 072342c75..653fd20f1 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/BaseComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/BaseComponent.cs @@ -1,21 +1,20 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Component within discord +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public abstract class BaseComponent : IDiscordValidation { /// - /// Represents Message Component within discord + /// Message component type /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public abstract class BaseComponent : IDiscordValidation - { - /// - /// Message component type - /// - [JsonProperty("type")] - public MessageComponentType Type { get; protected set; } + [JsonProperty("type")] + public MessageComponentType Type { get; protected set; } - /// - public abstract void Validate(); - } + /// + public abstract void Validate(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/BaseInteractableComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/BaseInteractableComponent.cs index 1c425f9f5..63cf40d4a 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/BaseInteractableComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/BaseInteractableComponent.cs @@ -1,24 +1,23 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represent a MessageComponent that can be interacted with +/// +public abstract class BaseInteractableComponent : BaseComponent { /// - /// Represent a MessageComponent that can be interacted with + /// Developer-defined identifier for the interactable component + /// Max 100 characters /// - public abstract class BaseInteractableComponent : BaseComponent - { - /// - /// Developer-defined identifier for the interactable component - /// Max 100 characters - /// - [JsonProperty("custom_id")] - public string CustomId { get; set; } + [JsonProperty("custom_id")] + public string CustomId { get; set; } - /// - public override void Validate() - { - InvalidMessageComponentException.ThrowIfInvalidCustomId(CustomId); - } + /// + public override void Validate() + { + InvalidMessageComponentException.ThrowIfInvalidCustomId(CustomId); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ButtonComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ButtonComponent.cs index 577617dad..991962580 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ButtonComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ButtonComponent.cs @@ -1,64 +1,69 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Button Component within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ButtonComponent : BaseInteractableComponent { /// - /// Represents a Button Component within discord. + /// Style for the button component /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ButtonComponent : BaseInteractableComponent - { - /// - /// Style for the button component - /// - [JsonProperty("style")] - public ButtonStyle Style { get; set; } + [JsonProperty("style")] + public ButtonStyle Style { get; set; } - /// - /// Text that appears on the button - /// Max 80 characters - /// - [JsonProperty("label")] - public string Label { get; set; } + /// + /// Text that appears on the button + /// Max 80 characters + /// + [JsonProperty("label")] + public string Label { get; set; } - /// - /// Emoji on the component - /// - [JsonProperty("emoji")] - public DiscordEmoji Emoji { get; set; } + /// + /// Emoji on the component + /// + [JsonProperty("emoji")] + public DiscordEmoji Emoji { get; set; } - /// - /// URL for link-style buttons - /// - [JsonProperty("url")] - public string Url { get; set; } + /// + /// Identifier for a purchasable SKU, only available when using premium-style buttons + /// + [JsonProperty("sku_id")] + public Snowflake? SkuId { get; set; } + + /// + /// URL for link-style buttons + /// + [JsonProperty("url")] + public string Url { get; set; } - /// - /// Whether the button is disabled - /// Default false - /// - [JsonProperty("disabled")] - public bool? Disabled { get; set; } + /// + /// Whether the button is disabled + /// Default false + /// + [JsonProperty("disabled")] + public bool? Disabled { get; set; } - /// - /// Constructor for button - /// Sets type to button - /// - public ButtonComponent() - { - Type = MessageComponentType.Button; - } + /// + /// Constructor for button + /// Sets type to button + /// + public ButtonComponent() + { + Type = MessageComponentType.Button; + } - /// - public override void Validate() + /// + public override void Validate() + { + base.Validate(); + InvalidMessageComponentException.ThrowIfInvalidButtonLabel(Label); + if (Style == ButtonStyle.Link) { - base.Validate(); - InvalidMessageComponentException.ThrowIfInvalidButtonLabel(Label); - if (Style == ButtonStyle.Link) - { - InvalidMessageComponentException.ThrowIfInvalidButtonUrl(Url); - } + InvalidMessageComponentException.ThrowIfInvalidButtonUrl(Url); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ButtonStyle.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ButtonStyle.cs index c40ffdb2b..ffb3d455f 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ButtonStyle.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/ButtonStyle.cs @@ -1,39 +1,45 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Button Styles within Discord.. +/// +public enum ButtonStyle : byte { /// - /// Represents Button Styles within Discord.. + /// Color blurple + /// Requires CustomId field /// - public enum ButtonStyle : byte - { - /// - /// Color blurple - /// Requires CustomId field - /// - Primary = 1, + Primary = 1, - /// - /// Color grey - /// Requires CustomId field - /// - Secondary = 2, + /// + /// Color grey + /// Requires CustomId field + /// + Secondary = 2, - /// - /// Color green - /// Requires CustomId field - /// - Success = 3, + /// + /// Color green + /// Requires CustomId field + /// + Success = 3, - /// - /// Color red - /// Requires CustomId field - /// - Danger = 4, + /// + /// Color red + /// Requires CustomId field + /// + Danger = 4, - /// - /// Color grey - /// Navigates to a URL - /// Requires Url field - /// - Link = 5 - } + /// + /// Color grey + /// Navigates to a URL + /// Requires Url field + /// + Link = 5, + + /// + /// Color blurple + /// Navigates to a URL + /// Requires SkuId field + /// + Premium = 6 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/InputTextComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/InputTextComponent.cs index 250381283..18687df6e 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/InputTextComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/InputTextComponent.cs @@ -1,73 +1,72 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Input Text Component within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class InputTextComponent : BaseInteractableComponent { /// - /// Represents a Input Text Component within discord. + /// Style of the input text /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InputTextComponent : BaseInteractableComponent - { - /// - /// Style of the input text - /// - [JsonProperty("style")] - public InputTextStyles Style { get; set; } + [JsonProperty("style")] + public InputTextStyles Style { get; set; } - /// - /// Text that appears on top of the input text field, max 80 characters - /// - [JsonProperty("label")] - public string Label { get; set; } + /// + /// Text that appears on top of the input text field, max 80 characters + /// + [JsonProperty("label")] + public string Label { get; set; } - /// - /// Minimum length of the text input - /// - [JsonProperty("min_length")] - public int? MinLength { get; set; } + /// + /// Minimum length of the text input + /// + [JsonProperty("min_length")] + public int? MinLength { get; set; } - /// - /// Maximum length of the text input - /// - [JsonProperty("max_length")] - public int? MaxLength { get; set; } + /// + /// Maximum length of the text input + /// + [JsonProperty("max_length")] + public int? MaxLength { get; set; } - /// - /// Whether this component is required to be filled - /// defaults to true - /// - [JsonProperty("required")] - public bool? Required { get; set; } + /// + /// Whether this component is required to be filled + /// defaults to true + /// + [JsonProperty("required")] + public bool? Required { get; set; } - /// - /// Pre-filled value for text input - /// - [JsonProperty("value")] - public string Value { get; set; } + /// + /// Pre-filled value for text input + /// + [JsonProperty("value")] + public string Value { get; set; } - /// - /// Custom placeholder text if the input is empty - /// Max 100 characters - /// - [JsonProperty("placeholder")] - public string Placeholder { get; set; } + /// + /// Custom placeholder text if the input is empty + /// Max 100 characters + /// + [JsonProperty("placeholder")] + public string Placeholder { get; set; } - /// - /// Input Text Constructor - /// - public InputTextComponent() - { - Type = MessageComponentType.InputText; - } + /// + /// Input Text Constructor + /// + public InputTextComponent() + { + Type = MessageComponentType.InputText; + } - /// - public override void Validate() - { - base.Validate(); - InvalidMessageComponentException.ThrowIfInvalidTextInputLabel(Label); - InvalidMessageComponentException.ThrowIfInvalidTextInputValue(Value); - InvalidMessageComponentException.ThrowIfInvalidTextInputLength(MinLength, MaxLength); - } + /// + public override void Validate() + { + base.Validate(); + InvalidMessageComponentException.ThrowIfInvalidTextInputLabel(Label); + InvalidMessageComponentException.ThrowIfInvalidTextInputValue(Value); + InvalidMessageComponentException.ThrowIfInvalidTextInputLength(MinLength, MaxLength); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/InputTextStyles.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/InputTextStyles.cs index a488aeafc..747886a72 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/InputTextStyles.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/InputTextStyles.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Input Text Styles within discord. +/// +public enum InputTextStyles : byte { /// - /// Represents a Input Text Styles within discord. + /// Single-line input /// - public enum InputTextStyles : byte - { - /// - /// Single-line input - /// - Short = 1, + Short = 1, - /// - /// Multi-line input - /// - Paragraph = 2 - } + /// + /// Multi-line input + /// + Paragraph = 2 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/MessageComponentType.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/MessageComponentType.cs index 8370e2237..6ba0af71a 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/MessageComponentType.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/MessageComponentType.cs @@ -1,48 +1,47 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Component Type within Discord.. +/// +public enum MessageComponentType : byte { /// - /// Represents a Message Component Type within Discord.. + /// Container for other components /// - public enum MessageComponentType : byte - { - /// - /// Container for other components - /// - ActionRow = 1, + ActionRow = 1, - /// - /// Clickable button - /// - Button = 2, + /// + /// Clickable button + /// + Button = 2, - /// - /// Select menu for picking from defined text options - /// - StringSelect = 3, + /// + /// Select menu for picking from defined text options + /// + StringSelect = 3, - /// - /// Text box for inserting written responses - /// - InputText = 4, + /// + /// Text box for inserting written responses + /// + InputText = 4, - /// - /// Select menu for users - /// - UserSelect = 5, + /// + /// Select menu for users + /// + UserSelect = 5, - /// - /// Select menu for roles - /// - RoleSelect = 6, + /// + /// Select menu for roles + /// + RoleSelect = 6, - /// - /// Select menu for mentionables (users and roles) - /// - MentionableSelect = 7, + /// + /// Select menu for mentionables (users and roles) + /// + MentionableSelect = 7, - /// - /// Select menu for channels - /// - ChannelSelect = 8, - } + /// + /// Select menu for channels + /// + ChannelSelect = 8, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/BaseSelectMenuComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/BaseSelectMenuComponent.cs index 2a2ce947b..b6a86b4b8 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/BaseSelectMenuComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/BaseSelectMenuComponent.cs @@ -2,65 +2,64 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Select Menus Component within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public abstract class BaseSelectMenuComponent : BaseInteractableComponent { /// - /// Represents a Select Menus Component within discord. + /// Custom placeholder text if nothing is selected + /// Max 150 characters /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public abstract class BaseSelectMenuComponent : BaseInteractableComponent - { - /// - /// Custom placeholder text if nothing is selected - /// Max 150 characters - /// - [JsonProperty("placeholder")] - public string Placeholder { get; set; } + [JsonProperty("placeholder")] + public string Placeholder { get; set; } - /// - /// List of default values for auto-populated select menu components; number of default values must be in the range defined by min_values and max_values - /// Max 150 characters - /// - [JsonProperty("default_values")] - public List DefaultValues { get; set; } + /// + /// List of default values for auto-populated select menu components; number of default values must be in the range defined by min_values and max_values + /// Max 150 characters + /// + [JsonProperty("default_values")] + public List DefaultValues { get; set; } - /// - /// the minimum number of items that must be chosen; - /// Default 1, Min 0, Max 25 - /// - [JsonProperty("min_values")] - public int? MinValues { get; set; } + /// + /// the minimum number of items that must be chosen; + /// Default 1, Min 0, Max 25 + /// + [JsonProperty("min_values")] + public int? MinValues { get; set; } - /// - /// the maximum number of items that must be chosen; - /// Default 1, Min 0, Max 25 - /// - [JsonProperty("max_values")] - public int? MaxValues { get; set; } + /// + /// the maximum number of items that must be chosen; + /// Default 1, Min 0, Max 25 + /// + [JsonProperty("max_values")] + public int? MaxValues { get; set; } - /// - /// Disable the select - /// Default false - /// - [JsonProperty("disabled")] - public bool? Disabled { get; set; } + /// + /// Disable the select + /// Default false + /// + [JsonProperty("disabled")] + public bool? Disabled { get; set; } - /// - /// Select Menu Component Constructor - /// - protected BaseSelectMenuComponent(MessageComponentType type) - { - Type = type; - } + /// + /// Select Menu Component Constructor + /// + protected BaseSelectMenuComponent(MessageComponentType type) + { + Type = type; + } - /// - public override void Validate() - { - base.Validate(); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuPlaceholder(Placeholder); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuMinValues(MinValues); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuMaxValues(MaxValues); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuValueRange(MinValues, MaxValues); - } + /// + public override void Validate() + { + base.Validate(); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuPlaceholder(Placeholder); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuMinValues(MinValues); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuMaxValues(MaxValues); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuValueRange(MinValues, MaxValues); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/ChannelSelectComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/ChannelSelectComponent.cs index 967150248..ac98cf745 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/ChannelSelectComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/ChannelSelectComponent.cs @@ -1,23 +1,22 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Select Menus Component within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ChannelSelectComponent : BaseSelectMenuComponent { /// - /// Represents a Select Menus Component within discord. + /// List of channel types to include in the channel select component /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ChannelSelectComponent : BaseSelectMenuComponent - { - /// - /// List of channel types to include in the channel select component - /// - [JsonProperty("channel_types")] - public List ChannelTypes { get; set; } = new List(); + [JsonProperty("channel_types")] + public List ChannelTypes { get; set; } = new(); - /// - /// Select Menu Component Constructor - /// - public ChannelSelectComponent() : base(MessageComponentType.ChannelSelect) { } - } + /// + /// Select Menu Component Constructor + /// + public ChannelSelectComponent() : base(MessageComponentType.ChannelSelect) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/MentionableSelectComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/MentionableSelectComponent.cs index dd65adf8c..16ba00816 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/MentionableSelectComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/MentionableSelectComponent.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Select Menus Component within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MentionableSelectComponent : BaseSelectMenuComponent { /// - /// Represents a Select Menus Component within discord. + /// Select Menu Component Constructor /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MentionableSelectComponent : BaseSelectMenuComponent - { - /// - /// Select Menu Component Constructor - /// - public MentionableSelectComponent() : base(MessageComponentType.MentionableSelect) { } - } + public MentionableSelectComponent() : base(MessageComponentType.MentionableSelect) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/RoleSelectComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/RoleSelectComponent.cs index 3964ba861..5892774e9 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/RoleSelectComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/RoleSelectComponent.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Select Menus Component within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class RoleSelectComponent : BaseSelectMenuComponent { /// - /// Represents a Select Menus Component within discord. + /// Select Menu Component Constructor /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class RoleSelectComponent : BaseSelectMenuComponent - { - /// - /// Select Menu Component Constructor - /// - public RoleSelectComponent() : base(MessageComponentType.RoleSelect) { } - } + public RoleSelectComponent() : base(MessageComponentType.RoleSelect) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuDefaultValue.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuDefaultValue.cs index c36f9eabf..256c5d328 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuDefaultValue.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuDefaultValue.cs @@ -1,41 +1,40 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Select Default Value Structure within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class SelectMenuDefaultValue { /// - /// Represents a Select Default Value Structure within discord. + /// ID of a user, role, or channel /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class SelectMenuDefaultValue - { - /// - /// ID of a user, role, or channel - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Type of value that id represents. Either "user", "role", or "channel" - /// Default 1, Min 0, Max 25 - /// - [JsonProperty("type")] - public SelectMenuDefaultValueType Type { get; set; } + /// + /// Type of value that id represents. Either "user", "role", or "channel" + /// Default 1, Min 0, Max 25 + /// + [JsonProperty("type")] + public SelectMenuDefaultValueType Type { get; set; } - /// - /// Default Constructor - /// - [JsonConstructor] - public SelectMenuDefaultValue() { } + /// + /// Default Constructor + /// + [JsonConstructor] + public SelectMenuDefaultValue() { } - /// - /// Constructor - /// - /// ID of the default value - /// Type of the ID - public SelectMenuDefaultValue(Snowflake id, SelectMenuDefaultValueType type) - { - Id = id; - Type = type; - } + /// + /// Constructor + /// + /// ID of the default value + /// Type of the ID + public SelectMenuDefaultValue(Snowflake id, SelectMenuDefaultValueType type) + { + Id = id; + Type = type; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuDefaultValueType.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuDefaultValueType.cs index a3d4cae2a..da75ecb2e 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuDefaultValueType.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuDefaultValueType.cs @@ -2,30 +2,29 @@ using Oxide.Ext.Discord.Attributes; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Select Menus Default Value Type within discord. +/// +[JsonConverter(typeof(DiscordEnumConverter))] +public enum SelectMenuDefaultValueType { /// - /// Represents a Select Menus Default Value Type within discord. + /// Select Menu Default Value Type is User /// - [JsonConverter(typeof(DiscordEnumConverter))] - public enum SelectMenuDefaultValueType - { - /// - /// Select Menu Default Value Type is User - /// - [DiscordEnum("user")] - User, + [DiscordEnum("user")] + User, - /// - /// Select Menu Default Value Type is Role - /// - [DiscordEnum("role")] - Role, + /// + /// Select Menu Default Value Type is Role + /// + [DiscordEnum("role")] + Role, - /// - /// Select Menu Default Value Type is Channel - /// - [DiscordEnum("channel")] - Channel - } + /// + /// Select Menu Default Value Type is Channel + /// + [DiscordEnum("channel")] + Channel } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuOption.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuOption.cs index 02d9d3c57..4136432a6 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuOption.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/SelectMenuOption.cs @@ -2,53 +2,52 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Select Menu Option Structure within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class SelectMenuOption : IDiscordValidation { /// - /// Represents a Select Menu Option Structure within discord. + /// User-facing name of the option, + /// Max 100 characters /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class SelectMenuOption : IDiscordValidation - { - /// - /// User-facing name of the option, - /// Max 100 characters - /// - [JsonProperty("label")] - public string Label { get; set; } + [JsonProperty("label")] + public string Label { get; set; } - /// - /// Dev-define value of the option, - /// Max 100 characters - /// - [JsonProperty("value")] - public string Value { get; set; } + /// + /// Dev-define value of the option, + /// Max 100 characters + /// + [JsonProperty("value")] + public string Value { get; set; } - /// - /// Additional description of the option, - /// Max 100 characters - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Additional description of the option, + /// Max 100 characters + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Emoji in the option - /// - [JsonProperty("emoji")] - public DiscordEmoji Emoji { get; set; } + /// + /// Emoji in the option + /// + [JsonProperty("emoji")] + public DiscordEmoji Emoji { get; set; } - /// - /// Will show this option as selected by default - /// - [JsonProperty("default")] - public bool? Default { get; set; } + /// + /// Will show this option as selected by default + /// + [JsonProperty("default")] + public bool? Default { get; set; } - /// - public void Validate() - { - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionLabel(Label); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionValue(Value); - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionDescription(Description); - } + /// + public void Validate() + { + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionLabel(Label); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionValue(Value); + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionDescription(Description); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/StringSelectComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/StringSelectComponent.cs index bc57150dc..f4ecb6c6d 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/StringSelectComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/StringSelectComponent.cs @@ -2,38 +2,37 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Select Menus Component within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class StringSelectComponent : BaseSelectMenuComponent { /// - /// Represents a Select Menus Component within discord. + /// The choices in the select + /// Max 25 options /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class StringSelectComponent : BaseSelectMenuComponent - { - /// - /// The choices in the select - /// Max 25 options - /// - [JsonProperty("options")] - public List Options { get; } = new List(); + [JsonProperty("options")] + public List Options { get; } = new(); - /// - /// Select Menu Component Constructor - /// - public StringSelectComponent() : base(MessageComponentType.StringSelect) { } + /// + /// Select Menu Component Constructor + /// + public StringSelectComponent() : base(MessageComponentType.StringSelect) { } - /// - public override void Validate() + /// + public override void Validate() + { + base.Validate(); + if (Options != null) { - base.Validate(); - if (Options != null) + InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionCount(Options.Count); + for (int index = 0; index < Options.Count; index++) { - InvalidSelectMenuComponentException.ThrowIfInvalidSelectMenuOptionCount(Options.Count); - for (int index = 0; index < Options.Count; index++) - { - SelectMenuOption option = Options[index]; - option.Validate(); - } + SelectMenuOption option = Options[index]; + option.Validate(); } } } diff --git a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/UserSelectComponent.cs b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/UserSelectComponent.cs index 451d6c136..7bada334a 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/UserSelectComponent.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/MessageComponents/SelectMenus/UserSelectComponent.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Select Menus Component within discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class UserSelectComponent : BaseSelectMenuComponent { /// - /// Represents a Select Menus Component within discord. + /// Select Menu Component Constructor /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class UserSelectComponent : BaseSelectMenuComponent - { - /// - /// Select Menu Component Constructor - /// - public UserSelectComponent() : base(MessageComponentType.UserSelect) { } - } + public UserSelectComponent() : base(MessageComponentType.UserSelect) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionMessage.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionMessage.cs index 0a54b98d7..7b97e1ab3 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionMessage.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionMessage.cs @@ -1,19 +1,18 @@ using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Base Message for an interaction +/// +public abstract class BaseInteractionMessage : BaseMessageCreate { - /// - /// Represents a Base Message for an interaction - /// - public abstract class BaseInteractionMessage : BaseMessageCreate - { - /// - protected override void ValidateRequiredFields() { } + /// + protected override void ValidateRequiredFields() { } - /// - protected override void ValidateFlags() - { - InvalidMessageException.ThrowIfInvalidFlags(Flags, MessageFlags.SuppressEmbeds | MessageFlags.Ephemeral | MessageFlags.SuppressNotifications, "Invalid Message Flags Used for Channel Message. Only supported flags are MessageFlags.SuppressEmbeds, MessageFlags.Ephemeral, and MessageFlags.SuppressNotifications"); - } + /// + protected override void ValidateFlags() + { + InvalidMessageException.ThrowIfInvalidFlags(Flags, MessageFlags.SuppressEmbeds | MessageFlags.Ephemeral | MessageFlags.SuppressNotifications, "Invalid Message Flags Used for Channel Message. Only supported flags are MessageFlags.SuppressEmbeds, MessageFlags.Ephemeral, and MessageFlags.SuppressNotifications"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionResponse.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionResponse.cs index 93910b620..b463c5ecb 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionResponse.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionResponse.cs @@ -1,31 +1,30 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Base Interaction response +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public abstract class BaseInteractionResponse { /// - /// Represents a Base Interaction response + /// The type of response /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public abstract class BaseInteractionResponse - { - /// - /// The type of response - /// - [JsonProperty("type")] - public InteractionResponseType Type { get; set; } + [JsonProperty("type")] + public InteractionResponseType Type { get; set; } - /// - /// Constructor - /// - protected BaseInteractionResponse() {} + /// + /// Constructor + /// + protected BaseInteractionResponse() {} - /// - /// Constructor with - /// - /// - protected BaseInteractionResponse(InteractionResponseType type) - { - Type = type; - } + /// + /// Constructor with + /// + /// + protected BaseInteractionResponse(InteractionResponseType type) + { + Type = type; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionResponse{T}.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionResponse{T}.cs index 40cf7bf9c..3c87e174b 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionResponse{T}.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/Response/BaseInteractionResponse{T}.cs @@ -1,33 +1,32 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Base Interaction Response with generic data {T} +/// +/// {T} data type +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public abstract class BaseInteractionResponse : BaseInteractionResponse { /// - /// Represents a Base Interaction Response with generic data {T} + /// Response to the Interaction /// - /// {T} data type - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public abstract class BaseInteractionResponse : BaseInteractionResponse - { - /// - /// Response to the Interaction - /// - [JsonProperty("data")] - public T Data { get; set; } + [JsonProperty("data")] + public T Data { get; set; } - /// - /// Constructor - /// - protected BaseInteractionResponse() { } + /// + /// Constructor + /// + protected BaseInteractionResponse() { } - /// - /// Constructor with Data and response type - /// - /// Response type for the interaction - /// Data for the interaction - protected BaseInteractionResponse(InteractionResponseType type, T data) : base(type) - { - Data = data; - } + /// + /// Constructor with Data and response type + /// + /// Response type for the interaction + /// Data for the interaction + protected BaseInteractionResponse(InteractionResponseType type, T data) : base(type) + { + Data = data; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionAutoCompleteMessage.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionAutoCompleteMessage.cs index bcf8624a2..d0bed3e44 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionAutoCompleteMessage.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionAutoCompleteMessage.cs @@ -1,17 +1,16 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Interaction Auto Complete Response Message +/// +public class InteractionAutoCompleteMessage { /// - /// Interaction Auto Complete Response Message + /// Autocomplete choices (max of 25 choices) /// - public class InteractionAutoCompleteMessage - { - /// - /// Autocomplete choices (max of 25 choices) - /// - [JsonProperty("choices")] - public List Choices { get; set; } - } + [JsonProperty("choices")] + public List Choices { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionAutoCompleteResponse.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionAutoCompleteResponse.cs index 6ec41e19b..14d4046e8 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionAutoCompleteResponse.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionAutoCompleteResponse.cs @@ -1,19 +1,18 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents an Auto Complete response in Discord +/// +public class InteractionAutoCompleteResponse : BaseInteractionResponse { /// - /// Represents an Auto Complete response in Discord + /// Constructor /// - public class InteractionAutoCompleteResponse : BaseInteractionResponse - { - /// - /// Constructor - /// - public InteractionAutoCompleteResponse() { } + public InteractionAutoCompleteResponse() { } - /// - /// Constructor with initial message - /// - /// Message to use for the response - public InteractionAutoCompleteResponse(InteractionAutoCompleteMessage message) : base(InteractionResponseType.ApplicationCommandAutocompleteResult, message) { } - } + /// + /// Constructor with initial message + /// + /// Message to use for the response + public InteractionAutoCompleteResponse(InteractionAutoCompleteMessage message) : base(InteractionResponseType.ApplicationCommandAutocompleteResult, message) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionCallbackData.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionCallbackData.cs index b574ed7ba..8c9fb0728 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionCallbackData.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionCallbackData.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Interaction Application Command Callback Data Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class InteractionCallbackData : BaseInteractionMessage { - /// - /// Represents Interaction Application Command Callback Data Structure - /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InteractionCallbackData : BaseInteractionMessage - { - } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionModalMessage.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionModalMessage.cs index 9c5aaf05f..dd35a4ed2 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionModalMessage.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionModalMessage.cs @@ -1,31 +1,30 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents an Interaction Modal Message +/// +public class InteractionModalMessage { /// - /// Represents an Interaction Modal Message + /// A developer-defined identifier for the interactable form + /// Max 100 characters /// - public class InteractionModalMessage - { - /// - /// A developer-defined identifier for the interactable form - /// Max 100 characters - /// - [JsonProperty("custom_id")] - public string CustomId { get; set; } + [JsonProperty("custom_id")] + public string CustomId { get; set; } - /// - /// Title of the modal if Modal Response - /// Max 45 characters - /// - [JsonProperty("title")] - public string Title { get; set; } + /// + /// Title of the modal if Modal Response + /// Max 45 characters + /// + [JsonProperty("title")] + public string Title { get; set; } - /// - /// Used to create message components on a message - /// - [JsonProperty("components")] - public List Components { get; set; } - } + /// + /// Used to create message components on a message + /// + [JsonProperty("components")] + public List Components { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionModalResponse.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionModalResponse.cs index 48aafb972..32ebb2f8e 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionModalResponse.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionModalResponse.cs @@ -1,19 +1,18 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents an Interaction Modal Response +/// +public class InteractionModalResponse : BaseInteractionResponse { /// - /// Represents an Interaction Modal Response + /// Constructor /// - public class InteractionModalResponse : BaseInteractionResponse - { - /// - /// Constructor - /// - public InteractionModalResponse() { } + public InteractionModalResponse() { } - /// - /// Constructor with message - /// - /// Message to use for the response - public InteractionModalResponse(InteractionModalMessage message) : base(InteractionResponseType.Modal, message) { } - } + /// + /// Constructor with message + /// + /// Message to use for the response + public InteractionModalResponse(InteractionModalMessage message) : base(InteractionResponseType.Modal, message) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionPremiumRequiredMessage.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionPremiumRequiredMessage.cs deleted file mode 100644 index b8499382d..000000000 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionPremiumRequiredMessage.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Newtonsoft.Json; - -namespace Oxide.Ext.Discord.Entities -{ - /// - /// Message for Premium Required - /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InteractionPremiumRequiredMessage - { - - } -} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionPremiumRequiredResponse.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionPremiumRequiredResponse.cs deleted file mode 100644 index 785523ef7..000000000 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionPremiumRequiredResponse.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json; - -namespace Oxide.Ext.Discord.Entities -{ - /// - /// Response for premium Required - /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InteractionPremiumRequiredResponse : BaseInteractionResponse - { - /// - /// Constructor - /// - public InteractionPremiumRequiredResponse() : base(InteractionResponseType.PremiumRequired, new InteractionPremiumRequiredMessage()) { } - } -} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionResponse.cs b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionResponse.cs index c6b7f6093..cf63bec51 100644 --- a/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionResponse.cs +++ b/Oxide.Ext.Discord/Entities/Interactions/Response/InteractionResponse.cs @@ -2,37 +2,36 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Interaction Response +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class InteractionResponse : BaseInteractionResponse, IDiscordValidation, IFileAttachments { + /// + public List FileAttachments => Data?.FileAttachments; + /// - /// Represents Interaction Response + /// Default Constructor /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InteractionResponse : BaseInteractionResponse, IDiscordValidation, IFileAttachments - { - /// - public List FileAttachments => Data?.FileAttachments; + public InteractionResponse() {} - /// - /// Default Constructor - /// - public InteractionResponse() {} - - /// - /// Creates a - /// - /// The type of the response - /// The data for the response - public InteractionResponse(InteractionResponseType type, InteractionCallbackData data) - { - Type = type; - Data = data; - } + /// + /// Creates a + /// + /// The type of the response + /// The data for the response + public InteractionResponse(InteractionResponseType type, InteractionCallbackData data) + { + Type = type; + Data = data; + } - /// - public void Validate() - { - Data?.Validate(); - } + /// + public void Validate() + { + Data?.Validate(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Invites/DiscordInvite.cs b/Oxide.Ext.Discord/Entities/Invites/DiscordInvite.cs index 5b29fc945..e656c6190 100644 --- a/Oxide.Ext.Discord/Entities/Invites/DiscordInvite.cs +++ b/Oxide.Ext.Discord/Entities/Invites/DiscordInvite.cs @@ -3,108 +3,113 @@ using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents an Invite Structure that when used, adds a user to a guild or group DM channel. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordInvite { /// - /// Represents an Invite Structure that when used, adds a user to a guild or group DM channel. + /// The type of the invite /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordInvite - { - /// - /// The invite code (unique ID) - /// - [JsonProperty("code")] - public string Code { get; set; } + [JsonProperty("type")] + public InviteType Type { get; set; } + + /// + /// The invite code (unique ID) + /// + [JsonProperty("code")] + public string Code { get; set; } - /// - /// The guild this invite is for - /// See - /// - [JsonProperty("guild")] - public DiscordGuild Guild { get; set; } + /// + /// The guild this invite is for + /// See + /// + [JsonProperty("guild")] + public DiscordGuild Guild { get; set; } - /// - /// The channel this invite is for - /// See - /// - [JsonProperty("channel")] - public DiscordChannel Channel { get; set; } + /// + /// The channel this invite is for + /// See + /// + [JsonProperty("channel")] + public DiscordChannel Channel { get; set; } - /// - /// The user who created the invite - /// See - /// - [JsonProperty("inviter")] - public DiscordUser Inviter { get; set; } + /// + /// The user who created the invite + /// See + /// + [JsonProperty("inviter")] + public DiscordUser Inviter { get; set; } - /// - /// The target user for this invite - /// See - /// - [JsonProperty("target_user")] - public DiscordUser TargetUser { get; set; } + /// + /// The target user for this invite + /// See + /// + [JsonProperty("target_user")] + public DiscordUser TargetUser { get; set; } - /// - /// The type of user target for this invite - /// See - /// - [JsonProperty("target_user_type")] - public TargetUserType? UserTargetType { get; set; } + /// + /// The type of user target for this invite + /// See + /// + [JsonProperty("target_user_type")] + public TargetUserType? UserTargetType { get; set; } - /// - /// Approximate count of online members (only present when target_user is set) - /// - [JsonProperty("approximate_presence_count")] - public int? ApproximatePresenceCount { get; set; } + /// + /// Approximate count of online members (only present when target_user is set) + /// + [JsonProperty("approximate_presence_count")] + public int? ApproximatePresenceCount { get; set; } - /// - /// Approximate count of total members - /// - [JsonProperty("approximate_member_count")] - public int? ApproximateMemberCount { get; set; } + /// + /// Approximate count of total members + /// + [JsonProperty("approximate_member_count")] + public int? ApproximateMemberCount { get; set; } - /// - /// When the invite code expires - /// - [JsonProperty("expires_at")] - public DateTime? ExpiresAt { get; set; } + /// + /// When the invite code expires + /// + [JsonProperty("expires_at")] + public DateTime? ExpiresAt { get; set; } - /// - /// Stage instance data if there is a public Stage instance in the Stage channel this invite is for - /// - [Obsolete("This field is considered deprecated by discord and may be removed in a future update.")] - [JsonProperty("stage_instance")] - public InviteStageInstance StageInstance { get; set; } + /// + /// Stage instance data if there is a public Stage instance in the Stage channel this invite is for + /// + [Obsolete("This field is considered deprecated by discord and may be removed in a future update.")] + [JsonProperty("stage_instance")] + public InviteStageInstance StageInstance { get; set; } - /// - /// Guild scheduled event data, only included if guild_scheduled_event_id contains a valid guild scheduled event id - /// - [JsonProperty("guild_scheduled_event")] - public InviteStageInstance GuildScheduledEvent { get; set; } + /// + /// Guild scheduled event data, only included if guild_scheduled_event_id contains a valid guild scheduled event id + /// + [JsonProperty("guild_scheduled_event")] + public InviteStageInstance GuildScheduledEvent { get; set; } - /// - /// Returns an invite object for the given code. - /// See Get Invite - /// - /// Client to use - /// Invite code - /// Lookup query string parameters for the request - public static IPromise Get(DiscordClient client, string inviteCode, InviteLookup lookup = null) - { - return client.Bot.Rest.Get(client,$"invites/{inviteCode}{lookup?.ToQueryString()}"); - } + /// + /// Returns an invite object for the given code. + /// See Get Invite + /// + /// Client to use + /// Invite code + /// Lookup query string parameters for the request + public static IPromise Get(DiscordClient client, string inviteCode, InviteLookup lookup = null) + { + return client.Bot.Rest.Get(client,$"invites/{inviteCode}{lookup?.ToQueryString()}"); + } - /// - /// Delete an invite. - /// Requires the MANAGE_CHANNELS permission on the channel this invite belongs to, or MANAGE_GUILD to remove any invite across the guild. - /// Returns an invite object on success. - /// See Delete Invite - /// - /// Client to use - public IPromise Delete(DiscordClient client) - { - return client.Bot.Rest.Delete(client,$"invites/{Code}"); - } + /// + /// Delete an invite. + /// Requires the MANAGE_CHANNELS permission on the channel this invite belongs to, or MANAGE_GUILD to remove any invite across the guild. + /// Returns an invite object on success. + /// See Delete Invite + /// + /// Client to use + public IPromise Delete(DiscordClient client) + { + return client.Bot.Rest.Delete(client,$"invites/{Code}"); } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Invites/InviteLookup.cs b/Oxide.Ext.Discord/Entities/Invites/InviteLookup.cs index c7a186333..ba6d47615 100644 --- a/Oxide.Ext.Discord/Entities/Invites/InviteLookup.cs +++ b/Oxide.Ext.Discord/Entities/Invites/InviteLookup.cs @@ -1,49 +1,47 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Scheduled Event Lookup Structure within Discord. +/// +public class InviteLookup : IDiscordQueryString { /// - /// Represents a Scheduled Event Lookup Structure within Discord. + /// Whether the invite should contain approximate member counts /// - public class InviteLookup : IDiscordQueryString - { - /// - /// Whether the invite should contain approximate member counts - /// - public bool? WithCounts { get; set; } + public bool? WithCounts { get; set; } - /// - /// Whether the invite should contain the expiration date - /// - public bool? WithExpiration { get; set; } + /// + /// Whether the invite should contain the expiration date + /// + public bool? WithExpiration { get; set; } - /// - /// The guild scheduled event to include with the invite - /// - public bool? GuildScheduledEventId { get; set; } + /// + /// The guild scheduled event to include with the invite + /// + public bool? GuildScheduledEventId { get; set; } - /// - public string ToQueryString() + /// + public string ToQueryString() + { + QueryStringBuilder builder = new(); + if (WithCounts.HasValue) { - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); - if (WithCounts.HasValue) - { - builder.Add("with_counts", WithCounts.Value.ToString()); - } + builder.Add("with_counts", WithCounts.Value.ToString()); + } - if (WithExpiration.HasValue) - { - builder.Add("with_expiration", WithExpiration.Value.ToString()); - } + if (WithExpiration.HasValue) + { + builder.Add("with_expiration", WithExpiration.Value.ToString()); + } - if (GuildScheduledEventId.HasValue) - { - builder.Add("guild_scheduled_event_id", GuildScheduledEventId.Value.ToString()); - } - - return builder.ToStringAndFree(); + if (GuildScheduledEventId.HasValue) + { + builder.Add("guild_scheduled_event_id", GuildScheduledEventId.Value.ToString()); } + + return builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Invites/InviteMetadata.cs b/Oxide.Ext.Discord/Entities/Invites/InviteMetadata.cs index 18466acb6..b83254e42 100644 --- a/Oxide.Ext.Discord/Entities/Invites/InviteMetadata.cs +++ b/Oxide.Ext.Discord/Entities/Invites/InviteMetadata.cs @@ -1,42 +1,41 @@ using System; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Invite Metadata Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class InviteMetadata : DiscordInvite { /// - /// Represents Invite Metadata Structure + /// Number of times this invite has been used /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InviteMetadata : DiscordInvite - { - /// - /// Number of times this invite has been used - /// - [JsonProperty("uses")] - public int Uses { get; set; } + [JsonProperty("uses")] + public int Uses { get; set; } - /// - /// Max number of times this invite can be used - /// - [JsonProperty("max_uses")] - public int MaxUses { get; set; } + /// + /// Max number of times this invite can be used + /// + [JsonProperty("max_uses")] + public int MaxUses { get; set; } - /// - /// Duration (in seconds) after which the invite expires - /// - [JsonProperty("max_age")] - public int MaxAge { get; set; } + /// + /// Duration (in seconds) after which the invite expires + /// + [JsonProperty("max_age")] + public int MaxAge { get; set; } - /// - /// Whether this invite only grants temporary membership - /// - [JsonProperty("temporary")] - public bool Temporary { get; set; } + /// + /// Whether this invite only grants temporary membership + /// + [JsonProperty("temporary")] + public bool Temporary { get; set; } - /// - /// When this invite was created - /// - [JsonProperty("created_at")] - public DateTime CreatedAt { get; set; } - } + /// + /// When this invite was created + /// + [JsonProperty("created_at")] + public DateTime CreatedAt { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Invites/InviteStageInstance.cs b/Oxide.Ext.Discord/Entities/Invites/InviteStageInstance.cs index 76bdfff72..b22cb27a3 100644 --- a/Oxide.Ext.Discord/Entities/Invites/InviteStageInstance.cs +++ b/Oxide.Ext.Discord/Entities/Invites/InviteStageInstance.cs @@ -1,36 +1,35 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents an Invite Stage Instance +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class InviteStageInstance { /// - /// Represents an Invite Stage Instance + /// The members speaking in the Stage /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class InviteStageInstance - { - /// - /// The members speaking in the Stage - /// - [JsonProperty("members")] - public List Members { get; set; } + [JsonProperty("members")] + public List Members { get; set; } - /// - /// The number of users in the Stage - /// - [JsonProperty("participant_count")] - public int ParticipantCount { get; set; } + /// + /// The number of users in the Stage + /// + [JsonProperty("participant_count")] + public int ParticipantCount { get; set; } - /// - /// The number of users speaking in the Stage - /// - [JsonProperty("speaker_count")] - public int SpeakerCount { get; set; } + /// + /// The number of users speaking in the Stage + /// + [JsonProperty("speaker_count")] + public int SpeakerCount { get; set; } - /// - /// The topic of the Stage instance (1-120 characters) - /// - [JsonProperty("topic")] - public string Topic { get; set; } - } + /// + /// The topic of the Stage instance (1-120 characters) + /// + [JsonProperty("topic")] + public string Topic { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Invites/InviteType.cs b/Oxide.Ext.Discord/Entities/Invites/InviteType.cs new file mode 100644 index 000000000..e2a245e9c --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Invites/InviteType.cs @@ -0,0 +1,22 @@ +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Invite Types +/// +public enum InviteType : byte +{ + /// + /// Guild Invite + /// + Guild = 0, + + /// + /// Guild Invite + /// + GroupDm = 1, + + /// + /// Guild Invite + /// + Friend = 2, +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Invites/TargetUserType.cs b/Oxide.Ext.Discord/Entities/Invites/TargetUserType.cs index 97f2eda74..72deb0d96 100644 --- a/Oxide.Ext.Discord/Entities/Invites/TargetUserType.cs +++ b/Oxide.Ext.Discord/Entities/Invites/TargetUserType.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Target User Types +/// +public enum TargetUserType : byte { /// - /// Represents Target User Types + /// Target user type is not defined /// - public enum TargetUserType : byte - { - /// - /// Target user type is not defined - /// - Undefined = 0, + Undefined = 0, - /// - /// Invite is for a go live stream - /// - Stream = 1 - } + /// + /// Invite is for a go live stream + /// + Stream = 1 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/AllowedMentionTypes.cs b/Oxide.Ext.Discord/Entities/Messages/AllowedMentionTypes.cs index 8ad451003..61f738217 100644 --- a/Oxide.Ext.Discord/Entities/Messages/AllowedMentionTypes.cs +++ b/Oxide.Ext.Discord/Entities/Messages/AllowedMentionTypes.cs @@ -2,35 +2,34 @@ using Oxide.Ext.Discord.Attributes; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Allowed Mention Types for a message +/// +[JsonConverter(typeof(DiscordEnumConverter))] +public enum AllowedMentionTypes : byte { /// - /// Represents a Allowed Mention Types for a message + /// Discord Extension doesn't currently support this allowed mention type. /// - [JsonConverter(typeof(DiscordEnumConverter))] - public enum AllowedMentionTypes : byte - { - /// - /// Discord Extension doesn't currently support this allowed mention type. - /// - Unknown, + Unknown, - /// - /// Controls role mentions - /// - [DiscordEnum("roles")] - Roles, + /// + /// Controls role mentions + /// + [DiscordEnum("roles")] + Roles, - /// - /// Controls user mentions - /// - [DiscordEnum("users")] - Users, + /// + /// Controls user mentions + /// + [DiscordEnum("users")] + Users, - /// - /// Controls @everyone and @here mentions - /// - [DiscordEnum("everyone")] - Everyone, - } + /// + /// Controls @everyone and @here mentions + /// + [DiscordEnum("everyone")] + Everyone, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/AllowedMentions.cs b/Oxide.Ext.Discord/Entities/Messages/AllowedMentions.cs index 86906d28e..e8fbbd6f3 100644 --- a/Oxide.Ext.Discord/Entities/Messages/AllowedMentions.cs +++ b/Oxide.Ext.Discord/Entities/Messages/AllowedMentions.cs @@ -2,47 +2,46 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Allowed Mention Types +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class AllowedMentions { /// - /// Represents a Allowed Mention Types + /// An array of allowed mention types to parse from the content. + /// /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class AllowedMentions - { - /// - /// An array of allowed mention types to parse from the content. - /// - /// - [JsonProperty("parse")] - public IList AllowedTypes { get; set; } + [JsonProperty("parse")] + public IList AllowedTypes { get; set; } - /// - /// Array of Role IDs to mention (Max size of 100) - /// - [JsonProperty("roles")] - public IList Roles { get; set; } + /// + /// Array of Role IDs to mention (Max size of 100) + /// + [JsonProperty("roles")] + public IList Roles { get; set; } - /// - /// Array of User IDs to mention (Max size of 100) - /// - [JsonProperty("users")] - public IList Users { get; set; } + /// + /// Array of User IDs to mention (Max size of 100) + /// + [JsonProperty("users")] + public IList Users { get; set; } - /// - /// For replies, whether to mention the author of the message being replied to (default false) - /// - [JsonProperty("replied_user")] - public bool RepliedUser { get; set; } + /// + /// For replies, whether to mention the author of the message being replied to (default false) + /// + [JsonProperty("replied_user")] + public bool RepliedUser { get; set; } - /// - /// Prevents all mentions - /// - public static readonly AllowedMentions None = new AllowedMentions - { - AllowedTypes = Array.Empty(), - Roles = Array.Empty(), - Users = Array.Empty() - }; - } + /// + /// Prevents all mentions + /// + public static readonly AllowedMentions None = new() + { + AllowedTypes = Array.Empty(), + Roles = Array.Empty(), + Users = Array.Empty() + }; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/AttachmentFlags.cs b/Oxide.Ext.Discord/Entities/Messages/AttachmentFlags.cs index 4e4d4bd3b..ae371371c 100644 --- a/Oxide.Ext.Discord/Entities/Messages/AttachmentFlags.cs +++ b/Oxide.Ext.Discord/Entities/Messages/AttachmentFlags.cs @@ -1,21 +1,20 @@ using System; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Attachment flags for an attachment +/// +[Flags] +public enum AttachmentFlags { /// - /// Represents a Attachment flags for an attachment + /// No Attachment Flags /// - [Flags] - public enum AttachmentFlags - { - /// - /// No Attachment Flags - /// - None = 0, + None = 0, - /// - /// This attachment has been edited using the remix feature on mobile - /// - IsRemix = 1 << 2, - } + /// + /// This attachment has been edited using the remix feature on mobile + /// + IsRemix = 1 << 2, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/BaseMessageCreate.cs b/Oxide.Ext.Discord/Entities/Messages/BaseMessageCreate.cs index 0a1f0b855..23cd63817 100644 --- a/Oxide.Ext.Discord/Entities/Messages/BaseMessageCreate.cs +++ b/Oxide.Ext.Discord/Entities/Messages/BaseMessageCreate.cs @@ -3,125 +3,131 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a base message in discord +/// +public abstract class BaseMessageCreate : IFileAttachments, IDiscordValidation, IDiscordMessageTemplate { /// - /// Represents a base message in discord + /// Contents of the message /// - public abstract class BaseMessageCreate : IFileAttachments, IDiscordValidation, IDiscordMessageTemplate - { - /// - /// Contents of the message - /// - [JsonProperty("content")] - public string Content { get; set; } + [JsonProperty("content")] + public string Content { get; set; } - /// - /// Whether this was a TTS message - /// - [JsonProperty("tts")] - public bool? Tts { get; set; } + /// + /// Whether this was a TTS message + /// + [JsonProperty("tts")] + public bool? Tts { get; set; } + + /// + /// Embeds for the message + /// Embeds are deduplicated by URL. If a message contains multiple embeds with the same URL, only the first is shown. + /// + [JsonProperty("embeds")] + public List Embeds { get; set; } - /// - /// Embeds for the message - /// Embeds are deduplicated by URL. If a message contains multiple embeds with the same URL, only the first is shown. - /// - [JsonProperty("embeds")] - public List Embeds { get; set; } + /// + /// Allowed mentions for a message + /// Allows for more granular control over mentions without various hacks to the message content. + /// + [JsonProperty("allowed_mentions")] + public AllowedMentions AllowedMentions { get; set; } - /// - /// Allowed mentions for a message - /// Allows for more granular control over mentions without various hacks to the message content. - /// - [JsonProperty("allowed_mentions")] - public AllowedMentions AllowedMentions { get; set; } + /// + /// Used to create message components on a message + /// + [JsonProperty("components")] + public List Components { get; set; } - /// - /// Used to create message components on a message - /// - [JsonProperty("components")] - public List Components { get; set; } + /// + /// IDs of up to 3 stickers in the server to send in the message + /// + [JsonProperty("sticker_ids")] + public List StickerIds { get; set; } - /// - /// IDs of up to 3 stickers in the server to send in the message - /// - [JsonProperty("sticker_ids")] - public List StickerIds { get; set; } + /// + /// Attachments for the message + /// + [JsonProperty("flags")] + public MessageFlags? Flags { get; set; } - /// - /// Attachments for the message - /// - [JsonProperty("flags")] - public MessageFlags? Flags { get; set; } + /// + /// Poll Create Request + /// + [JsonProperty("poll")] + public PollCreate Poll { get; set; } - /// - /// Attachments for a discord message - /// - public List FileAttachments { get; set; } + /// + /// Attachments for a discord message + /// + public List FileAttachments { get; set; } - /// - /// Attachments for the message - /// - [JsonProperty("attachments")] - public List Attachments { get; set; } - - /// - /// Adds an attachment to the message - /// - /// Name of the file - /// byte[] of the attachment - /// Attachment content type - /// Description for the attachment - public void AddAttachment(string filename, byte[] data, string contentType, string description = null) - { - InvalidFileNameException.ThrowIfInvalid(filename); - InvalidMessageException.ThrowIfInvalidAttachmentDescription(description); + /// + /// Attachments for the message + /// + [JsonProperty("attachments")] + public List Attachments { get; set; } - if (FileAttachments == null) - { - FileAttachments = new List(); - } + /// + /// Adds an attachment to the message + /// + /// Name of the file + /// byte[] of the attachment + /// Attachment content type + /// Description for the attachment + /// Title of the attachment + public void AddAttachment(string filename, byte[] data, string contentType, string description = null, string title = null) + { + InvalidFileNameException.ThrowIfInvalid(filename); + InvalidMessageException.ThrowIfInvalidAttachmentDescription(description); - if (Attachments == null) - { - Attachments = new List(); - } + if (FileAttachments == null) + { + FileAttachments = new List(); + } - FileAttachments.Add(new MessageFileAttachment(filename, data, contentType)); - Attachments.Add(new MessageAttachment {Id = new Snowflake((ulong)FileAttachments.Count), Filename = filename, Description = description}); + if (Attachments == null) + { + Attachments = new List(); } - /// - public void Validate() + FileAttachments.Add(new MessageFileAttachment(filename, data, contentType)); + Attachments.Add(new MessageAttachment {Id = new Snowflake((ulong)FileAttachments.Count), Filename = filename, Description = description, Title = title}); + } + + /// + public void Validate() + { + ValidateRequiredFields(); + InvalidMessageException.ThrowIfInvalidContent(Content); + ValidateFlags(); + if (Components != null) { - ValidateRequiredFields(); - InvalidMessageException.ThrowIfInvalidContent(Content); - ValidateFlags(); - if (Components != null) + for (int index = 0; index < Components.Count; index++) { - for (int index = 0; index < Components.Count; index++) - { - ActionRowComponent component = Components[index]; - component.Validate(); - } + ActionRowComponent component = Components[index]; + component.Validate(); } } + } - /// - /// Validates required fields for the message - /// - protected virtual void ValidateRequiredFields() - { - InvalidMessageException.ThrowIfMissingRequiredField(this); - } + /// + /// Validates required fields for the message + /// + protected virtual void ValidateRequiredFields() + { + InvalidMessageException.ThrowIfMissingRequiredField(this); + } - /// - /// Validates that the message flags are correct for the message type - /// - /// - protected virtual void ValidateFlags() - { - InvalidMessageException.ThrowIfInvalidFlags(Flags, MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications, "Invalid Message Flags Used for Channel Message. Only supported flags are MessageFlags.SuppressEmbeds or MessageFlags.SuppressNotifications"); - } + /// + /// Validates that the message flags are correct for the message type + /// + /// + protected virtual void ValidateFlags() + { + InvalidMessageException.ThrowIfInvalidFlags(Flags, MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications, "Invalid Message Flags Used for Channel Message. Only supported flags are MessageFlags.SuppressEmbeds or MessageFlags.SuppressNotifications"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/DiscordMessage.cs b/Oxide.Ext.Discord/Entities/Messages/DiscordMessage.cs index f78843c70..53c9be287 100644 --- a/Oxide.Ext.Discord/Entities/Messages/DiscordMessage.cs +++ b/Oxide.Ext.Discord/Entities/Messages/DiscordMessage.cs @@ -13,756 +13,805 @@ using Oxide.Plugins; using UserData = Oxide.Ext.Discord.Data.UserData; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Structure sent in a channel within Discord.. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordMessage : IFileAttachments { /// - /// Represents a Message Structure sent in a channel within Discord.. - /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordMessage : IFileAttachments - { - /// - /// ID of the message - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } - - /// - /// ID of the channel the message was sent in - /// - [JsonProperty("channel_id")] - public Snowflake ChannelId { get; set; } - - /// - /// ID of the guild the message was sent in - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } - - /// - /// The author of this message (not guaranteed to be a valid user) - /// The author object follows the structure of the user object, but is only a valid user in the case where the message is generated by a user or bot user. - /// If the message is generated by a webhook, the author object corresponds to the webhook's id, username, and avatar. - /// You can tell if a message is generated by a webhook by checking for the webhook_id on the message object. - /// - /// - [JsonProperty("author")] - public DiscordUser Author { get; set; } - - /// - /// Member properties for this message's author - /// - /// - [JsonProperty("member")] - public GuildMember Member { get; set; } - - /// - /// Contents of the message - /// - [JsonProperty("content")] - public string Content { get; set; } - - /// - /// When this message was sent - /// - [JsonProperty("timestamp")] - public DateTime Timestamp { get; set; } - - /// - /// When this message was edited (or null if never) - /// - [JsonProperty("edited_timestamp")] - public DateTime? EditedTimestamp { get; set; } - - /// - /// Whether this was a TTS message - /// - [JsonProperty("tts")] - public bool Tts { get; set; } - - /// - /// Whether this message mentions everyone - /// - [JsonProperty("mention_everyone")] - public bool MentionEveryone { get; set; } - - /// - /// Users specifically mentioned in the message - /// - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("mentions")] - public Hash Mentions { get; set; } - - /// - /// Roles specifically mentioned in this message - /// - [JsonProperty("mention_roles")] - public List MentionRoles { get; set; } - - /// - /// Channels specifically mentioned in this message - /// - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("mention_channels")] - public Hash MentionsChannels { get; set; } - - /// - /// Any attached files - /// - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("attachments")] - public Hash Attachments { get; set; } - - /// - /// Any embedded content - /// - /// - [JsonProperty("embeds")] - public List Embeds { get; set; } - - /// - /// Reactions to the message - /// - /// - [JsonProperty("reactions")] - public List Reactions { get; set; } - - /// - /// Used for validating a message was sent - /// - [JsonProperty("nonce")] - public string Nonce { get; set; } - - /// - /// Whether this message is pinned - /// - [JsonProperty("pinned")] - public bool Pinned { get; set; } - - /// - /// If the message is generated by a webhook, this is the webhook's id - /// - [JsonProperty("webhook_id")] - public Snowflake? WebhookId { get; set; } - - /// - /// Type of message - /// - /// - [JsonProperty("type")] - public MessageType? Type { get; set; } - - /// - /// Sent with Rich Presence-related chat embeds - /// - /// - [JsonProperty("activity")] - public MessageActivity Activity { get; set; } - - /// - /// Sent with Rich Presence-related chat embeds - /// - /// - [JsonProperty("application")] - public DiscordApplication Application { get; set; } - - /// - /// If the message is an Interaction or application-owned webhook, this is the id of the application - /// - [JsonProperty("application_id")] - public Snowflake? ApplicationId { get; set; } - - /// - /// Data showing the source of a crosspost, channel follow add, pin, or reply message - /// - /// - [JsonProperty("message_reference")] - public MessageReference MessageReference { get; set; } - - /// - /// Message flags combined as a bitfield - /// - /// - [JsonProperty("flags")] - public MessageFlags Flags { get; set; } - - /// - /// The message associated with the message_reference - /// - [JsonProperty("referenced_message")] - public DiscordMessage ReferencedMessage { get; internal set; } - - /// - /// Sent if the message is a response to an Interaction - /// - [JsonProperty("interaction")] - public MessageInteraction Interaction { get; set; } - - /// - /// The thread that was started from this message, includes thread member object - /// - [JsonProperty("thread")] - public DiscordChannel Thread { get; set; } - - /// - /// Sent if the message contains components like buttons, action rows, or other interactive components - /// - [JsonProperty("components")] - public List Components { get; set; } - - /// - /// Sent if the message contains stickers - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("sticker_items")] - public Hash StickerItems { get; set; } - - /// - /// A generally increasing integer (there may be gaps or duplicates) that represents the approximate position of the message in a thread, it can be used to estimate the relative position of the message in a thread in company with total_message_sent on parent thread - /// - [JsonProperty("position")] - public int? Position { get; set; } - - /// - /// The data of the role subscription purchase or renewal that prompted this ROLE_SUBSCRIPTION_PURCHASE message - /// - [JsonProperty("role_subscription_data")] - public RoleSubscription RoleSubscriptionData { get; set; } - - /// - /// File Attachments to add to the message on edit - /// - public List FileAttachments { get; set; } - - /// - /// Post a message to a guild text or DM channel. - /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. - /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. - /// See Create Message - /// - /// Client to use - /// Channel ID to send the message to - /// Message to be created - public static IPromise Create(DiscordClient client, Snowflake channelId, MessageCreate message) - { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - UserData userData = client.Bot.DirectMessagesByChannelId[channelId]?.UserData; - DateTime? isBlocked = userData?.GetBlockedUntil(); - - if (isBlocked.HasValue && isBlocked.Value > DateTime.UtcNow) - { - DiscordUser user = userData.GetUser(); - client.Logger.Debug("Blocking CreateMessage. User {0} ({1}) is DM blocked until {2}.", user.FullUserName, user.Id, userData.GetBlockedUntil()); - return Promise.Rejected(new BlockedUserException(userData.GetUser(), isBlocked.Value)); - } - - IPromise response = client.Bot.Rest.Post(client, $"channels/{channelId}/messages", message); - if (userData != null) - { - response.Catch(ex => userData.ProcessError(client, ex)); - } - - return response; - } + /// ID of the message + /// + [JsonProperty("id")] + public Snowflake Id { get; set; } + + /// + /// ID of the channel the message was sent in + /// + [JsonProperty("channel_id")] + public Snowflake ChannelId { get; set; } + + /// + /// ID of the guild the message was sent in + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } + + /// + /// The author of this message (not guaranteed to be a valid user) + /// The author object follows the structure of the user object, but is only a valid user in the case where the message is generated by a user or bot user. + /// If the message is generated by a webhook, the author object corresponds to the webhook's id, username, and avatar. + /// You can tell if a message is generated by a webhook by checking for the webhook_id on the message object. + /// + /// + [JsonProperty("author")] + public DiscordUser Author { get; set; } + + /// + /// Member properties for this message's author + /// + /// + [JsonProperty("member")] + public GuildMember Member { get; set; } - /// - /// Post a message to a guild text or DM channel. - /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. - /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. - /// See Create Message - /// - /// Client to use - /// Channel ID to send the message to - /// Builder for the message - public static IPromise Create(DiscordClient client, Snowflake channelId, DiscordMessageBuilder builder) - { - return Create(client, channelId, builder.Build()); - } + /// + /// Contents of the message + /// + [JsonProperty("content")] + public string Content { get; set; } - /// - /// Post a message to a guild text or DM channel. - /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. - /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. - /// See Create Message - /// - /// Client to use - /// Channel ID to send the message to - /// Content of the message - public static IPromise Create(DiscordClient client, Snowflake channelId, string message) - { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - MessageCreate createMessage = new MessageCreate - { - Content = message - }; + /// + /// When this message was sent + /// + [JsonProperty("timestamp")] + public DateTime Timestamp { get; set; } - return Create(client, channelId, createMessage); - } + /// + /// When this message was edited (or null if never) + /// + [JsonProperty("edited_timestamp")] + public DateTime? EditedTimestamp { get; set; } + + /// + /// Whether this was a TTS message + /// + [JsonProperty("tts")] + public bool Tts { get; set; } - /// - /// Post a message to a guild text or DM channel. - /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. - /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. - /// See Create Message - /// - /// Client to use - /// Channel ID to send the message to - /// Embed to be send in the message - public static IPromise Create(DiscordClient client, Snowflake channelId, DiscordEmbed embed) - { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - MessageCreate createMessage = new MessageCreate - { - Embeds = new List {embed} - }; + /// + /// Whether this message mentions everyone + /// + [JsonProperty("mention_everyone")] + public bool MentionEveryone { get; set; } - return Create(client, channelId, createMessage); - } + /// + /// Users specifically mentioned in the message + /// + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("mentions")] + public Hash Mentions { get; set; } + + /// + /// Roles specifically mentioned in this message + /// + [JsonProperty("mention_roles")] + public List MentionRoles { get; set; } - /// - /// Post a message to a guild text or DM channel. - /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. - /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. - /// See Create Message - /// - /// Client to use - /// Channel ID to send the message to - /// Embeds to be send in the message - public static IPromise Create(DiscordClient client, Snowflake channelId, List embeds) - { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - MessageCreate createMessage = new MessageCreate - { - Embeds = embeds - }; + /// + /// Channels specifically mentioned in this message + /// + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("mention_channels")] + public Hash MentionsChannels { get; set; } - return Create(client, channelId, createMessage); - } + /// + /// Any attached files + /// + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("attachments")] + public Hash Attachments { get; set; } + + /// + /// Any embedded content + /// + /// + [JsonProperty("embeds")] + public List Embeds { get; set; } + + /// + /// Reactions to the message + /// + /// + [JsonProperty("reactions")] + public List Reactions { get; set; } - /// - /// Send a message in the channel with the given ID using a global message template - /// - /// Client to use - /// Channel ID to send the message in - /// Plugin for the template - /// Template Name - /// Message to use (optional) - /// Placeholders to apply (optional) - public static IPromise CreateGlobalTemplateMessage(DiscordClient client, Snowflake channelId, Plugin plugin, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) - { - MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(plugin, templateName).ToMessage(placeholders, message); - return Create(client, channelId, template); - } + /// + /// Used for validating a message was sent + /// + [JsonProperty("nonce")] + public string Nonce { get; set; } - /// - /// Send a message in the channel with the given ID using a localized message template - /// - /// Client to use - /// Channel ID to send the message in - /// Plugin for the template - /// Template Name - /// Oxide language to use - /// Message to use (optional) - /// Placeholders to apply (optional) - public static IPromise CreateTemplateMessage(DiscordClient client, Snowflake channelId, Plugin plugin, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, MessageCreate message = null, PlaceholderData placeholders = null) - { - MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(plugin, templateName, language).ToMessage(placeholders, message); - return Create(client, channelId, template); - } + /// + /// Whether this message is pinned + /// + [JsonProperty("pinned")] + public bool Pinned { get; set; } - /// - /// Returns a specific message in the channel. - /// If operating on a guild channel, this endpoint requires the 'READ_MESSAGE_HISTORY' permission to be present on the current user. - /// See Get Channel Messages - /// - /// Client to use - /// Channel ID where the message is - /// Message ID of the message - public static IPromise GetMessage(DiscordClient client, Snowflake channelId, Snowflake messageId) - { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - InvalidSnowflakeException.ThrowIfInvalid(messageId, nameof(messageId)); - return client.Bot.Rest.Get(client,$"channels/{channelId}/messages/{messageId}"); - } + /// + /// If the message is generated by a webhook, this is the webhook's id + /// + [JsonProperty("webhook_id")] + public Snowflake? WebhookId { get; set; } + + /// + /// Type of message + /// + /// + [JsonProperty("type")] + public MessageType? Type { get; set; } - /// - /// Replies to a previously sent message - /// See Create Message - /// - /// Client to use - /// Message to send - public IPromise Reply(DiscordClient client, MessageCreate message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - if (message.MessageReference == null) - { - message.MessageReference = new MessageReference {MessageId = Id, GuildId = GuildId}; - } - - return Create(client, ChannelId, message); - } + /// + /// Sent with Rich Presence-related chat embeds + /// + /// + [JsonProperty("activity")] + public MessageActivity Activity { get; set; } - /// - /// Replies to a previously sent message - /// See Create Message - /// - /// Client to use - /// Builder for the message - public IPromise Reply(DiscordClient client, DiscordMessageBuilder builder) - { - return Reply(client, builder.Build()); - } + /// + /// Sent with Rich Presence-related chat embeds + /// + /// + [JsonProperty("application")] + public DiscordApplication Application { get; set; } - /// - /// Replies to a previously sent message - /// See Create Message - /// - /// Client to use - /// Message text to send - public IPromise Reply(DiscordClient client, string message) - { - MessageCreate newMessage = new MessageCreate - { - Content = message - }; + /// + /// If the message is an Interaction or application-owned webhook, this is the id of the application + /// + [JsonProperty("application_id")] + public Snowflake? ApplicationId { get; set; } + + /// + /// Data showing the source of a crosspost, channel follow add, pin, or reply message + /// + /// + [JsonProperty("message_reference")] + public MessageReference MessageReference { get; set; } + + /// + /// The message associated with the message_reference. + /// This is a minimal subset of fields in a message (e.g. author is excluded.) + /// + /// + [JsonProperty("message_snapshots")] + public List MessageSnapshots { get; set; } + + /// + /// Message flags combined as a bitfield + /// + /// + [JsonProperty("flags")] + public MessageFlags Flags { get; set; } - return Reply(client, newMessage); + /// + /// The message associated with the message_reference + /// + [JsonProperty("referenced_message")] + public DiscordMessage ReferencedMessage { get; internal set; } + + /// + /// sent if the message is sent as a result of an interaction + /// + [JsonProperty("interaction_metadata")] + public MessageInteraction InteractionMetadata { get; set; } + + /// + /// Sent if the message is a response to an Interaction + /// + [Obsolete("Deprecated in favor of InteractionMetadata")] + [JsonProperty("interaction")] + public MessageInteraction Interaction { get; set; } + + /// + /// The thread that was started from this message, includes thread member object + /// + [JsonProperty("thread")] + public DiscordChannel Thread { get; set; } + + /// + /// Sent if the message contains components like buttons, action rows, or other interactive components + /// + [JsonProperty("components")] + public List Components { get; set; } + + /// + /// Sent if the message contains stickers + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("sticker_items")] + public Hash StickerItems { get; set; } + + /// + /// A generally increasing integer (there may be gaps or duplicates) that represents the approximate position of the message in a thread, it can be used to estimate the relative position of the message in a thread in company with total_message_sent on parent thread + /// + [JsonProperty("position")] + public int? Position { get; set; } + + /// + /// The data of the role subscription purchase or renewal that prompted this ROLE_SUBSCRIPTION_PURCHASE message + /// + [JsonProperty("role_subscription_data")] + public RoleSubscription RoleSubscriptionData { get; set; } + + /// + /// Poll object + /// + [JsonProperty("poll")] + public DiscordPoll Poll { get; set; } + + /// + /// The call associated with the message + /// + [JsonProperty("call")] + public MessageCall Call { get; set; } + + /// + /// File Attachments to add to the message on edit + /// + public List FileAttachments { get; set; } + + /// + /// Post a message to a guild text or DM channel. + /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. + /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. + /// See Create Message + /// + /// Client to use + /// Channel ID to send the message to + /// Message to be created + public static IPromise Create(DiscordClient client, Snowflake channelId, MessageCreate message) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + UserData userData = client.Bot.DirectMessagesByChannelId[channelId]?.UserData; + DateTime? isBlocked = userData?.GetBlockedUntil(); + + if (isBlocked.HasValue && isBlocked.Value > DateTime.UtcNow) + { + DiscordUser user = userData.GetUser(); + client.Logger.Debug("Blocking CreateMessage. User {0} ({1}) is DM blocked until {2}.", user.FullUserName, user.Id, userData.GetBlockedUntil()); + return Promise.Rejected(new BlockedUserException(userData.GetUser(), isBlocked.Value)); } - /// - /// Replies to a previously sent message - /// See Create Message - /// - /// Client to use - /// Embed to send - public IPromise Reply(DiscordClient client, DiscordEmbed embed) + IPromise response = client.Bot.Rest.Post(client, $"channels/{channelId}/messages", message); + if (userData != null) { - return Reply(client, new List {embed}); + response.Catch(ex => userData.ProcessError(client, ex)); } + + return response; + } - /// - /// Replies to a previously sent message - /// See Create Message - /// - /// Client to use - /// Embeds to send - public IPromise Reply(DiscordClient client, List embeds) + /// + /// Post a message to a guild text or DM channel. + /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. + /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. + /// See Create Message + /// + /// Client to use + /// Channel ID to send the message to + /// Builder for the message + public static IPromise Create(DiscordClient client, Snowflake channelId, DiscordMessageBuilder builder) + { + return Create(client, channelId, builder.Build()); + } + + /// + /// Post a message to a guild text or DM channel. + /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. + /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. + /// See Create Message + /// + /// Client to use + /// Channel ID to send the message to + /// Content of the message + public static IPromise Create(DiscordClient client, Snowflake channelId, string message) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + MessageCreate createMessage = new() { - MessageCreate newMessage = new MessageCreate - { - Embeds = embeds, - }; + Content = message + }; - return Reply(client, newMessage); - } + return Create(client, channelId, createMessage); + } - /// - /// Reply to a message using a global message template - /// - /// Client to use - /// Template Name - /// Message to use (optional) - /// Placeholders to apply (optional) - public IPromise ReplyWithGlobalTemplate(DiscordClient client, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) + /// + /// Post a message to a guild text or DM channel. + /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. + /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. + /// See Create Message + /// + /// Client to use + /// Channel ID to send the message to + /// Embed to be send in the message + public static IPromise Create(DiscordClient client, Snowflake channelId, DiscordEmbed embed) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + MessageCreate createMessage = new() { - MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(client.Plugin, templateName).ToMessage(placeholders, message); - return Reply(client, template); - } + Embeds = [embed] + }; - /// - /// Reply to a message using a global message template - /// - /// Client to use - /// Template Name - /// Oxide language to use - /// Message to use (optional) - /// Placeholders to apply (optional) - public IPromise ReplyWithTemplate(DiscordClient client, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, MessageCreate message = null, PlaceholderData placeholders = null) - { - MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, language).ToMessage(placeholders, message); - return Reply(client, template); - } + return Create(client, channelId, createMessage); + } - /// - /// Crosspost a message in a News Channel to following channels. - /// This endpoint requires the 'SEND_MESSAGES' permission, if the current user sent the message, or additionally the 'MANAGE_MESSAGES' permission, for all other messages, to be present for the current user. - /// See Crosspost Message - /// - /// Client to use - /// Message ID to cross post - public IPromise CrossPostMessage(DiscordClient client, Snowflake messageId) + /// + /// Post a message to a guild text or DM channel. + /// If operating on a guild channel, this endpoint requires the SEND_MESSAGES permission to be present on the current user. + /// If the tts field is set to true, the SEND_TTS_MESSAGES permission is required for the message to be spoken. + /// See Create Message + /// + /// Client to use + /// Channel ID to send the message to + /// Embeds to be send in the message + public static IPromise Create(DiscordClient client, Snowflake channelId, List embeds) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + MessageCreate createMessage = new() { - InvalidSnowflakeException.ThrowIfInvalid(Id, nameof(Id)); - InvalidSnowflakeException.ThrowIfInvalid(messageId, nameof(messageId)); - return client.Bot.Rest.Post(client,$"channels/{Id}/messages/{messageId}/crosspost", null); - } + Embeds = embeds + }; + + return Create(client, channelId, createMessage); + } - /// - /// Crosspost a message in a News Channel to following channels. - /// This endpoint requires the 'SEND_MESSAGES' permission, if the current user sent the message, or additionally the 'MANAGE_MESSAGES' permission, for all other messages, to be present for the current user. - /// See Crosspost Message - /// - /// Client to use - /// Message to cross post - public IPromise CrossPostMessage(DiscordClient client, DiscordMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - return CrossPostMessage(client, message.Id); - } + /// + /// Send a message in the channel with the given ID using a global message template + /// + /// Client to use + /// Channel ID to send the message in + /// Plugin for the template + /// Template Name + /// Message to use (optional) + /// Placeholders to apply (optional) + public static IPromise CreateGlobalTemplateMessage(DiscordClient client, Snowflake channelId, Plugin plugin, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) + { + MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(plugin, templateName).ToMessage(placeholders, message); + return Create(client, channelId, template); + } + + /// + /// Send a message in the channel with the given ID using a localized message template + /// + /// Client to use + /// Channel ID to send the message in + /// Plugin for the template + /// Template Name + /// Oxide language to use + /// Message to use (optional) + /// Placeholders to apply (optional) + public static IPromise CreateTemplateMessage(DiscordClient client, Snowflake channelId, Plugin plugin, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, MessageCreate message = null, PlaceholderData placeholders = null) + { + MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(plugin, templateName, language).ToMessage(placeholders, message); + return Create(client, channelId, template); + } - /// - /// Create a reaction for the message. - /// This endpoint requires the 'READ_MESSAGE_HISTORY' permission to be present on the current user. - /// Additionally, if nobody else has reacted to the message using this emoji, this endpoint requires the 'ADD_REACTIONS' permission to be present on the current user. - /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> - /// See Create Reaction - /// - /// Client to use - /// Emoji to react with. - public IPromise CreateReaction(DiscordClient client, DiscordEmoji emoji) + /// + /// Returns a specific message in the channel. + /// If operating on a guild channel, this endpoint requires the 'READ_MESSAGE_HISTORY' permission to be present on the current user. + /// See Get Channel Messages + /// + /// Client to use + /// Channel ID where the message is + /// Message ID of the message + public static IPromise GetMessage(DiscordClient client, Snowflake channelId, Snowflake messageId) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + InvalidSnowflakeException.ThrowIfInvalid(messageId); + return client.Bot.Rest.Get(client,$"channels/{channelId}/messages/{messageId}"); + } + + /// + /// Replies to a previously sent message + /// See Create Message + /// + /// Client to use + /// Message to send + public IPromise Reply(DiscordClient client, MessageCreate message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + if (message.MessageReference == null) { - if (emoji == null) throw new ArgumentNullException(nameof(emoji)); - return CreateReaction(client, emoji.ToDataString()); + message.MessageReference = new MessageReference {MessageId = Id, GuildId = GuildId}; } + + return Create(client, ChannelId, message); + } - /// - /// Create a reaction for the message. - /// This endpoint requires the 'READ_MESSAGE_HISTORY' permission to be present on the current user. - /// Additionally, if nobody else has reacted to the message using this emoji, this endpoint requires the 'ADD_REACTIONS' permission to be present on the current user. - /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> - /// See Create Reaction - /// - /// Client to use - /// Emoji to react with. - public IPromise CreateReaction(DiscordClient client, string emoji) + /// + /// Replies to a previously sent message + /// See Create Message + /// + /// Client to use + /// Builder for the message + public IPromise Reply(DiscordClient client, DiscordMessageBuilder builder) + { + return Reply(client, builder.Build()); + } + + /// + /// Replies to a previously sent message + /// See Create Message + /// + /// Client to use + /// Message text to send + public IPromise Reply(DiscordClient client, string message) + { + MessageCreate newMessage = new() { - InvalidSnowflakeException.ThrowIfInvalid(Id, nameof(Id)); - InvalidSnowflakeException.ThrowIfInvalid(ChannelId, nameof(ChannelId)); - InvalidEmojiException.ThrowIfInvalidEmojiString(emoji); - return client.Bot.Rest.Put(client,$"channels/{ChannelId}/messages/{Id}/reactions/{emoji}/@me", null); - } + Content = message + }; - /// - /// Delete a reaction the current user has made for the message - /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> - /// See Delete Own Reaction - /// - /// Client to use - /// Emoji to delete - public IPromise DeleteOwnReaction(DiscordClient client, DiscordEmoji emoji) - { - if (emoji == null) throw new ArgumentNullException(nameof(emoji)); - return DeleteOwnReaction(client, emoji.ToDataString()); - } + return Reply(client, newMessage); + } + + /// + /// Replies to a previously sent message + /// See Create Message + /// + /// Client to use + /// Embed to send + public IPromise Reply(DiscordClient client, DiscordEmbed embed) + { + return Reply(client, [embed]); + } - /// - /// Delete a reaction the current user has made for the message - /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> - /// See Delete Own Reaction - /// - /// Client to use - /// Emoji to delete - public IPromise DeleteOwnReaction(DiscordClient client, string emoji) + /// + /// Replies to a previously sent message + /// See Create Message + /// + /// Client to use + /// Embeds to send + public IPromise Reply(DiscordClient client, List embeds) + { + MessageCreate newMessage = new() { - InvalidSnowflakeException.ThrowIfInvalid(Id, nameof(Id)); - InvalidSnowflakeException.ThrowIfInvalid(ChannelId, nameof(ChannelId)); - InvalidEmojiException.ThrowIfInvalidEmojiString(emoji); - return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/messages/{Id}/reactions/{emoji}/@me"); - } + Embeds = embeds, + }; - /// - /// Deletes another user's reaction. - /// This endpoint requires the 'MANAGE_MESSAGES' permission to be present on the current user. - /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> - /// See Delete User Reaction - /// - /// Client to use - /// Emoji to delete - /// User ID who add the reaction - public IPromise DeleteUserReaction(DiscordClient client, DiscordEmoji emoji, Snowflake userId) - { - return DeleteUserReaction(client, emoji.ToDataString(), userId); - } + return Reply(client, newMessage); + } - /// - /// Deletes another user's reaction. - /// This endpoint requires the 'MANAGE_MESSAGES' permission to be present on the current user. - /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> - /// See Delete User Reaction - /// - /// Client to use - /// Emoji to delete - /// User ID who add the reaction - public IPromise DeleteUserReaction(DiscordClient client, string emoji, Snowflake userId) - { - InvalidSnowflakeException.ThrowIfInvalid(Id, nameof(Id)); - InvalidSnowflakeException.ThrowIfInvalid(ChannelId, nameof(ChannelId)); - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - InvalidEmojiException.ThrowIfInvalidEmojiString(emoji); - return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/messages/{Id}/reactions/{emoji}/{userId}"); - } + /// + /// Reply to a message using a global message template + /// + /// Client to use + /// Template Name + /// Message to use (optional) + /// Placeholders to apply (optional) + public IPromise ReplyWithGlobalTemplate(DiscordClient client, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) + { + MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(client.Plugin, templateName).ToMessage(placeholders, message); + return Reply(client, template); + } - /// - /// Get a list of users that reacted with this emoji - /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> - /// See Get Reactions - /// - /// Client to use - /// Emoji to get the list for - public IPromise> GetReactions(DiscordClient client, DiscordEmoji emoji) - { - if (emoji == null) throw new ArgumentNullException(nameof(emoji)); - return GetReactions(client, emoji.ToDataString()); - } + /// + /// Reply to a message using a global message template + /// + /// Client to use + /// Template Name + /// Oxide language to use + /// Message to use (optional) + /// Placeholders to apply (optional) + public IPromise ReplyWithTemplate(DiscordClient client, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, MessageCreate message = null, PlaceholderData placeholders = null) + { + MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, language).ToMessage(placeholders, message); + return Reply(client, template); + } - /// - /// Get a list of users that reacted with this emoji - /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> - /// See Get Reactions - /// - /// Client to use - /// Emoji to get the list for - public IPromise> GetReactions(DiscordClient client, string emoji) - { - InvalidEmojiException.ThrowIfInvalidEmojiString(emoji); - return client.Bot.Rest.Get>(client,$"channels/{ChannelId}/messages/{Id}/reactions/{emoji}"); - } + /// + /// Crosspost a message in a News Channel to following channels. + /// This endpoint requires the 'SEND_MESSAGES' permission, if the current user sent the message, or additionally the 'MANAGE_MESSAGES' permission, for all other messages, to be present for the current user. + /// See Crosspost Message + /// + /// Client to use + /// Message ID to cross post + public IPromise CrossPostMessage(DiscordClient client, Snowflake messageId) + { + InvalidSnowflakeException.ThrowIfInvalid(Id); + InvalidSnowflakeException.ThrowIfInvalid(messageId); + return client.Bot.Rest.Post(client,$"channels/{Id}/messages/{messageId}/crosspost", null); + } + + /// + /// Crosspost a message in a News Channel to following channels. + /// This endpoint requires the 'SEND_MESSAGES' permission, if the current user sent the message, or additionally the 'MANAGE_MESSAGES' permission, for all other messages, to be present for the current user. + /// See Crosspost Message + /// + /// Client to use + /// Message to cross post + public IPromise CrossPostMessage(DiscordClient client, DiscordMessage message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + return CrossPostMessage(client, message.Id); + } - /// - /// Deletes all reactions on a message. - /// This endpoint requires the 'MANAGE_MESSAGES' permission to be present on the current user. - /// - /// Client to use - public IPromise DeleteAllReactions(DiscordClient client) - { - InvalidSnowflakeException.ThrowIfInvalid(Id, nameof(Id)); - InvalidSnowflakeException.ThrowIfInvalid(ChannelId, nameof(ChannelId)); - return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/messages/{Id}/reactions"); - } + /// + /// Create a reaction for the message. + /// This endpoint requires the 'READ_MESSAGE_HISTORY' permission to be present on the current user. + /// Additionally, if nobody else has reacted to the message using this emoji, this endpoint requires the 'ADD_REACTIONS' permission to be present on the current user. + /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> + /// See Create Reaction + /// + /// Client to use + /// Emoji to react with. + public IPromise CreateReaction(DiscordClient client, DiscordEmoji emoji) + { + if (emoji == null) throw new ArgumentNullException(nameof(emoji)); + return CreateReaction(client, emoji.ToDataString()); + } - /// - /// Deletes all the reactions for a given emoji on a message. - /// This endpoint requires the MANAGE_MESSAGES permission to be present on the current user. - /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> - /// See Delete All Reactions for Emoji - /// - /// Client to use - /// Emoji to delete all reactions for - public IPromise DeleteAllReactionsForEmoji(DiscordClient client, DiscordEmoji emoji) - { - if (emoji == null) throw new ArgumentNullException(nameof(emoji)); - return DeleteAllReactionsForEmoji(client, emoji.ToDataString()); - } + /// + /// Create a reaction for the message. + /// This endpoint requires the 'READ_MESSAGE_HISTORY' permission to be present on the current user. + /// Additionally, if nobody else has reacted to the message using this emoji, this endpoint requires the 'ADD_REACTIONS' permission to be present on the current user. + /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> + /// See Create Reaction + /// + /// Client to use + /// Emoji to react with. + public IPromise CreateReaction(DiscordClient client, string emoji) + { + InvalidSnowflakeException.ThrowIfInvalid(Id); + InvalidSnowflakeException.ThrowIfInvalid(ChannelId); + InvalidEmojiException.ThrowIfInvalidEmojiString(emoji); + return client.Bot.Rest.Put(client,$"channels/{ChannelId}/messages/{Id}/reactions/{emoji}/@me", null); + } + + /// + /// Delete a reaction the current user has made for the message + /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> + /// See Delete Own Reaction + /// + /// Client to use + /// Emoji to delete + public IPromise DeleteOwnReaction(DiscordClient client, DiscordEmoji emoji) + { + if (emoji == null) throw new ArgumentNullException(nameof(emoji)); + return DeleteOwnReaction(client, emoji.ToDataString()); + } - /// - /// Deletes all the reactions for a given emoji on a message. - /// This endpoint requires the MANAGE_MESSAGES permission to be present on the current user. - /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> - /// See Delete All Reactions for Emoji - /// - /// Client to use - /// Emoji to delete all reactions for - public IPromise DeleteAllReactionsForEmoji(DiscordClient client, string emoji) - { - InvalidEmojiException.ThrowIfInvalidEmojiString(emoji); - return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/messages/{Id}/reactions/{emoji}"); - } + /// + /// Delete a reaction the current user has made for the message + /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> + /// See Delete Own Reaction + /// + /// Client to use + /// Emoji to delete + public IPromise DeleteOwnReaction(DiscordClient client, string emoji) + { + InvalidSnowflakeException.ThrowIfInvalid(Id); + InvalidSnowflakeException.ThrowIfInvalid(ChannelId); + InvalidEmojiException.ThrowIfInvalidEmojiString(emoji); + return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/messages/{Id}/reactions/{emoji}/@me"); + } - /// - /// Edit a previously sent message. - /// The fields content, embed, allowed_mentions and flags can be edited by the original message author. - /// Other users can only edit flags and only if they have the MANAGE_MESSAGES permission in the corresponding channel. - /// When specifying flags, ensure to include all previously set flags/bits in addition to ones that you are modifying. - /// Only flags documented in the table below may be modified by users (unsupported flag changes are currently ignored without error). - /// See Edit Message - /// - /// Client to use - /// Update to be applied to the message - public IPromise Edit(DiscordClient client, MessageUpdate update) - { - InvalidSnowflakeException.ThrowIfInvalid(Id, nameof(Id)); - InvalidSnowflakeException.ThrowIfInvalid(ChannelId, nameof(ChannelId)); - return client.Bot.Rest.Patch(client,$"channels/{ChannelId}/messages/{Id}", update); - } + /// + /// Deletes another user's reaction. + /// This endpoint requires the 'MANAGE_MESSAGES' permission to be present on the current user. + /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> + /// See Delete User Reaction + /// + /// Client to use + /// Emoji to delete + /// User ID who add the reaction + public IPromise DeleteUserReaction(DiscordClient client, DiscordEmoji emoji, Snowflake userId) + { + return DeleteUserReaction(client, emoji.ToDataString(), userId); + } - /// - /// Edit a message using a global message template - /// - /// Client to use - /// Template Name - /// Placeholders to apply (optional) - /// Update to be applied to the message - public IPromise EditGlobalTemplateMessage(DiscordClient client, TemplateKey templateName, PlaceholderData placeholders = null, MessageUpdate update = null) - { - MessageUpdate template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(client.Plugin, templateName).ToMessage(placeholders, update); - return Edit(client, template); - } + /// + /// Deletes another user's reaction. + /// This endpoint requires the 'MANAGE_MESSAGES' permission to be present on the current user. + /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> + /// See Delete User Reaction + /// + /// Client to use + /// Emoji to delete + /// User ID who add the reaction + public IPromise DeleteUserReaction(DiscordClient client, string emoji, Snowflake userId) + { + InvalidSnowflakeException.ThrowIfInvalid(Id); + InvalidSnowflakeException.ThrowIfInvalid(ChannelId); + InvalidSnowflakeException.ThrowIfInvalid(userId); + InvalidEmojiException.ThrowIfInvalidEmojiString(emoji); + return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/messages/{Id}/reactions/{emoji}/{userId}"); + } - /// - /// Edit a message using a localized message template - /// - /// Client to use - /// Template Name - /// Oxide language to use - /// Placeholders to apply (optional) - /// Update to be applied tothe message - public IPromise EditTemplateMessage(DiscordClient client, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, PlaceholderData placeholders = null, MessageUpdate update = null) - { - MessageUpdate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, language).ToMessage(placeholders, update); - return Edit(client, template); - } + /// + /// Get a list of users that reacted with this emoji + /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> + /// See Get Reactions + /// + /// Client to use + /// Emoji to get the list for + public IPromise> GetReactions(DiscordClient client, DiscordEmoji emoji) + { + if (emoji == null) throw new ArgumentNullException(nameof(emoji)); + return GetReactions(client, emoji.ToDataString()); + } + + /// + /// Get a list of users that reacted with this emoji + /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> + /// See Get Reactions + /// + /// Client to use + /// Emoji to get the list for + public IPromise> GetReactions(DiscordClient client, string emoji) + { + InvalidEmojiException.ThrowIfInvalidEmojiString(emoji); + return client.Bot.Rest.Get>(client,$"channels/{ChannelId}/messages/{Id}/reactions/{emoji}"); + } - /// - /// Delete a message. - /// If operating on a guild channel and trying to delete a message that was not sent by the current user, this endpoint requires the MANAGE_MESSAGES permission. - /// See Delete Message - /// - /// Client to use - public IPromise Delete(DiscordClient client) - { - InvalidSnowflakeException.ThrowIfInvalid(Id, nameof(Id)); - InvalidSnowflakeException.ThrowIfInvalid(ChannelId, nameof(ChannelId)); - InvalidMessageException.ThrowIfCantBeDeleted(this); - return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/messages/{Id}"); - } + /// + /// Deletes all reactions on a message. + /// This endpoint requires the 'MANAGE_MESSAGES' permission to be present on the current user. + /// + /// Client to use + public IPromise DeleteAllReactions(DiscordClient client) + { + InvalidSnowflakeException.ThrowIfInvalid(Id); + InvalidSnowflakeException.ThrowIfInvalid(ChannelId); + return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/messages/{Id}/reactions"); + } + + /// + /// Deletes all the reactions for a given emoji on a message. + /// This endpoint requires the MANAGE_MESSAGES permission to be present on the current user. + /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> + /// See Delete All Reactions for Emoji + /// + /// Client to use + /// Emoji to delete all reactions for + public IPromise DeleteAllReactionsForEmoji(DiscordClient client, DiscordEmoji emoji) + { + if (emoji == null) throw new ArgumentNullException(nameof(emoji)); + return DeleteAllReactionsForEmoji(client, emoji.ToDataString()); + } + + /// + /// Deletes all the reactions for a given emoji on a message. + /// This endpoint requires the MANAGE_MESSAGES permission to be present on the current user. + /// Valid emoji formats are the unicode emoji character '😀' or for custom emoji format must be <emojiName:emojiId> + /// See Delete All Reactions for Emoji + /// + /// Client to use + /// Emoji to delete all reactions for + public IPromise DeleteAllReactionsForEmoji(DiscordClient client, string emoji) + { + InvalidEmojiException.ThrowIfInvalidEmojiString(emoji); + return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/messages/{Id}/reactions/{emoji}"); + } - /// - /// Pin a message in a channel. - /// Requires the MANAGE_MESSAGES permission. - /// See Add Pinned Channel Message - /// - /// Client to use - public IPromise Pin(DiscordClient client) - { - InvalidSnowflakeException.ThrowIfInvalid(Id, nameof(Id)); - InvalidSnowflakeException.ThrowIfInvalid(ChannelId, nameof(ChannelId)); - return client.Bot.Rest.Put(client,$"channels/{ChannelId}/pins/{Id}", null); - } + /// + /// Edit a previously sent message. + /// The fields content, embed, allowed_mentions and flags can be edited by the original message author. + /// Other users can only edit flags and only if they have the MANAGE_MESSAGES permission in the corresponding channel. + /// When specifying flags, ensure to include all previously set flags/bits in addition to ones that you are modifying. + /// Only flags documented in the table below may be modified by users (unsupported flag changes are currently ignored without error). + /// See Edit Message + /// + /// Client to use + /// Update to be applied to the message + public IPromise Edit(DiscordClient client, MessageUpdate update) + { + InvalidSnowflakeException.ThrowIfInvalid(Id); + InvalidSnowflakeException.ThrowIfInvalid(ChannelId); + return client.Bot.Rest.Patch(client,$"channels/{ChannelId}/messages/{Id}", update); + } - /// - /// Delete a pinned message in a channel. - /// Requires the MANAGE_MESSAGES permission. - /// See Unpin Pinned Channel Message - /// - /// Client to use - public IPromise Unpin(DiscordClient client) - { - return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/pins/{Id}"); - } + /// + /// Edit a message using a global message template + /// + /// Client to use + /// Template Name + /// Placeholders to apply (optional) + /// Update to be applied to the message + public IPromise EditGlobalTemplateMessage(DiscordClient client, TemplateKey templateName, PlaceholderData placeholders = null, MessageUpdate update = null) + { + MessageUpdate template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(client.Plugin, templateName).ToMessage(placeholders, update); + return Edit(client, template); + } + + /// + /// Edit a message using a localized message template + /// + /// Client to use + /// Template Name + /// Oxide language to use + /// Placeholders to apply (optional) + /// Update to be applied tothe message + public IPromise EditTemplateMessage(DiscordClient client, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, PlaceholderData placeholders = null, MessageUpdate update = null) + { + MessageUpdate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, language).ToMessage(placeholders, update); + return Edit(client, template); + } + + /// + /// Delete a message. + /// If operating on a guild channel and trying to delete a message that was not sent by the current user, this endpoint requires the MANAGE_MESSAGES permission. + /// See Delete Message + /// + /// Client to use + public IPromise Delete(DiscordClient client) + { + InvalidSnowflakeException.ThrowIfInvalid(Id); + InvalidSnowflakeException.ThrowIfInvalid(ChannelId); + InvalidMessageException.ThrowIfCantBeDeleted(this); + return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/messages/{Id}"); + } + + /// + /// Pin a message in a channel. + /// Requires the MANAGE_MESSAGES permission. + /// See Add Pinned Channel Message + /// + /// Client to use + public IPromise Pin(DiscordClient client) + { + InvalidSnowflakeException.ThrowIfInvalid(Id); + InvalidSnowflakeException.ThrowIfInvalid(ChannelId); + return client.Bot.Rest.Put(client,$"channels/{ChannelId}/pins/{Id}", null); + } + + /// + /// Delete a pinned message in a channel. + /// Requires the MANAGE_MESSAGES permission. + /// See Unpin Pinned Channel Message + /// + /// Client to use + public IPromise Unpin(DiscordClient client) + { + return client.Bot.Rest.Delete(client,$"channels/{ChannelId}/pins/{Id}"); + } - /// - /// Creates a new public thread this message - /// See - /// - /// Client to use - /// Data to use when creating the thread - public IPromise StartThread(DiscordClient client, ThreadCreateFromMessage create) - { - if (create == null) throw new ArgumentNullException(nameof(create)); - return client.Bot.Rest.Post(client,$"channels/{ChannelId}/messages/{Id}/threads", create); - } + /// + /// Creates a new public thread this message + /// See Start Thread + /// + /// Client to use + /// Data to use when creating the thread + public IPromise StartThread(DiscordClient client, ThreadCreateFromMessage create) + { + if (create == null) throw new ArgumentNullException(nameof(create)); + return client.Bot.Rest.Post(client,$"channels/{ChannelId}/messages/{Id}/threads", create); + } + + /// + /// Get a list of users that voted for this specific answer. + /// See Get Answer Voters + /// + /// Client to use + /// Answer to get voters for + /// + public IPromise GetPollVoters(DiscordClient client, PollAnswers answer, GetPollAnswerVoters filter = null) + { + return client.Bot.Rest.Get(client, $"channels/{ChannelId}/polls/{Id}/answers/{answer.AnswerId}{filter?.ToQueryString()}"); + } + + /// + /// Immediately ends the poll. + /// You cannot end polls from other users. + /// See End Poll + /// + /// Client to use + public IPromise EndPoll(DiscordClient client) + { + return client.Bot.Rest.Post(client, $"channels/{ChannelId}/polls/{Id}/expire", null); } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Embeds/DiscordEmbed.cs b/Oxide.Ext.Discord/Entities/Messages/Embeds/DiscordEmbed.cs index 232daac79..c1b9553e8 100644 --- a/Oxide.Ext.Discord/Entities/Messages/Embeds/DiscordEmbed.cs +++ b/Oxide.Ext.Discord/Entities/Messages/Embeds/DiscordEmbed.cs @@ -2,98 +2,97 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Embed Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordEmbed { /// - /// Represents Embed Structure + /// Title of embed /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordEmbed - { - /// - /// Title of embed - /// - [JsonProperty("title")] - public string Title { get; set; } + [JsonProperty("title")] + public string Title { get; set; } - /// - /// Type of embed (always "rich" for webhook embeds) - /// - [Obsolete("Embed types should be considered deprecated and might be removed in a future API version")] - [JsonProperty("type")] - public string Type { get; set; } + /// + /// Type of embed (always "rich" for webhook embeds) + /// + [Obsolete("Embed types should be considered deprecated and might be removed in a future API version")] + [JsonProperty("type")] + public string Type { get; set; } - /// - /// Description of embed - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of embed + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Url of embed - /// - [JsonProperty("url")] - public string Url { get; set; } + /// + /// Url of embed + /// + [JsonProperty("url")] + public string Url { get; set; } - /// - /// Timestamp of embed content - /// - [JsonProperty("timestamp")] - public DateTime? Timestamp { get; set; } + /// + /// Timestamp of embed content + /// + [JsonProperty("timestamp")] + public DateTime? Timestamp { get; set; } - /// - /// Color code of the embed - /// - [JsonProperty("color")] - public DiscordColor? Color { get; set; } + /// + /// Color code of the embed + /// + [JsonProperty("color")] + public DiscordColor? Color { get; set; } - /// - /// Footer information - /// - /// - [JsonProperty("footer")] - public EmbedFooter Footer { get; set; } + /// + /// Footer information + /// + /// + [JsonProperty("footer")] + public EmbedFooter Footer { get; set; } - /// - /// Image information - /// - /// - [JsonProperty("image")] - public EmbedImage Image { get; set; } + /// + /// Image information + /// + /// + [JsonProperty("image")] + public EmbedImage Image { get; set; } - /// - /// Thumbnail information - /// - /// - [JsonProperty("thumbnail")] - public EmbedThumbnail Thumbnail { get; set; } + /// + /// Thumbnail information + /// + /// + [JsonProperty("thumbnail")] + public EmbedThumbnail Thumbnail { get; set; } - /// - /// Video information - /// - /// - [JsonProperty("video")] - public EmbedVideo Video { get; set; } + /// + /// Video information + /// + /// + [JsonProperty("video")] + public EmbedVideo Video { get; set; } - /// - /// Provider information - /// - /// - [JsonProperty("provider")] - public EmbedProvider Provider { get; set; } + /// + /// Provider information + /// + /// + [JsonProperty("provider")] + public EmbedProvider Provider { get; set; } - /// - /// Author information - /// - /// - [JsonProperty("author")] - public EmbedAuthor Author { get; set; } + /// + /// Author information + /// + /// + [JsonProperty("author")] + public EmbedAuthor Author { get; set; } - /// - /// Fields information - /// - /// - [JsonProperty("fields")] - public List Fields { get; set; } - } + /// + /// Fields information + /// + /// + [JsonProperty("fields")] + public List Fields { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedAuthor.cs b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedAuthor.cs index a02c9a0c5..8a2125366 100644 --- a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedAuthor.cs +++ b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedAuthor.cs @@ -1,56 +1,55 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Embed Author Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class EmbedAuthor { /// - /// Represents Embed Author Structure + /// Name of author /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class EmbedAuthor - { - /// - /// Name of author - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Url of author - /// * Only supports http(s) - /// - [JsonProperty("url")] - public string Url { get; set; } + /// + /// Url of author + /// * Only supports http(s) + /// + [JsonProperty("url")] + public string Url { get; set; } - /// - /// Url of author icon (only supports http(s) and attachments) - /// - [JsonProperty("icon_url")] - public string IconUrl { get; set; } + /// + /// Url of author icon (only supports http(s) and attachments) + /// + [JsonProperty("icon_url")] + public string IconUrl { get; set; } - /// - /// A proxied url of author icon - /// - [JsonProperty("proxy_icon_url")] - public string ProxyIconUrl { get; set; } + /// + /// A proxied url of author icon + /// + [JsonProperty("proxy_icon_url")] + public string ProxyIconUrl { get; set; } - /// - /// Embed Author Constructor - /// - public EmbedAuthor() { } + /// + /// Embed Author Constructor + /// + public EmbedAuthor() { } - /// - /// Embed Author Constructor - /// - /// - /// - /// - /// - public EmbedAuthor(string name, string url = null, string iconUrl = null, string proxyIconUrl = null) - { - Name = name; - Url = url; - IconUrl = iconUrl; - ProxyIconUrl = proxyIconUrl; - } + /// + /// Embed Author Constructor + /// + /// + /// + /// + /// + public EmbedAuthor(string name, string url = null, string iconUrl = null, string proxyIconUrl = null) + { + Name = name; + Url = url; + IconUrl = iconUrl; + ProxyIconUrl = proxyIconUrl; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedField.cs b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedField.cs index c11d21618..ebbe060f4 100644 --- a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedField.cs +++ b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedField.cs @@ -1,52 +1,51 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Embed Field Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class EmbedField { /// - /// Represents Embed Field Structure + /// Represents a blank character to be used in embeds for empty text /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class EmbedField - { - /// - /// Represents a blank character to be used in embeds for empty text - /// - public const string Blank = "\u200b"; + public const string Blank = "\u200b"; - /// - /// Name of the field - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the field + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Value of the field - /// - [JsonProperty("value")] - public string Value { get; set; } + /// + /// Value of the field + /// + [JsonProperty("value")] + public string Value { get; set; } - /// - /// Whether or not this field should display inline - /// - [JsonProperty("inline")] - public bool Inline { get; set; } + /// + /// Whether or not this field should display inline + /// + [JsonProperty("inline")] + public bool Inline { get; set; } - /// - /// Embed Field constructor - /// - public EmbedField() { } + /// + /// Embed Field constructor + /// + public EmbedField() { } - /// - /// Embed Field constructor - /// - /// Field Name - /// Field Value - /// Should field be inlined - public EmbedField(string name, string value, bool inline) - { - Name = !string.IsNullOrEmpty(name) ? name : Blank; - Value = !string.IsNullOrEmpty(value) ? value : Blank; - Inline = inline; - } + /// + /// Embed Field constructor + /// + /// Field Name + /// Field Value + /// Should field be inlined + public EmbedField(string name, string value, bool inline) + { + Name = !string.IsNullOrEmpty(name) ? name : Blank; + Value = !string.IsNullOrEmpty(value) ? value : Blank; + Inline = inline; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedFooter.cs b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedFooter.cs index 10037ef48..7d4d17d76 100644 --- a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedFooter.cs +++ b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedFooter.cs @@ -1,48 +1,47 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Embed Footer Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class EmbedFooter { /// - /// Represents Embed Footer Structure + /// Footer text /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class EmbedFooter - { - /// - /// Footer text - /// - [JsonProperty("text")] - public string Text { get; set; } + [JsonProperty("text")] + public string Text { get; set; } - /// - /// Url of footer icon (only supports http(s) and attachments) - /// - [JsonProperty("icon_url")] - public string IconUrl { get; set; } + /// + /// Url of footer icon (only supports http(s) and attachments) + /// + [JsonProperty("icon_url")] + public string IconUrl { get; set; } - /// - /// A proxied url of footer icon - /// - [JsonProperty("proxy_icon_url")] - public string ProxyIconUrl { get; set; } + /// + /// A proxied url of footer icon + /// + [JsonProperty("proxy_icon_url")] + public string ProxyIconUrl { get; set; } - /// - /// Embed Footer Constructor - /// - [JsonConstructor] - public EmbedFooter() {} + /// + /// Embed Footer Constructor + /// + [JsonConstructor] + public EmbedFooter() {} - /// - /// Embed Footer Constructor - /// - /// - /// - /// - public EmbedFooter(string text, string iconUrl = null, string proxyIconUrl = null) - { - Text = text; - IconUrl = iconUrl; - ProxyIconUrl = proxyIconUrl; - } + /// + /// Embed Footer Constructor + /// + /// + /// + /// + public EmbedFooter(string text, string iconUrl = null, string proxyIconUrl = null) + { + Text = text; + IconUrl = iconUrl; + ProxyIconUrl = proxyIconUrl; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedImage.cs b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedImage.cs index 8385e024c..45d143dea 100644 --- a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedImage.cs +++ b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedImage.cs @@ -1,58 +1,57 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Embed Image Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class EmbedImage { /// - /// Represents Embed Image Structure + /// Source url of image (only supports http(s) and attachments) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class EmbedImage - { - /// - /// Source url of image (only supports http(s) and attachments) - /// - [JsonProperty("url")] - public string Url { get; set; } + [JsonProperty("url")] + public string Url { get; set; } - /// - /// A proxied url of the image - /// - [JsonProperty("proxy_url")] - public string ProxyUrl { get; set; } + /// + /// A proxied url of the image + /// + [JsonProperty("proxy_url")] + public string ProxyUrl { get; set; } - /// - /// Height of image - /// - [JsonProperty("height")] - public int? Height { get; set; } + /// + /// Height of image + /// + [JsonProperty("height")] + public int? Height { get; set; } - /// - /// Width of image - /// - [JsonProperty("width")] - public int? Width { get; set; } + /// + /// Width of image + /// + [JsonProperty("width")] + public int? Width { get; set; } - /// - /// Embed Image Constructor - /// - public EmbedImage() - { + /// + /// Embed Image Constructor + /// + public EmbedImage() + { - } + } - /// - /// Embed Image Constructor - /// - /// - /// - /// - /// - public EmbedImage(string url, int? height = null, int? width = null, string proxyUrl = null) - { - Url = url; - ProxyUrl = proxyUrl; - Height = height; - Width = width; - } + /// + /// Embed Image Constructor + /// + /// + /// + /// + /// + public EmbedImage(string url, int? height = null, int? width = null, string proxyUrl = null) + { + Url = url; + ProxyUrl = proxyUrl; + Height = height; + Width = width; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedProvider.cs b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedProvider.cs index 9d59d4084..546bffb2d 100644 --- a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedProvider.cs +++ b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedProvider.cs @@ -1,42 +1,41 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Embed Provider Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class EmbedProvider { /// - /// Represents Embed Provider Structure + /// Name of provider /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class EmbedProvider - { - /// - /// Name of provider - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Url of provider - /// - [JsonProperty("url")] - public string Url { get; set; } + /// + /// Url of provider + /// + [JsonProperty("url")] + public string Url { get; set; } - /// - /// Embed Provider Constructor - /// - public EmbedProvider() - { + /// + /// Embed Provider Constructor + /// + public EmbedProvider() + { - } + } - /// - /// Embed Provider Constructor - /// - /// - /// - public EmbedProvider(string name, string url) - { - Name = name; - Url = url; - } + /// + /// Embed Provider Constructor + /// + /// + /// + public EmbedProvider(string name, string url) + { + Name = name; + Url = url; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedThumbnail.cs b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedThumbnail.cs index 1413a6fe8..8ad9c7be4 100644 --- a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedThumbnail.cs +++ b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedThumbnail.cs @@ -1,58 +1,57 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Embed Thumbnail Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class EmbedThumbnail { /// - /// Represents Embed Thumbnail Structure + /// Source url of thumbnail (only supports http(s) and attachments) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class EmbedThumbnail - { - /// - /// Source url of thumbnail (only supports http(s) and attachments) - /// - [JsonProperty("url")] - public string Url { get; set; } + [JsonProperty("url")] + public string Url { get; set; } - /// - /// A proxied url of the thumbnail - /// - [JsonProperty("proxy_url")] - public string ProxyUrl { get; set; } + /// + /// A proxied url of the thumbnail + /// + [JsonProperty("proxy_url")] + public string ProxyUrl { get; set; } - /// - /// Height of thumbnail - /// - [JsonProperty("height")] - public int? Height { get; set; } + /// + /// Height of thumbnail + /// + [JsonProperty("height")] + public int? Height { get; set; } - /// - /// Width of thumbnail - /// - [JsonProperty("width")] - public int? Width { get; set; } + /// + /// Width of thumbnail + /// + [JsonProperty("width")] + public int? Width { get; set; } - /// - /// Embed Thumbnail constructor - /// - public EmbedThumbnail() - { + /// + /// Embed Thumbnail constructor + /// + public EmbedThumbnail() + { - } + } - /// - /// Embed Thumbnail constructor - /// - /// - /// - /// - /// - public EmbedThumbnail(string url, int? height = null, int? width = null, string proxyUrl = null) - { - Url = url; - ProxyUrl = proxyUrl; - Height = height; - Width = width; - } + /// + /// Embed Thumbnail constructor + /// + /// + /// + /// + /// + public EmbedThumbnail(string url, int? height = null, int? width = null, string proxyUrl = null) + { + Url = url; + ProxyUrl = proxyUrl; + Height = height; + Width = width; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedVideo.cs b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedVideo.cs index 0d8d340e4..70754da8d 100644 --- a/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedVideo.cs +++ b/Oxide.Ext.Discord/Entities/Messages/Embeds/EmbedVideo.cs @@ -1,58 +1,57 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Embed Video Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class EmbedVideo { /// - /// Represents Embed Video Structure + /// Source url of video /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class EmbedVideo - { - /// - /// Source url of video - /// - [JsonProperty("url")] - public string Url { get; set; } + [JsonProperty("url")] + public string Url { get; set; } - /// - /// Source url of video - /// - [JsonProperty("proxy_url")] - public string ProxyUrl { get; set; } + /// + /// Source url of video + /// + [JsonProperty("proxy_url")] + public string ProxyUrl { get; set; } - /// - /// Height of video - /// - [JsonProperty("height")] - public int? Height { get; set; } + /// + /// Height of video + /// + [JsonProperty("height")] + public int? Height { get; set; } - /// - /// Width of video - /// - [JsonProperty("width")] - public int? Width { get; set; } + /// + /// Width of video + /// + [JsonProperty("width")] + public int? Width { get; set; } - /// - /// Embed Video Constructor - /// - public EmbedVideo() - { + /// + /// Embed Video Constructor + /// + public EmbedVideo() + { - } + } - /// - /// Embed Video Constructor - /// - /// - /// - /// - /// - public EmbedVideo(string url, int? height, int? width, string proxyUrl) - { - Url = url; - ProxyUrl = proxyUrl; - Height = height; - Width = width; - } + /// + /// Embed Video Constructor + /// + /// + /// + /// + /// + public EmbedVideo(string url, int? height, int? width, string proxyUrl) + { + Url = url; + ProxyUrl = proxyUrl; + Height = height; + Width = width; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageActivity.cs b/Oxide.Ext.Discord/Entities/Messages/MessageActivity.cs index b67d7ad4c..85e1d3e09 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageActivity.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageActivity.cs @@ -1,24 +1,23 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Activity Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageActivity { /// - /// Represents a Message Activity Structure + /// Type of message activity + /// /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageActivity - { - /// - /// Type of message activity - /// - /// - [JsonProperty("type")] - public MessageActivityType Type { get; set; } + [JsonProperty("type")] + public MessageActivityType Type { get; set; } - /// - /// Party ID from a Rich Presence event - /// - [JsonProperty("party_id")] - public string PartyId { get; set; } - } + /// + /// Party ID from a Rich Presence event + /// + [JsonProperty("party_id")] + public string PartyId { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageActivityType.cs b/Oxide.Ext.Discord/Entities/Messages/MessageActivityType.cs index 648a5e0b3..180bc89a2 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageActivityType.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageActivityType.cs @@ -1,34 +1,33 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Activity Types +/// +public enum MessageActivityType : byte { /// - /// Represents a Message Activity Types + /// Message Activity Join /// - public enum MessageActivityType : byte - { - /// - /// Message Activity Join - /// - [DiscordEnum("JOIN")] - Join = 1, + [DiscordEnum("JOIN")] + Join = 1, - /// - /// Message Activity Spectate - /// - [DiscordEnum("SPECTATE")] - Spectate = 2, + /// + /// Message Activity Spectate + /// + [DiscordEnum("SPECTATE")] + Spectate = 2, - /// - /// Message Activity Listen - /// - [DiscordEnum("LISTEN")] - Listen = 3, + /// + /// Message Activity Listen + /// + [DiscordEnum("LISTEN")] + Listen = 3, - /// - /// Message Activity JoinRequest - /// - [DiscordEnum("JOIN_REQUEST")] - JoinRequest = 5, - } + /// + /// Message Activity JoinRequest + /// + [DiscordEnum("JOIN_REQUEST")] + JoinRequest = 5, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageAttachment.cs b/Oxide.Ext.Discord/Entities/Messages/MessageAttachment.cs index ca985a1a0..acd1f9885 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageAttachment.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageAttachment.cs @@ -1,90 +1,95 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a message Attachment Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageAttachment : ISnowflakeEntity { /// - /// Represents a message Attachment Structure + /// Attachment ID /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageAttachment : ISnowflakeEntity - { - /// - /// Attachment ID - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Name of file attached - /// - [JsonProperty("filename")] - public string Filename { get; set; } + /// + /// Name of file attached + /// + [JsonProperty("filename")] + public string Filename { get; set; } - /// - /// Description for the file - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Title of the file + /// + [JsonProperty("title")] + public string Title { get; set; } + + /// + /// Description for the file + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// The attachment's media type - /// - [JsonProperty("content_type")] - public string ContentType { get; set; } + /// + /// The attachment's media type + /// + [JsonProperty("content_type")] + public string ContentType { get; set; } - /// - /// Size of file in bytes - /// - [JsonProperty("size")] - public int? Size { get; set; } + /// + /// Size of file in bytes + /// + [JsonProperty("size")] + public int? Size { get; set; } - /// - /// Source url of file - /// - [JsonProperty("url")] - public string Url { get; set; } + /// + /// Source url of file + /// + [JsonProperty("url")] + public string Url { get; set; } - /// - /// A proxied url of file - /// - [JsonProperty("proxy_url")] - public string ProxyUrl { get; set; } + /// + /// A proxied url of file + /// + [JsonProperty("proxy_url")] + public string ProxyUrl { get; set; } - /// - /// Height of file (if image) - /// - [JsonProperty("height")] - public int? Height { get; set; } + /// + /// Height of file (if image) + /// + [JsonProperty("height")] + public int? Height { get; set; } - /// - /// Width of file (if image) - /// - [JsonProperty("width")] - public int? Width { get; set; } + /// + /// Width of file (if image) + /// + [JsonProperty("width")] + public int? Width { get; set; } - /// - /// Whether this attachment is ephemeral - /// - [JsonProperty("ephemeral")] - public bool? Ephemeral { get; set; } + /// + /// Whether this attachment is ephemeral + /// + [JsonProperty("ephemeral")] + public bool? Ephemeral { get; set; } - /// - /// The duration of the audio file (currently for voice messages) - /// - [JsonProperty("duration_secs")] - public float? DurationSecs { get; set; } + /// + /// The duration of the audio file (currently for voice messages) + /// + [JsonProperty("duration_secs")] + public float? DurationSecs { get; set; } - /// - /// base64 encoded bytearray representing a sampled waveform (currently for voice messages) - /// - [JsonProperty("waveform")] - public string Waveform { get; set; } + /// + /// base64 encoded bytearray representing a sampled waveform (currently for voice messages) + /// + [JsonProperty("waveform")] + public string Waveform { get; set; } - /// - /// Attachment Flags - /// - [JsonProperty("flags")] - public AttachmentFlags? Flags { get; set; } - } -} + /// + /// Attachment Flags + /// + [JsonProperty("flags")] + public AttachmentFlags? Flags { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageCall.cs b/Oxide.Ext.Discord/Entities/Messages/MessageCall.cs new file mode 100644 index 000000000..71ec7ebb7 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/MessageCall.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Call Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageCall +{ + /// + /// Array of user ids that participated in the call + /// + [JsonProperty("participants")] + public List Participants { get; set; } + + /// + /// Time when call ended + /// + [JsonProperty("ended_timestamp")] + public DateTimeOffset? EndedTimestamp { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageCreate.cs b/Oxide.Ext.Discord/Entities/Messages/MessageCreate.cs index 1cc11e25b..7aac8d078 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageCreate.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageCreate.cs @@ -1,30 +1,29 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Create Structure to be created in discord +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageCreate : BaseMessageCreate { /// - /// Represents a Message Create Structure to be created in discord + /// Can be used to verify a message was sent (up to 25 characters). + /// Value will appear in the Message Create event. /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageCreate : BaseMessageCreate - { - /// - /// Can be used to verify a message was sent (up to 25 characters). - /// Value will appear in the Message Create event. - /// - [JsonProperty("nonce")] - public string Nonce { get; set; } + [JsonProperty("nonce")] + public string Nonce { get; set; } - /// - /// If true and nonce is present, it will be checked for uniqueness in the past few minutes. If another message was created by the same author with the same nonce, that message will be returned and no new message will be created. - /// - [JsonProperty("enforce_nonce")] - public bool EnforceNonce { get; set; } + /// + /// If true and nonce is present, it will be checked for uniqueness in the past few minutes. If another message was created by the same author with the same nonce, that message will be returned and no new message will be created. + /// + [JsonProperty("enforce_nonce")] + public bool EnforceNonce { get; set; } - /// - /// Include to make your message a reply - /// - [JsonProperty("message_reference")] - public MessageReference MessageReference { get; set; } - } + /// + /// Include to make your message a reply or a forward + /// + [JsonProperty("message_reference")] + public MessageReference MessageReference { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageFileAttachment.cs b/Oxide.Ext.Discord/Entities/Messages/MessageFileAttachment.cs index dca153f36..b9967b7f4 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageFileAttachment.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageFileAttachment.cs @@ -1,36 +1,35 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a file attachment for a discord message +/// +public class MessageFileAttachment { /// - /// Represents a file attachment for a discord message + /// Name of the file attachment /// - public class MessageFileAttachment - { - /// - /// Name of the file attachment - /// - public string FileName { get; set; } + public string FileName { get; set; } - /// - /// Data for the file attachment - /// - public byte[] Data { get; set; } + /// + /// Data for the file attachment + /// + public byte[] Data { get; set; } - /// - /// Web Content Type for the file attachment - /// - public string ContentType { get; set; } + /// + /// Web Content Type for the file attachment + /// + public string ContentType { get; set; } - /// - /// Constructor - /// - /// File Attachment Name - /// Data for the file - /// Web Content Type for the file attachment - public MessageFileAttachment(string fileName, byte[] data, string contentType) - { - FileName = fileName; - Data = data; - ContentType = contentType; - } + /// + /// Constructor + /// + /// File Attachment Name + /// Data for the file + /// Web Content Type for the file attachment + public MessageFileAttachment(string fileName, byte[] data, string contentType) + { + FileName = fileName; + Data = data; + ContentType = contentType; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageFlags.cs b/Oxide.Ext.Discord/Entities/Messages/MessageFlags.cs index eba7d9328..e3d6b2c55 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageFlags.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageFlags.cs @@ -1,83 +1,82 @@ using System; using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Flags for a message +/// +[Flags] +public enum MessageFlags { /// - /// Represents Message Flags for a message + /// This message has no flags /// - [Flags] - public enum MessageFlags - { - /// - /// This message has no flags - /// - None = 0, + None = 0, - /// - /// This message has been published to subscribed channels (via Channel Following) - /// - [DiscordEnum("CROSSPOSTED")] - CrossPosted = 1 << 0, + /// + /// This message has been published to subscribed channels (via Channel Following) + /// + [DiscordEnum("CROSSPOSTED")] + CrossPosted = 1 << 0, - /// - /// This message originated from a message in another channel (via Channel Following) - /// - [DiscordEnum("IS_CROSSPOST")] - IsCrossPost = 1 << 1, + /// + /// This message originated from a message in another channel (via Channel Following) + /// + [DiscordEnum("IS_CROSSPOST")] + IsCrossPost = 1 << 1, - /// - /// Do not include any embeds when serializing this message - /// - [DiscordEnum("SUPPRESS_EMBEDS")] - SuppressEmbeds = 1 << 2, + /// + /// Do not include any embeds when serializing this message + /// + [DiscordEnum("SUPPRESS_EMBEDS")] + SuppressEmbeds = 1 << 2, - /// - /// The source message for this crosspost has been deleted (via Channel Following) - /// - [DiscordEnum("SOURCE_MESSAGE_DELETED")] - SourceMessageDeleted = 1 << 3, + /// + /// The source message for this crosspost has been deleted (via Channel Following) + /// + [DiscordEnum("SOURCE_MESSAGE_DELETED")] + SourceMessageDeleted = 1 << 3, - /// - /// This message came from the urgent message system - /// - [DiscordEnum("URGENT")] - Urgent = 1 << 4, + /// + /// This message came from the urgent message system + /// + [DiscordEnum("URGENT")] + Urgent = 1 << 4, - /// - /// This message has an associated thread, with the same id as the message - /// - [DiscordEnum("HAS_THREAD")] - HasThread = 1 << 5, + /// + /// This message has an associated thread, with the same id as the message + /// + [DiscordEnum("HAS_THREAD")] + HasThread = 1 << 5, - /// - /// This message is only visible to the user who invoked the Interaction - /// - [DiscordEnum("EPHEMERAL")] - Ephemeral = 1 << 6, + /// + /// This message is only visible to the user who invoked the Interaction + /// + [DiscordEnum("EPHEMERAL")] + Ephemeral = 1 << 6, - /// - /// This message is an Interaction Response and the bot is "thinking" - /// - [DiscordEnum("LOADING")] - Loading = 1 << 7, + /// + /// This message is an Interaction Response and the bot is "thinking" + /// + [DiscordEnum("LOADING")] + Loading = 1 << 7, - /// - /// This message failed to mention some roles and add their members to the thread - /// - [DiscordEnum("FAILED_TO_MENTION_SOME_ROLES_IN_THREAD")] - FailedToMentionSomeRolesInThread = 1 << 8, + /// + /// This message failed to mention some roles and add their members to the thread + /// + [DiscordEnum("FAILED_TO_MENTION_SOME_ROLES_IN_THREAD")] + FailedToMentionSomeRolesInThread = 1 << 8, - /// - /// This message will not trigger push and desktop notifications - /// - [DiscordEnum("SUPPRESS_NOTIFICATIONS")] - SuppressNotifications = 1 << 12, + /// + /// This message will not trigger push and desktop notifications + /// + [DiscordEnum("SUPPRESS_NOTIFICATIONS")] + SuppressNotifications = 1 << 12, - /// - /// This message is a voice message - /// - [DiscordEnum("IS_VOICE_MESSAGE")] - IsVoiceMessage = 1 << 13, - } + /// + /// This message is a voice message + /// + [DiscordEnum("IS_VOICE_MESSAGE")] + IsVoiceMessage = 1 << 13, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageInteraction.cs b/Oxide.Ext.Discord/Entities/Messages/MessageInteraction.cs index 4ac23a859..0dd2bcf02 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageInteraction.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageInteraction.cs @@ -1,41 +1,40 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Interaction Structure within Discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageInteraction { /// - /// Represents a Message Interaction Structure within Discord. + /// ID of the interaction /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageInteraction - { - /// - /// ID of the interaction - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Type of interaction - /// - [JsonProperty("type")] - public InteractionType Type { get; set; } + /// + /// Type of interaction + /// + [JsonProperty("type")] + public InteractionType Type { get; set; } - /// - /// Name of the , including subcommands and subcommand groups - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the , including subcommands and subcommand groups + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// The user who invoked the interaction - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } + /// + /// The user who invoked the interaction + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } - /// - /// Member who invoked the interaction in the guild - /// - [JsonProperty("member")] - public GuildMember Member { get; set; } - } + /// + /// Member who invoked the interaction in the guild + /// + [JsonProperty("member")] + public GuildMember Member { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageInteractionMetadata.cs b/Oxide.Ext.Discord/Entities/Messages/MessageInteractionMetadata.cs new file mode 100644 index 000000000..c99b24017 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/MessageInteractionMetadata.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json; +using Oxide.Plugins; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Interaction Metadata Structure within Discord. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageInteractionMetadata +{ + /// + /// ID of the interaction + /// + [JsonProperty("id")] + public Snowflake Id { get; set; } + + /// + /// Type of interaction + /// + [JsonProperty("type")] + public InteractionType Type { get; set; } + + /// + /// IUser who triggered the interaction + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } + + /// + /// IDs for installation context(s) related to an interaction. + /// + [JsonProperty("authorizing_integration_owners")] + public Hash AuthorizingIntegrationOwners { get; set; } + + /// + /// ID of the original response message, present only on follow-up messages + /// + [JsonProperty("original_response_message_id")] + public Snowflake? OriginalResponseMessageId { get; set; } + + /// + /// ID of the message that contained interactive component, present only on messages created from component interactions + /// + [JsonProperty("interacted_message_id")] + public Snowflake? InteractedMessageId { get; set; } + + /// + /// Metadata for the interaction that was used to open the modal, present only on modal submit interactions + /// + [JsonProperty("triggering_interaction_metadata")] + public MessageInteractionMetadata TriggeringInteractionMetadata { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageReaction.cs b/Oxide.Ext.Discord/Entities/Messages/MessageReaction.cs index 3278a890b..9ef0f09ee 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageReaction.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageReaction.cs @@ -1,49 +1,48 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Reaction Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageReaction { /// - /// Represents a Reaction Structure + /// Total number of times this emoji has been used to react (including super reacts) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageReaction - { - /// - /// Total number of times this emoji has been used to react (including super reacts) - /// - [JsonProperty("count")] - public int Count { get; set; } + [JsonProperty("count")] + public int Count { get; set; } - /// - /// Reaction Count Details - /// - [JsonProperty("count_details")] - public ReactionCountDetails CountDetails { get; set; } + /// + /// Reaction Count Details + /// + [JsonProperty("count_details")] + public ReactionCountDetails CountDetails { get; set; } - /// - /// Whether the current user reacted using this emoji - /// - [JsonProperty("me")] - public bool Me { get; set; } + /// + /// Whether the current user reacted using this emoji + /// + [JsonProperty("me")] + public bool Me { get; set; } - /// - /// Whether the current user super-reacted using this emoji - /// - [JsonProperty("me_burst")] - public bool MeBurst { get; set; } + /// + /// Whether the current user super-reacted using this emoji + /// + [JsonProperty("me_burst")] + public bool MeBurst { get; set; } - /// - /// Emoji information - /// - /// - [JsonProperty("emoji")] - public DiscordEmoji Emoji { get; set; } + /// + /// Emoji information + /// + /// + [JsonProperty("emoji")] + public DiscordEmoji Emoji { get; set; } - /// - /// HEX colors used for super reaction - /// TODO: Find out the array type - /// - [JsonProperty("burst_colors")] - public object[] BurstColors { get; set; } - } -} + /// + /// HEX colors used for super reaction + /// TODO: Find out the array type + /// + [JsonProperty("burst_colors")] + public object[] BurstColors { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageReference.cs b/Oxide.Ext.Discord/Entities/Messages/MessageReference.cs index e85b57dce..b191e9c44 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageReference.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageReference.cs @@ -1,36 +1,41 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Reference Structure for a message +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageReference { /// - /// Represents a Message Reference Structure for a message + /// Type of reference. /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageReference - { - /// - /// ID of the originating message - /// - [JsonProperty("message_id")] - public Snowflake MessageId { get; set; } + [JsonProperty("type")] + public MessageReferenceType? Type { get; set; } - /// - /// ID of the originating message's channel - /// Is optional when creating a reply, but will always be present when receiving an event/response that includes this data model. - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } + /// + /// ID of the originating message + /// + [JsonProperty("message_id")] + public Snowflake MessageId { get; set; } + + /// + /// ID of the originating message's channel + /// Is optional when creating a reply, but will always be present when receiving an event/response that includes this data model. + /// + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } - /// - /// ID of the originating message's guild - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// ID of the originating message's guild + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// When sending, whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message, default true - /// - [JsonProperty("fail_if_not_exists")] - public bool? FailIfNotExists { get; set; } - } + /// + /// When sending, whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message, default true + /// + [JsonProperty("fail_if_not_exists")] + public bool? FailIfNotExists { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageReferenceType.cs b/Oxide.Ext.Discord/Entities/Messages/MessageReferenceType.cs new file mode 100644 index 000000000..ea47cd529 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/MessageReferenceType.cs @@ -0,0 +1,17 @@ +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Reference Type +/// +public enum MessageReferenceType +{ + /// + /// A standard reference used by replies. + /// + Default = 0, + + /// + /// Reference used to point to a message at a point in time. + /// + Forward = 1 +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageSnapshot.cs b/Oxide.Ext.Discord/Entities/Messages/MessageSnapshot.cs new file mode 100644 index 000000000..eca9f1620 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/MessageSnapshot.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Snapshot +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageSnapshot +{ + /// + /// Subset of fields in the message object + /// + [JsonProperty("message")] + public DiscordMessage Message { get; set; } + + /// + /// ID of the origin message's guild + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageType.cs b/Oxide.Ext.Discord/Entities/Messages/MessageType.cs index fbc46e69e..5342585f8 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageType.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageType.cs @@ -1,202 +1,231 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Message Types +/// +public enum MessageType : byte { /// - /// Represents Message Types - /// - public enum MessageType : byte - { - /// - /// The default message type - /// - [DiscordEnum("DEFAULT")] - Default = 0, - - /// - /// The message when a recipient is added - /// - [DiscordEnum("RECIPIENT_ADD")] - RecipientAdd = 1, - - /// - /// The message when a recipient is removed - /// - [DiscordEnum("RECIPIENT_REMOVE")] - RecipientRemove = 2, - - /// - /// The message when a user is called - /// - [DiscordEnum("CALL")] - Call = 3, - - /// - /// The message when a channel name is changed - /// - [DiscordEnum("CHANNEL_NAME_CHANGE")] - ChannelNameChange = 4, - - /// - /// The message when a channel icon is changed - /// - [DiscordEnum("CHANNEL_ICON_CHANGE")] - ChannelIconChange = 5, - - /// - /// The message when another message is pinned - /// - [DiscordEnum("CHANNEL_PINNED_MESSAGE")] - ChannelPinnedMessage = 6, - - /// - /// The message when a new member joined - /// - [DiscordEnum("USER_JOIN")] - UserJoin = 7, - - /// - /// The message for when a user boosts a guild - /// - [DiscordEnum("GUILD_BOOST")] - GuildBoost = 8, - - /// - /// The message for when a guild reaches Tier 1 of Nitro boosts - /// - [DiscordEnum("GUILD_BOOST_TIER_1")] - GuildBoostTier1 = 9, - - /// - /// The message for when a guild reaches Tier 2 of Nitro boosts - /// - [DiscordEnum("GUILD_BOOST_TIER_2")] - GuildBoostTier2 = 10, - - /// - /// The message for when a guild reaches Tier 3 of Nitro boosts - /// - [DiscordEnum("GUILD_BOOST_TIER_3")] - GuildBoostTier3 = 11, - - /// - /// The message for when a news channel subscription is added to a text channel - /// - [DiscordEnum("ChannelFollowAdd")] - ChannelFollowAdd = 12, - - /// - /// The message for when a guild discovery is disqualified - /// - [DiscordEnum("GuildDiscoveryDisqualified")] - GuildDiscoveryDisqualified = 14, - - /// - /// The message for when a guild discovery is requalified - /// - [DiscordEnum("GUILD_DISCOVERY_REQUALIFIED")] - GuildDiscoveryRequalified = 15, - - /// - /// The message for grace period initial warning - /// - [DiscordEnum("GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING")] - GuildDiscoveryGracePeriodInitialWarning = 16, - - /// - /// The message for grace period final warning - /// - [DiscordEnum("GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING")] - GuildDiscoveryGracePeriodFinalWarning = 17, - - /// - /// The message created a thread - /// - [DiscordEnum("THREAD_CREATED")] - ThreadCreated = 18, - - /// - /// The message for when the message is a reply - /// - [DiscordEnum("REPLY")] - Reply = 19, - - /// - /// The message for when the message is an application command - /// - [DiscordEnum("CHAT_INPUT_COMMAND")] - ChatInputCommand = 20, - - /// - /// Starter message for a thread - /// - [DiscordEnum("THREAD_STARTER_MESSAGE")] - ThreadStarterMessage = 21, + /// The default message type + /// + [DiscordEnum("DEFAULT")] + Default = 0, + + /// + /// The message when a recipient is added + /// + [DiscordEnum("RECIPIENT_ADD")] + RecipientAdd = 1, + + /// + /// The message when a recipient is removed + /// + [DiscordEnum("RECIPIENT_REMOVE")] + RecipientRemove = 2, + + /// + /// The message when a user is called + /// + [DiscordEnum("CALL")] + Call = 3, + + /// + /// The message when a channel name is changed + /// + [DiscordEnum("CHANNEL_NAME_CHANGE")] + ChannelNameChange = 4, + + /// + /// The message when a channel icon is changed + /// + [DiscordEnum("CHANNEL_ICON_CHANGE")] + ChannelIconChange = 5, + + /// + /// The message when another message is pinned + /// + [DiscordEnum("CHANNEL_PINNED_MESSAGE")] + ChannelPinnedMessage = 6, + + /// + /// The message when a new member joined + /// + [DiscordEnum("USER_JOIN")] + UserJoin = 7, + + /// + /// The message for when a user boosts a guild + /// + [DiscordEnum("GUILD_BOOST")] + GuildBoost = 8, + + /// + /// The message for when a guild reaches Tier 1 of Nitro boosts + /// + [DiscordEnum("GUILD_BOOST_TIER_1")] + GuildBoostTier1 = 9, + + /// + /// The message for when a guild reaches Tier 2 of Nitro boosts + /// + [DiscordEnum("GUILD_BOOST_TIER_2")] + GuildBoostTier2 = 10, + + /// + /// The message for when a guild reaches Tier 3 of Nitro boosts + /// + [DiscordEnum("GUILD_BOOST_TIER_3")] + GuildBoostTier3 = 11, + + /// + /// The message for when a news channel subscription is added to a text channel + /// + [DiscordEnum("CHANNEL_FOLLOW_ADD")] + ChannelFollowAdd = 12, + + /// + /// The message for when a guild discovery is disqualified + /// + [DiscordEnum("GUILD_DISCOVERY_DISQUALIFIED")] + GuildDiscoveryDisqualified = 14, + + /// + /// The message for when a guild discovery is requalified + /// + [DiscordEnum("GUILD_DISCOVERY_REQUALIFIED")] + GuildDiscoveryRequalified = 15, + + /// + /// The message for grace period initial warning + /// + [DiscordEnum("GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING")] + GuildDiscoveryGracePeriodInitialWarning = 16, + + /// + /// The message for grace period final warning + /// + [DiscordEnum("GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING")] + GuildDiscoveryGracePeriodFinalWarning = 17, + + /// + /// The message created a thread + /// + [DiscordEnum("THREAD_CREATED")] + ThreadCreated = 18, + + /// + /// The message for when the message is a reply + /// + [DiscordEnum("REPLY")] + Reply = 19, + + /// + /// The message for when the message is an application command + /// + [DiscordEnum("CHAT_INPUT_COMMAND")] + ChatInputCommand = 20, + + /// + /// Starter message for a thread + /// + [DiscordEnum("THREAD_STARTER_MESSAGE")] + ThreadStarterMessage = 21, - /// - /// Reminder for a guild invite - /// - [DiscordEnum("GUILD_INVITE_REMINDER")] - GuildInviteReminder = 22, + /// + /// Reminder for a guild invite + /// + [DiscordEnum("GUILD_INVITE_REMINDER")] + GuildInviteReminder = 22, - /// - /// Reminder for a guild invite - /// - [DiscordEnum("CONTEXT_MENU_COMMAND")] - ContextMenuCommand = 23, + /// + /// Reminder for a guild invite + /// + [DiscordEnum("CONTEXT_MENU_COMMAND")] + ContextMenuCommand = 23, - /// - /// Message is an auto mod action - /// - [DiscordEnum("AUTO_MODERATION_ACTION")] - AutoModerationAction = 24, - - /// - /// Message is a role subscription purchase - /// - [DiscordEnum("ROLE_SUBSCRIPTION_PURCHASE")] - RoleSubscriptionPurchase = 25, - - /// - /// Message is a interaction premium upsell - /// - [DiscordEnum("INTERACTION_PREMIUM_UPSELL")] - InteractionPremiumUpsell = 26, - - /// - /// Message is a stage start - /// - [DiscordEnum("STAGE_START")] - StageStart = 27, - - /// - /// Message is a stage end - /// - [DiscordEnum("STAGE_END")] - StageEnd = 28, - - /// - /// Message is a stage speaker - /// - [DiscordEnum("STAGE_SPEAKER")] - StageSpeaker = 29, - - /// - /// Message is a stage raise hand - /// - [DiscordEnum("STAGE_RAISE_HAND")] - StageRaiseHand = 30, - - /// - /// Message is a stage topic - /// - [DiscordEnum("STAGE_TOPIC")] - StageTopic = 31, - - /// - /// Message is a Guild Application Premium Subscription - /// - [DiscordEnum("GUILD_APPLICATION_PREMIUM_SUBSCRIPTION")] - GuildApplicationPremiumSubscription = 32, - } + /// + /// Message is an auto mod action + /// + [DiscordEnum("AUTO_MODERATION_ACTION")] + AutoModerationAction = 24, + + /// + /// Message is a role subscription purchase + /// + [DiscordEnum("ROLE_SUBSCRIPTION_PURCHASE")] + RoleSubscriptionPurchase = 25, + + /// + /// Message is a interaction premium upsell + /// + [DiscordEnum("INTERACTION_PREMIUM_UPSELL")] + InteractionPremiumUpsell = 26, + + /// + /// Message is a stage start + /// + [DiscordEnum("STAGE_START")] + StageStart = 27, + + /// + /// Message is a stage end + /// + [DiscordEnum("STAGE_END")] + StageEnd = 28, + + /// + /// Message is a stage speaker + /// + [DiscordEnum("STAGE_SPEAKER")] + StageSpeaker = 29, + + /// + /// Message is a stage raise hand + /// + [DiscordEnum("STAGE_RAISE_HAND")] + StageRaiseHand = 30, + + /// + /// Message is a stage topic + /// + [DiscordEnum("STAGE_TOPIC")] + StageTopic = 31, + + /// + /// Message is a Guild Application Premium Subscription + /// + [DiscordEnum("GUILD_APPLICATION_PREMIUM_SUBSCRIPTION")] + GuildApplicationPremiumSubscription = 32, + + /// + /// Message is a Guild Incident Alert Mode Enabled + /// + [DiscordEnum("GUILD_INCIDENT_ALERT_MODE_ENABLED")] + GuildIncidentAlertModeEnabled = 36, + + /// + /// Message is a Guild Incident Alert Mode Disabled + /// + [DiscordEnum("GUILD_INCIDENT_ALERT_MODE_DISABLED")] + GuildIncidentAlertModeDisabled = 37, + + /// + /// Message is a Guild Incident Report Raid + /// + [DiscordEnum("GUILD_INCIDENT_REPORT_RAID")] + GuildIncidentReportRaid = 38, + + /// + /// Message is a Guild Incident Report False Alarm + /// + [DiscordEnum("GUILD_INCIDENT_REPORT_FALSE_ALARM")] + GuildIncidentReportFalseAlarm = 39, + + /// + /// Message is a Purchase Notification + /// + [DiscordEnum("PURCHASE_NOTIFICATION")] + PurchaseNotification = 44, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/MessageUpdate.cs b/Oxide.Ext.Discord/Entities/Messages/MessageUpdate.cs index 882e1782d..d101c459d 100644 --- a/Oxide.Ext.Discord/Entities/Messages/MessageUpdate.cs +++ b/Oxide.Ext.Discord/Entities/Messages/MessageUpdate.cs @@ -4,101 +4,100 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Message Update Structure sent in a channel within Discord.. +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class MessageUpdate : IFileAttachments, IDiscordValidation, IDiscordMessageTemplate { /// - /// Represents a Message Update Structure sent in a channel within Discord.. + /// Contents of the message up to 2000 characters /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class MessageUpdate : IFileAttachments, IDiscordValidation, IDiscordMessageTemplate - { - /// - /// Contents of the message up to 2000 characters - /// - [JsonProperty("content")] - public string Content { get; set; } + [JsonProperty("content")] + public string Content { get; set; } - /// - /// Up to 10 rich embeds (up to 6000 characters) - /// - [JsonProperty("embeds")] - public List Embeds { get; set; } + /// + /// Up to 10 rich embeds (up to 6000 characters) + /// + [JsonProperty("embeds")] + public List Embeds { get; set; } - /// - /// Edit the flags of a message (only SUPPRESS_EMBEDS can currently be set/unset) - /// - [JsonProperty("flags")] - public MessageFlags? Flags { get; set; } + /// + /// Edit the flags of a message (only SUPPRESS_EMBEDS can currently be set/unset) + /// + [JsonProperty("flags")] + public MessageFlags? Flags { get; set; } - /// - /// Allowed mentions for the message - /// - [JsonProperty("allowed_mentions")] - public AllowedMentions AllowedMentions { get; set; } + /// + /// Allowed mentions for the message + /// + [JsonProperty("allowed_mentions")] + public AllowedMentions AllowedMentions { get; set; } - /// - /// Components to include with the message - /// - [JsonProperty("components")] - public List Components { get; set; } + /// + /// Components to include with the message + /// + [JsonProperty("components")] + public List Components { get; set; } - /// - /// Attachments for the message - /// - [JsonProperty("attachments")] - public List Attachments { get; set; } + /// + /// Attachments for the message + /// + [JsonProperty("attachments")] + public List Attachments { get; set; } - /// - /// Attachments for a discord message - /// - public List FileAttachments { get; set; } + /// + /// Attachments for a discord message + /// + public List FileAttachments { get; set; } - /// - /// Constructor - /// - public MessageUpdate() { } + /// + /// Constructor + /// + public MessageUpdate() { } - /// - /// Constructor for message to be edited - /// Only sets the Attachments field - /// - /// - public MessageUpdate(DiscordMessage message) - { - Attachments = message.Attachments?.Values.ToList(); - } + /// + /// Constructor for message to be edited + /// Only sets the Attachments field + /// + /// + public MessageUpdate(DiscordMessage message) + { + Attachments = message.Attachments?.Values.ToList(); + } - /// - /// Adds an attachment to the message - /// - /// Name of the file - /// byte[] of the attachment - /// Attachment content type - /// Description for the attachment - public void AddAttachment(string filename, byte[] data, string contentType, string description = null) - { - InvalidFileNameException.ThrowIfInvalid(filename); - InvalidMessageException.ThrowIfInvalidAttachmentDescription(description); - - if (FileAttachments == null) - { - FileAttachments = new List(); - } - - if (Attachments == null) - { - Attachments = new List(); - } + /// + /// Adds an attachment to the message + /// + /// Name of the file + /// byte[] of the attachment + /// Attachment content type + /// Description for the attachment + public void AddAttachment(string filename, byte[] data, string contentType, string description = null) + { + InvalidFileNameException.ThrowIfInvalid(filename); + InvalidMessageException.ThrowIfInvalidAttachmentDescription(description); - FileAttachments.Add(new MessageFileAttachment(filename, data, contentType)); - Attachments.Add(new MessageAttachment {Id = new Snowflake((ulong)FileAttachments.Count), Filename = filename, Description = description}); + if (FileAttachments == null) + { + FileAttachments = new List(); } - - /// - public void Validate() + + if (Attachments == null) { - InvalidMessageException.ThrowIfInvalidContent(Content); - InvalidMessageException.ThrowIfInvalidFlags(Flags, MessageFlags.SuppressEmbeds, "Invalid Message Flags Used for Channel Message. Only supported flags are MessageFlags.SuppressEmbeds"); + Attachments = new List(); } + + FileAttachments.Add(new MessageFileAttachment(filename, data, contentType)); + Attachments.Add(new MessageAttachment {Id = new Snowflake((ulong)FileAttachments.Count), Filename = filename, Description = description}); + } + + /// + public void Validate() + { + InvalidMessageException.ThrowIfInvalidContent(Content); + InvalidMessageException.ThrowIfInvalidFlags(Flags, MessageFlags.SuppressEmbeds, "Invalid Message Flags Used for Channel Message. Only supported flags are MessageFlags.SuppressEmbeds"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Polls/DiscordPoll.cs b/Oxide.Ext.Discord/Entities/Messages/Polls/DiscordPoll.cs new file mode 100644 index 000000000..f6d8fd3ef --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/Polls/DiscordPoll.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Poll +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordPoll +{ + /// + /// The question of the poll. Only text is supported. + /// + [JsonProperty("question")] + public PollMedia Question { get; set; } + + /// + /// Each of the answers available in the poll. + /// + [JsonProperty("answers")] + public List Answers { get; set; } + + /// + /// The time when the poll ends. + /// + [JsonProperty("expiry")] + public DateTimeOffset? Expiry { get; set; } + + /// + /// Whether a user can select multiple answers + /// + [JsonProperty("allow_multiselect")] + public bool AllowMultiselect { get; set; } + + /// + /// The layout type of the poll + /// + [JsonProperty("layout_type")] + public PollLayoutType LayoutType { get; set; } + + /// + /// The results of the poll + /// + [JsonProperty("results")] + public PollResults Results { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Polls/GetPollAnswerResponse.cs b/Oxide.Ext.Discord/Entities/Messages/Polls/GetPollAnswerResponse.cs new file mode 100644 index 000000000..8b90b6077 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/Polls/GetPollAnswerResponse.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Get Poll Answers Response +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GetPollAnswerResponse +{ + /// + /// Users who voted for this answer + /// + [JsonProperty("users")] + public List Users { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Polls/GetPollAnswerVoters.cs b/Oxide.Ext.Discord/Entities/Messages/Polls/GetPollAnswerVoters.cs new file mode 100644 index 000000000..19331c55b --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/Polls/GetPollAnswerVoters.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json; +using Oxide.Ext.Discord.Builders; +using Oxide.Ext.Discord.Cache; +using Oxide.Ext.Discord.Interfaces; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Get Answer Voters Query String Params +/// +public class GetPollAnswerVoters : IDiscordQueryString +{ + /// + /// The type of reaction + /// + [JsonProperty("type")] + public ReactionType Type { get; set; } = ReactionType.Normal; + + /// + /// Get users after this user ID + /// + [JsonProperty("after")] + public Snowflake? After { get; set; } + + /// + /// Max number of users to return (1-100) + /// + [JsonProperty("limit")] + public int? Limit { get; set; } + + /// + public string ToQueryString() + { + QueryStringBuilder builder = new(); + + if(Type != ReactionType.Normal) + { + builder.Add("type", StringCache.Instance.ToString((byte)Type)); + } + + if (After.HasValue) + { + builder.Add("after", After.Value.ToString()); + } + + if (Limit.HasValue) + { + builder.Add("limit", Limit.Value.ToString()); + } + + return builder.ToString(); + } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Polls/PollAnswerCount.cs b/Oxide.Ext.Discord/Entities/Messages/Polls/PollAnswerCount.cs new file mode 100644 index 000000000..de26b3020 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/Polls/PollAnswerCount.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Poll Answer Count +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class PollAnswerCount +{ + /// + /// The answer_id + /// + [JsonProperty("id")] + public int Id { get; set; } + + /// + /// The number of votes for this answer + /// + [JsonProperty("count")] + public int Count { get; set; } + + /// + /// Whether the current user voted for this answer + /// + [JsonProperty("me_voted")] + public bool MeVoted { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Polls/PollAnswers.cs b/Oxide.Ext.Discord/Entities/Messages/Polls/PollAnswers.cs new file mode 100644 index 000000000..c10b73659 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/Polls/PollAnswers.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Poll Answers +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class PollAnswers +{ + /// + /// The ID of the answer + /// + [JsonProperty("answer_id")] + public int AnswerId { get; set; } + + /// + /// The data of the answer + /// + [JsonProperty("poll_media")] + public PollMedia PollMedia { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Polls/PollCreate.cs b/Oxide.Ext.Discord/Entities/Messages/Polls/PollCreate.cs new file mode 100644 index 000000000..36a3abef9 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/Polls/PollCreate.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Poll Create +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class PollCreate +{ + /// + /// The question of the poll. Only text is supported. + /// + [JsonProperty("question")] + public PollMedia Question { get; set; } + + /// + /// Each of the answers available in the poll. + /// + [JsonProperty("answers")] + public List Answers { get; set; } + + /// + /// Number of hours the poll should be open for, up to 32 days + /// + [JsonProperty("duration")] + public int Duration { get; set; } + + /// + /// Whether a user can select multiple answers + /// + [JsonProperty("allow_multiselect")] + public bool AllowMultiselect { get; set; } + + /// + /// The layout type of the poll + /// + [JsonProperty("layout_type")] + public PollLayoutType LayoutType { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Polls/PollLayoutType.cs b/Oxide.Ext.Discord/Entities/Messages/Polls/PollLayoutType.cs new file mode 100644 index 000000000..011df3b6c --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/Polls/PollLayoutType.cs @@ -0,0 +1,12 @@ +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Poll Layout Type +/// +public enum PollLayoutType +{ + /// + /// The default layout type. + /// + Default = 1 +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Polls/PollMedia.cs b/Oxide.Ext.Discord/Entities/Messages/Polls/PollMedia.cs new file mode 100644 index 000000000..3074739d1 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/Polls/PollMedia.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Poll Media +/// +public class PollMedia +{ + /// + /// The text of the field + /// + [JsonProperty("text")] + public string Text { get; set; } + + /// + /// The emoji of the field + /// + [JsonProperty("emoji")] + public DiscordEmoji Emoji { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/Polls/PollResults.cs b/Oxide.Ext.Discord/Entities/Messages/Polls/PollResults.cs new file mode 100644 index 000000000..4a3169695 --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/Polls/PollResults.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Poll Results +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class PollResults +{ + /// + /// Whether the votes have been precisely counted + /// + [JsonProperty("is_finalized")] + public bool IsFinalized { get; set; } + + /// + /// The counts for each answer + /// + [JsonProperty("answer_counts")] + public List AnswerCounts { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/ReactionCountDetails.cs b/Oxide.Ext.Discord/Entities/Messages/ReactionCountDetails.cs index 5026c062c..8a041a92d 100644 --- a/Oxide.Ext.Discord/Entities/Messages/ReactionCountDetails.cs +++ b/Oxide.Ext.Discord/Entities/Messages/ReactionCountDetails.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Reaction Count Details Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ReactionCountDetails { /// - /// Represents a Reaction Count Details Structure + /// Count of super reactions /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ReactionCountDetails - { - /// - /// Count of super reactions - /// - [JsonProperty("burst")] - public int Burst { get; set; } + [JsonProperty("burst")] + public int Burst { get; set; } - /// - /// Count of normal reactions - /// - [JsonProperty("normal")] - public int Normal { get; set; } - } + /// + /// Count of normal reactions + /// + [JsonProperty("normal")] + public int Normal { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Messages/ReactionType.cs b/Oxide.Ext.Discord/Entities/Messages/ReactionType.cs new file mode 100644 index 000000000..87994ccfa --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Messages/ReactionType.cs @@ -0,0 +1,17 @@ +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Reaction Type +/// +public enum ReactionType +{ + /// + /// Normal Reaction Type + /// + Normal = 0, + + /// + /// Burst Reaction Type + /// + Burst = 1 +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Monetization/Entitlements/CreateTestEntitlement.cs b/Oxide.Ext.Discord/Entities/Monetization/Entitlements/CreateTestEntitlement.cs index 72c08c11a..7a454c9b5 100644 --- a/Oxide.Ext.Discord/Entities/Monetization/Entitlements/CreateTestEntitlement.cs +++ b/Oxide.Ext.Discord/Entities/Monetization/Entitlements/CreateTestEntitlement.cs @@ -1,29 +1,28 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Create Test Entitlement Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class CreateTestEntitlement { /// - /// Represents a Create Test Entitlement Structure + /// ID of the SKU to grant the entitlement to /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class CreateTestEntitlement - { - /// - /// ID of the SKU to grant the entitlement to - /// - [JsonProperty("sku_id")] - public Snowflake SkuId { get; set; } + [JsonProperty("sku_id")] + public Snowflake SkuId { get; set; } - /// - /// ID of the guild or user to grant the entitlement to - /// - [JsonProperty("owner_id")] - public Snowflake OwnerId { get; set; } + /// + /// ID of the guild or user to grant the entitlement to + /// + [JsonProperty("owner_id")] + public Snowflake OwnerId { get; set; } - /// - /// ID of the guild or user to grant the entitlement to - /// - [JsonProperty("owner_type")] - public EntitlementOwnerType OwnerType { get; set; } - } + /// + /// ID of the guild or user to grant the entitlement to + /// + [JsonProperty("owner_type")] + public EntitlementOwnerType OwnerType { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Monetization/Entitlements/DiscordEntitlement.cs b/Oxide.Ext.Discord/Entities/Monetization/Entitlements/DiscordEntitlement.cs index 44b24ff33..345c0e46d 100644 --- a/Oxide.Ext.Discord/Entities/Monetization/Entitlements/DiscordEntitlement.cs +++ b/Oxide.Ext.Discord/Entities/Monetization/Entitlements/DiscordEntitlement.cs @@ -5,97 +5,115 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Entitlement Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordEntitlement { /// - /// Represents a Entitlement Structure + /// ID of the entitlement /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordEntitlement - { - /// - /// ID of the entitlement - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// ID of the SKU - /// - [JsonProperty("sku_id")] - public Snowflake SkuId { get; set; } + /// + /// ID of the SKU + /// + [JsonProperty("sku_id")] + public Snowflake SkuId { get; set; } - /// - /// ID of the parent application - /// - [JsonProperty("application_id")] - public Snowflake ApplicationId { get; set; } + /// + /// ID of the parent application + /// + [JsonProperty("application_id")] + public Snowflake ApplicationId { get; set; } - /// - /// ID of the user that is granted access to the entitlement's sku - /// - [JsonProperty("user_id")] - public Snowflake? UserId { get; set; } + /// + /// ID of the user that is granted access to the entitlement's sku + /// + [JsonProperty("user_id")] + public Snowflake? UserId { get; set; } - /// - /// Type of entitlement - /// - [JsonProperty("type")] - public EntitlementType Type { get; set; } + /// + /// Type of entitlement + /// + [JsonProperty("type")] + public EntitlementType Type { get; set; } - /// - /// Entitlement was deleted - /// - [JsonProperty("deleted")] - public bool Deleted { get; set; } + /// + /// Entitlement was deleted + /// + [JsonProperty("deleted")] + public bool Deleted { get; set; } - /// - /// Start date at which the entitlement is valid. Not present when using test entitlements. - /// - [JsonProperty("starts_at")] - public DateTime StartsAt { get; set; } + /// + /// Start date at which the entitlement is valid. Not present when using test entitlements. + /// + [JsonProperty("starts_at")] + public DateTime StartsAt { get; set; } - /// - /// Date at which the entitlement is no longer valid. Not present when using test entitlements. - /// - [JsonProperty("ends_at")] - public DateTime EndsAt { get; set; } + /// + /// Date at which the entitlement is no longer valid. Not present when using test entitlements. + /// + [JsonProperty("ends_at")] + public DateTime EndsAt { get; set; } + + /// + /// ID of the guild that is granted access to the entitlement's sku + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// ID of the guild that is granted access to the entitlement's sku - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// For consumable items, whether the entitlement has been consumed + /// + [JsonProperty("consumed")] + public bool? Consumed { get; set; } - /// - /// Returns all entitlements for a given app, active and expired. - /// - /// Client to use - /// Application ID to get entitlement for - /// Query string options for the request - public static IPromise> GetEntitlements(DiscordClient client, Snowflake applicationId, GetEntitlements getEntitlements = null) - { - InvalidSnowflakeException.ThrowIfInvalid(applicationId, true, nameof(applicationId)); - return client.Bot.Rest.Get>(client, $"applications/{applicationId}/application-object/entitlements{getEntitlements?.ToQueryString()}"); - } + /// + /// Returns all entitlements for a given app, active and expired. + /// See List Entitlements + /// + /// Client to use + /// Application ID to get entitlement for + /// Query string options for the request + public static IPromise> GetEntitlements(DiscordClient client, Snowflake applicationId, GetEntitlements getEntitlements = null) + { + InvalidSnowflakeException.ThrowIfInvalid(applicationId, true); + return client.Bot.Rest.Get>(client, $"applications/{applicationId}/application-object/entitlements{getEntitlements?.ToQueryString()}"); + } + + /// + /// For One-Time Purchase consumable SKUs, marks a given entitlement for the user as consumed. + /// See Consume an Entitlement + /// + /// Client to use + public IPromise ConsumeEntitlement(DiscordClient client) + { + return client.Bot.Rest.Post(client, $"applications/{ApplicationId}/entitlements/{Id}/consume", null); + } - /// - /// Creates a test entitlement to a given SKU for a given guild or user. Discord will act as though that user or guild has entitlement to your premium offering. - /// - /// Client to use - /// Create request - public IPromise CreateTestEntitlement(DiscordClient client, CreateTestEntitlement create) - { - return client.Bot.Rest.Post(client, $"applications/{ApplicationId}/entitlements", create); - } + /// + /// Creates a test entitlement to a given SKU for a given guild or user. Discord will act as though that user or guild has entitlement to your premium offering. + /// See Create Test Entitlement + /// + /// Client to use + /// Create request + public IPromise CreateTestEntitlement(DiscordClient client, CreateTestEntitlement create) + { + return client.Bot.Rest.Post(client, $"applications/{ApplicationId}/entitlements", create); + } - /// - /// Deletes a currently-active test entitlement. Discord will act as though that user or guild no longer has entitlement to your premium offering. - /// - /// Client to use - public IPromise DeleteTestEntitlement(DiscordClient client) - { - return client.Bot.Rest.Delete(client, $"/applications/{ApplicationId}/entitlements/{Id}"); - } + /// + /// Deletes a currently-active test entitlement. Discord will act as though that user or guild no longer has entitlement to your premium offering. + /// See Delete Test Entitlement + /// + /// Client to use + public IPromise DeleteTestEntitlement(DiscordClient client) + { + return client.Bot.Rest.Delete(client, $"/applications/{ApplicationId}/entitlements/{Id}"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Monetization/Entitlements/EntitlementOwnerType.cs b/Oxide.Ext.Discord/Entities/Monetization/Entitlements/EntitlementOwnerType.cs index 06b9a21f4..a53e9d1d0 100644 --- a/Oxide.Ext.Discord/Entities/Monetization/Entitlements/EntitlementOwnerType.cs +++ b/Oxide.Ext.Discord/Entities/Monetization/Entitlements/EntitlementOwnerType.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Entitlement Owner Types +/// +public enum EntitlementOwnerType { /// - /// Represents a Entitlement Owner Types + /// Subscription is a Guild Subscription /// - public enum EntitlementOwnerType - { - /// - /// Subscription is a Guild Subscription - /// - GuidSubscription = 1, + GuidSubscription = 1, - /// - /// Subscription is a User Subscription - /// - UserSubscription = 2 - } + /// + /// Subscription is a User Subscription + /// + UserSubscription = 2 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Monetization/Entitlements/EntitlementType.cs b/Oxide.Ext.Discord/Entities/Monetization/Entitlements/EntitlementType.cs index 6b1a21880..e41259ba7 100644 --- a/Oxide.Ext.Discord/Entities/Monetization/Entitlements/EntitlementType.cs +++ b/Oxide.Ext.Discord/Entities/Monetization/Entitlements/EntitlementType.cs @@ -1,13 +1,47 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Entitlement Types +/// +public enum EntitlementType { /// - /// Represents a Entitlement Types + /// Entitlement was purchased by user /// - public enum EntitlementType - { - /// - /// Entitlement was purchased as an app subscription - /// - ApplicationSubscription = 8 - } + Purchase = 1, + + /// + /// Entitlement for Discord Nitro subscription + /// + PremiumSubscription = 2, + + /// + /// Entitlement was gifted by developer + /// + DeveloperGift = 3, + + /// + /// Entitlement was purchased by a dev in application test mode + /// + TestModePurchase = 4, + + /// + /// Entitlement was granted when the SKU was free + /// + FreePurchase = 5, + + /// + /// Entitlement was claimed by user for free as a Nitro Subscriber + /// + UserGift = 6, + + /// + /// Entitlement was purchased as an app subscription + /// + PremiumPurchase = 7, + + /// + /// Entitlement was purchased as an app subscription + /// + ApplicationSubscription = 8 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Monetization/Entitlements/GetEntitlements.cs b/Oxide.Ext.Discord/Entities/Monetization/Entitlements/GetEntitlements.cs index 1aff2102e..a4c9c73e7 100644 --- a/Oxide.Ext.Discord/Entities/Monetization/Entitlements/GetEntitlements.cs +++ b/Oxide.Ext.Discord/Entities/Monetization/Entitlements/GetEntitlements.cs @@ -3,71 +3,69 @@ using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Get Entitlements Query String Builder +/// +public class GetEntitlements : IDiscordQueryString, IDiscordValidation { /// - /// Get Entitlements Query String Builder + /// User ID to look up entitlements for /// - public class GetEntitlements : IDiscordQueryString, IDiscordValidation - { - /// - /// User ID to look up entitlements for - /// - public Snowflake? UserId { get; set; } + public Snowflake? UserId { get; set; } - /// - /// Optional list of SKU IDs to check entitlements for - /// - public List SkuIds { get; set; } + /// + /// Optional list of SKU IDs to check entitlements for + /// + public List SkuIds { get; set; } - /// - /// Retrieve entitlements before this entitlement ID - /// - public Snowflake? Before { get; set; } + /// + /// Retrieve entitlements before this entitlement ID + /// + public Snowflake? Before { get; set; } - /// - /// Retrieve entitlements after this entitlement ID - /// - public Snowflake? After { get; set; } + /// + /// Retrieve entitlements after this entitlement ID + /// + public Snowflake? After { get; set; } - /// - /// Number of entitlements to return, 1-100, default 100 - /// - public int? Limit { get; set; } + /// + /// Number of entitlements to return, 1-100, default 100 + /// + public int? Limit { get; set; } - /// - /// Guild ID to look up entitlements for - /// - public Snowflake? GuildId { get; set; } + /// + /// Guild ID to look up entitlements for + /// + public Snowflake? GuildId { get; set; } - /// - /// Whether expired entitlements should be omitted - /// - public bool? ExcludeEnded { get; set; } + /// + /// Whether expired entitlements should be omitted + /// + public bool? ExcludeEnded { get; set; } - /// - public string ToQueryString() - { - Validate(); - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); + /// + public string ToQueryString() + { + Validate(); + QueryStringBuilder builder = new(); - if(UserId.HasValue) builder.Add("user_id", UserId.Value); - if(SkuIds != null) builder.AddList("sku_ids", SkuIds, ","); - if(Before.HasValue) builder.Add("before", Before.Value); - if(After.HasValue) builder.Add("after", After.Value); - if(Limit.HasValue) builder.Add("limit", Limit.Value.ToString()); - if(GuildId.HasValue) builder.Add("guild_id", GuildId.Value.ToString()); - if(ExcludeEnded.HasValue) builder.Add("exclude_ended", StringCache.Instance.ToString(ExcludeEnded.Value)); + if(UserId.HasValue) builder.Add("user_id", UserId.Value); + if(SkuIds != null) builder.AddList("sku_ids", SkuIds, ","); + if(Before.HasValue) builder.Add("before", Before.Value); + if(After.HasValue) builder.Add("after", After.Value); + if(Limit.HasValue) builder.Add("limit", Limit.Value.ToString()); + if(GuildId.HasValue) builder.Add("guild_id", GuildId.Value.ToString()); + if(ExcludeEnded.HasValue) builder.Add("exclude_ended", StringCache.Instance.ToString(ExcludeEnded.Value)); - return builder.ToStringAndFree(); - } + return builder.ToString(); + } - /// - public void Validate() - { - InvalidGetEntitlementException.ThrowIfInvalidLimit(Limit); - } + /// + public void Validate() + { + InvalidGetEntitlementException.ThrowIfInvalidLimit(Limit); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Monetization/Skus/DiscordSku.cs b/Oxide.Ext.Discord/Entities/Monetization/Skus/DiscordSku.cs index d6a3e163d..5555b049d 100644 --- a/Oxide.Ext.Discord/Entities/Monetization/Skus/DiscordSku.cs +++ b/Oxide.Ext.Discord/Entities/Monetization/Skus/DiscordSku.cs @@ -3,58 +3,57 @@ using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a SKU Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordSku { /// - /// Represents a SKU Structure + /// ID of SKU /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordSku - { - /// - /// ID of SKU - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Type of SKU - /// - [JsonProperty("type")] - public DiscordSkuType Type { get; set; } + /// + /// Type of SKU + /// + [JsonProperty("type")] + public DiscordSkuType Type { get; set; } - /// - /// ID of the parent application - /// - [JsonProperty("application_id")] - public Snowflake ApplicationId { get; set; } + /// + /// ID of the parent application + /// + [JsonProperty("application_id")] + public Snowflake ApplicationId { get; set; } - /// - /// Customer-facing name of your premium offering - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Customer-facing name of your premium offering + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// System-generated URL slug based on the SKU's name - /// - [JsonProperty("slug")] - public string Slug { get; set; } + /// + /// System-generated URL slug based on the SKU's name + /// + [JsonProperty("slug")] + public string Slug { get; set; } - /// - /// SKU flags combined as a bitfield - /// - [JsonProperty("flags")] - public SkuFlags Flags { get; set; } + /// + /// SKU flags combined as a bitfield + /// + [JsonProperty("flags")] + public SkuFlags Flags { get; set; } - /// - /// Returns all SKUs for a given application. Because of how our SKU and subscription systems work, you will see two SKUs for your premium offering. - /// - /// Client to use - /// Application ID to get SKU's for - public static IPromise> GetSkus(DiscordClient client, Snowflake applicationId) - { - return client.Bot.Rest.Get>(client, $"applications/{applicationId}/skus"); - } + /// + /// Returns all SKUs for a given application. Because of how our SKU and subscription systems work, you will see two SKUs for your premium offering. + /// + /// Client to use + /// Application ID to get SKU's for + public static IPromise> GetSkus(DiscordClient client, Snowflake applicationId) + { + return client.Bot.Rest.Get>(client, $"applications/{applicationId}/skus"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Monetization/Skus/DiscordSkuType.cs b/Oxide.Ext.Discord/Entities/Monetization/Skus/DiscordSkuType.cs index 82ad7c27f..da27487d9 100644 --- a/Oxide.Ext.Discord/Entities/Monetization/Skus/DiscordSkuType.cs +++ b/Oxide.Ext.Discord/Entities/Monetization/Skus/DiscordSkuType.cs @@ -1,18 +1,27 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord SKU Types +/// +public enum DiscordSkuType { /// - /// Represents a Discord SKU Types + /// Durable one-time purchase /// - public enum DiscordSkuType - { - /// - /// Represents a recurring subscription - /// - Subscription = 5, - - /// - /// System-generated group for each SUBSCRIPTION SKU created - /// - SubscriptionGroup = 6 - } + Durable = 2, + + /// + /// Consumable one-time purchase + /// + Consumable = 3, + + /// + /// Represents a recurring subscription + /// + Subscription = 5, + + /// + /// System-generated group for each SUBSCRIPTION SKU created + /// + SubscriptionGroup = 6 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Monetization/Skus/SkuFlags.cs b/Oxide.Ext.Discord/Entities/Monetization/Skus/SkuFlags.cs index da37e1be4..b53158706 100644 --- a/Oxide.Ext.Discord/Entities/Monetization/Skus/SkuFlags.cs +++ b/Oxide.Ext.Discord/Entities/Monetization/Skus/SkuFlags.cs @@ -1,31 +1,30 @@ using System; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord SKU Flags +/// +[Flags] +public enum SkuFlags { /// - /// Represents a Discord SKU Flags + /// No Sku Flags /// - [Flags] - public enum SkuFlags - { - /// - /// No Sku Flags - /// - None = 0, + None = 0, - /// - /// SKU is available for purchase - /// - Available = 1 << 2, + /// + /// SKU is available for purchase + /// + Available = 1 << 2, - /// - /// Recurring SKU that can be purchased by a user and applied to a single server. Grants access to every user in that server. - /// - GuildSubscription = 1 << 7, + /// + /// Recurring SKU that can be purchased by a user and applied to a single server. Grants access to every user in that server. + /// + GuildSubscription = 1 << 7, - /// - /// Recurring SKU purchased by a user for themselves. Grants access to the purchasing user in every server. - /// - UserSubscription = 1 << 8, - } + /// + /// Recurring SKU purchased by a user for themselves. Grants access to the purchasing user in every server. + /// + UserSubscription = 1 << 8, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Permissions/DiscordRole.cs b/Oxide.Ext.Discord/Entities/Permissions/DiscordRole.cs index 8aea5c859..7e19ad30f 100644 --- a/Oxide.Ext.Discord/Entities/Permissions/DiscordRole.cs +++ b/Oxide.Ext.Discord/Entities/Permissions/DiscordRole.cs @@ -3,149 +3,148 @@ using Oxide.Ext.Discord.Helpers; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Role Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordRole : ISnowflakeEntity, IDiscordValidation { + #region Discord Fields /// - /// Represents Role Structure + /// Role id /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordRole : ISnowflakeEntity, IDiscordValidation - { - #region Discord Fields - /// - /// Role id - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } - - /// - /// Role name - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Role Color - /// - [JsonProperty("color")] - public DiscordColor Color { get; set; } - - /// - /// If this role is pinned in the user listing - /// - [JsonProperty("hoist")] - public bool? Hoist { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } + + /// + /// Role name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Role Color + /// + [JsonProperty("color")] + public DiscordColor Color { get; set; } + + /// + /// If this role is pinned in the user listing + /// + [JsonProperty("hoist")] + public bool? Hoist { get; set; } - /// - /// The role's icon image (if the guild has the ROLE_ICONS feature) - /// - [JsonProperty("icon")] - public string Icon { get; set; } + /// + /// The role's icon image (if the guild has the ROLE_ICONS feature) + /// + [JsonProperty("icon")] + public string Icon { get; set; } - /// - /// The role's unicode emoji as a standard emoji (if the guild has the ROLE_ICONS feature) - /// - [JsonProperty("unicode_emoji")] - public string UnicodeEmoji { get; set; } - - /// - /// Position of this role - /// - [JsonProperty("position")] - public int Position { get; set; } - - /// - /// Role Permissions - /// - [JsonProperty("permissions")] - public PermissionFlags Permissions { get; set; } - - /// - /// Whether this role is managed by an integration - /// - [JsonProperty("managed")] - public bool Managed { get; set; } - - /// - /// Whether this role is mentionable - /// - [JsonProperty("mentionable")] - public bool Mentionable { get; set; } + /// + /// The role's unicode emoji as a standard emoji (if the guild has the ROLE_ICONS feature) + /// + [JsonProperty("unicode_emoji")] + public string UnicodeEmoji { get; set; } + + /// + /// Position of this role + /// + [JsonProperty("position")] + public int Position { get; set; } + + /// + /// Role Permissions + /// + [JsonProperty("permissions")] + public PermissionFlags Permissions { get; set; } + + /// + /// Whether this role is managed by an integration + /// + [JsonProperty("managed")] + public bool Managed { get; set; } + + /// + /// Whether this role is mentionable + /// + [JsonProperty("mentionable")] + public bool Mentionable { get; set; } - /// - /// The tags this role has - /// - [JsonProperty("tags")] - public RoleTags Tags { get; set; } + /// + /// The tags this role has + /// + [JsonProperty("tags")] + public RoleTags Tags { get; set; } - /// - /// The flags for the given role - /// - [JsonProperty("flags")] - public RoleFlags Flags { get; set; } + /// + /// The flags for the given role + /// + [JsonProperty("flags")] + public RoleFlags Flags { get; set; } - /// - /// Returns a string to mention this role in a message - /// - public string Mention => DiscordFormatting.MentionRole(Id); - - /// - /// Return the Role Icon URL for a Discord Role. Empty string is not set. - /// - public string RoleIcon => !string.IsNullOrEmpty(Icon) ? DiscordCdn.GetRoleIcon(Id) : string.Empty; - #endregion - - #region Helper Methods - /// - /// Returns if the role has the specified permission - /// - /// Permission to check for - /// Return true if role has permission; false otherwise - public bool HasPermission(PermissionFlags perm) - { - return (Permissions & perm) == perm; - } + /// + /// Returns a string to mention this role in a message + /// + public string Mention => DiscordFormatting.MentionRole(Id); - /// - /// Returns if this role is the booster - /// - /// True if booster role. False otherwise; - public bool IsBoosterRole() - { - return Managed && Tags != null && !Tags.BotId.HasValue; - } - #endregion + /// + /// Return the Role Icon URL for a Discord Role. Empty string is not set. + /// + public string RoleIcon => !string.IsNullOrEmpty(Icon) ? DiscordCdn.GetRoleIcon(Id) : string.Empty; + #endregion - #region Entity Update - internal DiscordRole UpdateRole(DiscordRole role) - { - DiscordRole previous = (DiscordRole)MemberwiseClone(); - if (role.Name != null) - { - Name = role.Name; - } - - Color = role.Color; - Hoist = role.Hoist; - Position = role.Position; - Permissions = role.Permissions; - Managed = role.Managed; - Mentionable = role.Mentionable; - Flags = role.Flags; - - if (role.Tags != null) - { - Tags = role.Tags; - } + #region Helper Methods + /// + /// Returns if the role has the specified permission + /// + /// Permission to check for + /// Return true if role has permission; false otherwise + public bool HasPermission(PermissionFlags perm) + { + return (Permissions & perm) == perm; + } + + /// + /// Returns if this role is the booster + /// + /// True if booster role. False otherwise; + public bool IsBoosterRole() + { + return Managed && Tags != null && !Tags.BotId.HasValue; + } + #endregion - return previous; + #region Entity Update + internal DiscordRole UpdateRole(DiscordRole role) + { + DiscordRole previous = (DiscordRole)MemberwiseClone(); + if (role.Name != null) + { + Name = role.Name; } - #endregion - /// - public void Validate() + Color = role.Color; + Hoist = role.Hoist; + Position = role.Position; + Permissions = role.Permissions; + Managed = role.Managed; + Mentionable = role.Mentionable; + Flags = role.Flags; + + if (role.Tags != null) { - InvalidGuildRoleException.ThrowIfInvalidRoleName(Name); + Tags = role.Tags; } + + return previous; + } + #endregion + + /// + public void Validate() + { + InvalidGuildRoleException.ThrowIfInvalidRoleName(Name); } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Permissions/PermissionFlags.cs b/Oxide.Ext.Discord/Entities/Permissions/PermissionFlags.cs index 942e2ca5f..bb5c67ffb 100644 --- a/Oxide.Ext.Discord/Entities/Permissions/PermissionFlags.cs +++ b/Oxide.Ext.Discord/Entities/Permissions/PermissionFlags.cs @@ -1,373 +1,384 @@ using System; using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Permission Flags for user or role +/// +[Flags] +public enum PermissionFlags : ulong { /// - /// Represents Permission Flags for user or role - /// - [Flags] - public enum PermissionFlags : ulong - { - /// - /// Represents No Permissions - /// - None = 0, - - /// - /// Represents all possible Permissions Flags - /// - All = ulong.MaxValue, - - /// - /// Allows creation of instant invites - /// Channel Type (Text, Voice, Stage) - /// - [DiscordEnum("CREATE_INSTANT_INVITE")] - CreateInstantInvite = 1 << 0, - - /// - /// Allows kicking members - /// - [DiscordEnum("KICK_MEMBERS")] - KickMembers = 1 << 1, - - /// - /// Allows banning members - /// - [DiscordEnum("BAN_MEMBERS")] - BanMembers = 1 << 2, - - /// - /// Allows all permissions and bypasses channel permission overwrites - /// - [DiscordEnum("ADMINISTRATOR")] - Administrator = 1 << 3, - - /// - /// Allows management and editing of channels - /// Channel Type (Text, Voice, Stage) - /// - [DiscordEnum("MANAGE_CHANNELS")] - ManageChannels = 1 << 4, - - /// - /// Allows management and editing of the guild - /// - [DiscordEnum("MANAGE_GUILD")] - ManageGuild = 1 << 5, - - /// - /// Allows for the addition of reactions to messages - /// Channel Type (Text) - /// - [DiscordEnum("ADD_REACTIONS")] - AddReactions = 1 << 6, - - /// - /// Allows for viewing of audit logs - /// - [DiscordEnum("VIEW_AUDIT_LOG")] - ViewAuditLog = 1 << 7, - - /// - /// Allows for using priority speaker in a voice channel - /// Channel Type (Voice) - /// - [DiscordEnum("PRIORITY_SPEAKER")] - PrioritySpeaker = 1 << 8, - - /// - /// Allows the user to go live - /// Channel Type (Voice) - /// - [DiscordEnum("STREAM")] - Stream = 1 << 9, - - /// - /// Allows guild members to view a channel, which includes reading messages in text channels and joining voice channels - /// Channel Type (Text, Voice, Stage) - /// - [DiscordEnum("VIEW_CHANNEL")] - ViewChannel = 1 << 10, - - /// - /// Allows for sending messages in a channel - /// Channel Type (Text) - /// - [DiscordEnum("SEND_MESSAGES")] - SendMessages = 1 << 11, - - /// - /// Allows for sending of /tts messages - /// Channel Type (Text) - /// - [DiscordEnum("SEND_TTS_MESSAGES")] - SendTtsMessages = 1 << 12, - - /// - /// Allows for deletion of other users messages - /// Channel Type (Text) - /// - [DiscordEnum("MANAGE_MESSAGES")] - ManageMessages = 1 << 13, - - /// - /// Links sent by users with this permission will be auto-embedded - /// Channel Type (Text) - /// - [DiscordEnum("EMBED_LINKS")] - EmbedLinks = 1 << 14, - - /// - /// Allows for uploading images and files - /// Channel Type (Text) - /// - [DiscordEnum("ATTACH_FILES")] - AttachFiles = 1 << 15, - - /// - /// Allows for reading of message history - /// Channel Type (Text) - /// - [DiscordEnum("READ_MESSAGE_HISTORY")] - ReadMessageHistory = 1 << 16, - - /// - /// Allows for using the @everyone tag to notify all users in a channel, - /// and the @here tag to notify all online users in a channel - /// Channel Type (Text, Stage) - /// - [DiscordEnum("MENTION_EVERYONE")] - MentionEveryone = 1 << 17, - - /// - /// Allows the usage of custom emojis from other servers - /// Channel Type (Text) - /// - [DiscordEnum("USE_EXTERNAL_EMOJIS")] - UseExternalEmojis = 1 << 18, - - /// - /// Allows for viewing guild insights - /// - [DiscordEnum("VIEW_GUILD_INSIGHTS")] - ViewGuildInsights = 1 << 19, - - /// - /// Allows for joining of a voice channel - /// Channel Type (Voice, Stage) - /// - [DiscordEnum("CONNECT")] - Connect = 1 << 20, - - /// - /// Allows for speaking in a voice channel - /// Channel Type (Voice) - /// - [DiscordEnum("SPEAK")] - Speak = 1 << 21, - - /// - /// Allows for muting members in a voice channel - /// Channel Type (Voice, Stage) - /// - [DiscordEnum("MUTE_MEMBERS")] - MuteMembers = 1 << 22, - - /// - /// Allows for deafening of members in a voice channel - /// Channel Type (Voice, Stage) - /// - [DiscordEnum("DEAFEN_MEMBERS")] - DeafanMembers = 1 << 23, - - /// - /// Allows for moving of members between voice channels - /// Channel Type (Voice, Stage) - /// - [DiscordEnum("MOVE_MEMBERS")] - MoveMembers = 1 << 24, - - /// - /// Allows for using voice-activity-detection in a voice channel - /// Channel Type (Voice) - /// - [DiscordEnum("USE_VAD")] - UseVad = 1 << 25, - - /// - /// Allows for modification of own nickname - /// - [DiscordEnum("CHANGE_NICKNAME")] - ChangeNickname = 1 << 26, - - /// - /// Allows for modification of other users nicknames - /// - [DiscordEnum("MANAGE_NICKNAMES")] - ManageNicknames = 1 << 27, - - /// - /// Allows management and editing of roles - /// Channel Type (Text, Voice, Stage) - /// - [DiscordEnum("MANAGE_ROLES")] - ManageRoles = 1 << 28, - - /// - /// Allows management and editing of webhooks - /// Channel Type (Text) - /// - [DiscordEnum("MANAGE_WEBHOOKS")] - ManageWebhooks = 1 << 29, - - /// - /// Allows for editing and deleting emojis, stickers, and soundboard sounds created by all users - /// - [DiscordEnum("MANAGE_GUILD_EXPRESSIONS")] - ManageGuildExpressions = 1 << 30, - - /// - /// Allows management and editing of emojis - /// - [DiscordEnum("MANAGE_EMOJIS_AND_STICKERS")] - [Obsolete("Replace with ManageGuildExpressions")] - ManageEmojisAndStickers = 1 << 30, - - /// - /// Allows members to use application commands, including slash commands and context menu commands. - /// - [DiscordEnum("USE_APPLICATION_COMMANDS")] - UseSlashCommands = 1ul << 31, - - /// - /// Allows for requesting to speak in stage channels. - /// Channel Type (Stage) - /// (This permission is under active development and may be changed or removed.) - /// - [DiscordEnum("REQUEST_TO_SPEAK")] - RequestToSpeak = 1ul << 32, - - /// - /// Allows for editing and deleting scheduled events created by all users - /// Channel Type (Voice, Stage) - /// - [DiscordEnum("MANAGE_EVENTS")] - ManageEvents = 1ul << 33, - - /// - /// Allows for deleting and archiving threads, and viewing all private threads - /// Channel Type (Text) - /// - [DiscordEnum("MANAGE_THREADS")] - ManageThreads = 1ul << 34, - - /// - /// Allows for creating and participating in threads - /// Channel Type (Text) - /// - [Obsolete("This flag has been deprecated and will be removed in a future update. This flag is replaced by CreatePublicThreads")] - [DiscordEnum("USE_PUBLIC_THREADS")] - UsePublicThreads = 1ul << 35, - - /// - /// Allows for creating threads - /// Channel Type (Text) - /// - [DiscordEnum("CREATE_PUBLIC_THREADS")] - CreatePublicThreads = 1ul << 35, - - /// - /// Allows for creating and participating in private threads - /// Channel Type (Text) - /// - [Obsolete("This flag has been deprecated and will be removed in a future update. This flag is replaced by CreatePrivateThreads")] - [DiscordEnum("USE_PRIVATE_THREADS")] - UsePrivateThreads = 1ul << 36, - - /// - /// Allows for creating private threads - /// Channel Type (Text) - /// - [DiscordEnum("CREATE_PRIVATE_THREADS")] - CreatePrivateThreads = 1ul << 36, - - /// - /// Allows the usage of custom stickers from other servers - /// Channel Type (Text) - /// - [DiscordEnum("USE_EXTERNAL_STICKERS")] - UseExternalStickers = 1ul << 37, - - /// - /// Allows for sending messages in threads - /// Channel Type (Text) - /// - [DiscordEnum("SEND_MESSAGES_IN_THREADS")] - SendMessagesInThreads = 1ul << 38, - - /// - /// Allows for launching activities (applications with the `EMBEDDED` flag) in a voice channel - /// Channel Type (Voice) - /// - [Obsolete("Replaced with UseEmbeddedActivities")] - [DiscordEnum("START_EMBEDDED_ACTIVITIES")] - StartEmbeddedActivities = 1ul << 39, - - /// - /// Allows for using Activities (applications with the `EMBEDDED` flag) in a voice channel - /// Channel Type (Voice) - /// - [DiscordEnum("USE_EMBEDDED_ACTIVITIES")] - UseEmbeddedActivities = 1ul << 39, - - /// - /// Allows for timing out users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels - /// - [DiscordEnum("MODERATE_MEMBERS")] - ModerateMembers = 1ul << 40, - - /// - /// Allows for viewing role subscription insights - /// - [DiscordEnum("VIEW_CREATOR_MONETIZATION_ANALYTICS")] - ViewCreatorMonetizationAnalytics = 1ul << 41, - - /// - /// Allows for using soundboard in a voice channel - /// - [DiscordEnum("USE_SOUNDBOARD")] - UseSoundboard = 1ul << 42, - - /// - /// Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user - /// - [DiscordEnum("CREATE_GUILD_EXPRESSIONS")] - CreateGuildExpressions = 1ul << 43, - - /// - /// Allows for creating scheduled events, and editing and deleting those created by the current user - /// - [DiscordEnum("CREATE_EVENTS")] - CreateEvents = 1ul << 44, - - /// - /// Allows the usage of custom soundboard sounds from other servers - /// - [DiscordEnum("USE_EXTERNAL_SOUNDS")] - UseExternalSounds = 1ul << 45, - - /// - /// Allows sending voice messages - /// - [DiscordEnum("SEND_VOICE_MESSAGES")] - SendVoiceMessages = 1ul << 46, - - /// - /// Allows members to interact with the Clyde AI bot - /// - [DiscordEnum("USE_CLYDE_AI")] - UseClydeAi = 1ul << 47, - } + /// Represents No Permissions + /// + None = 0, + + /// + /// Represents all possible Permissions Flags + /// + All = ulong.MaxValue, + + /// + /// Allows creation of instant invites + /// Channel Type (Text, Voice, Stage) + /// + [DiscordEnum("CREATE_INSTANT_INVITE")] + CreateInstantInvite = 1 << 0, + + /// + /// Allows kicking members + /// + [DiscordEnum("KICK_MEMBERS")] + KickMembers = 1 << 1, + + /// + /// Allows banning members + /// + [DiscordEnum("BAN_MEMBERS")] + BanMembers = 1 << 2, + + /// + /// Allows all permissions and bypasses channel permission overwrites + /// + [DiscordEnum("ADMINISTRATOR")] + Administrator = 1 << 3, + + /// + /// Allows management and editing of channels + /// Channel Type (Text, Voice, Stage) + /// + [DiscordEnum("MANAGE_CHANNELS")] + ManageChannels = 1 << 4, + + /// + /// Allows management and editing of the guild + /// + [DiscordEnum("MANAGE_GUILD")] + ManageGuild = 1 << 5, + + /// + /// Allows for the addition of reactions to messages + /// Channel Type (Text) + /// + [DiscordEnum("ADD_REACTIONS")] + AddReactions = 1 << 6, + + /// + /// Allows for viewing of audit logs + /// + [DiscordEnum("VIEW_AUDIT_LOG")] + ViewAuditLog = 1 << 7, + + /// + /// Allows for using priority speaker in a voice channel + /// Channel Type (Voice) + /// + [DiscordEnum("PRIORITY_SPEAKER")] + PrioritySpeaker = 1 << 8, + + /// + /// Allows the user to go live + /// Channel Type (Voice) + /// + [DiscordEnum("STREAM")] + Stream = 1 << 9, + + /// + /// Allows guild members to view a channel, which includes reading messages in text channels and joining voice channels + /// Channel Type (Text, Voice, Stage) + /// + [DiscordEnum("VIEW_CHANNEL")] + ViewChannel = 1 << 10, + + /// + /// Allows for sending messages in a channel + /// Channel Type (Text) + /// + [DiscordEnum("SEND_MESSAGES")] + SendMessages = 1 << 11, + + /// + /// Allows for sending of /tts messages + /// Channel Type (Text) + /// + [DiscordEnum("SEND_TTS_MESSAGES")] + SendTtsMessages = 1 << 12, + + /// + /// Allows for deletion of other users messages + /// Channel Type (Text) + /// + [DiscordEnum("MANAGE_MESSAGES")] + ManageMessages = 1 << 13, + + /// + /// Links sent by users with this permission will be auto-embedded + /// Channel Type (Text) + /// + [DiscordEnum("EMBED_LINKS")] + EmbedLinks = 1 << 14, + + /// + /// Allows for uploading images and files + /// Channel Type (Text) + /// + [DiscordEnum("ATTACH_FILES")] + AttachFiles = 1 << 15, + + /// + /// Allows for reading of message history + /// Channel Type (Text) + /// + [DiscordEnum("READ_MESSAGE_HISTORY")] + ReadMessageHistory = 1 << 16, + + /// + /// Allows for using the @everyone tag to notify all users in a channel, + /// and the @here tag to notify all online users in a channel + /// Channel Type (Text, Stage) + /// + [DiscordEnum("MENTION_EVERYONE")] + MentionEveryone = 1 << 17, + + /// + /// Allows the usage of custom emojis from other servers + /// Channel Type (Text) + /// + [DiscordEnum("USE_EXTERNAL_EMOJIS")] + UseExternalEmojis = 1 << 18, + + /// + /// Allows for viewing guild insights + /// + [DiscordEnum("VIEW_GUILD_INSIGHTS")] + ViewGuildInsights = 1 << 19, + + /// + /// Allows for joining of a voice channel + /// Channel Type (Voice, Stage) + /// + [DiscordEnum("CONNECT")] + Connect = 1 << 20, + + /// + /// Allows for speaking in a voice channel + /// Channel Type (Voice) + /// + [DiscordEnum("SPEAK")] + Speak = 1 << 21, + + /// + /// Allows for muting members in a voice channel + /// Channel Type (Voice, Stage) + /// + [DiscordEnum("MUTE_MEMBERS")] + MuteMembers = 1 << 22, + + /// + /// Allows for deafening of members in a voice channel + /// Channel Type (Voice, Stage) + /// + [DiscordEnum("DEAFEN_MEMBERS")] + DeafanMembers = 1 << 23, + + /// + /// Allows for moving of members between voice channels + /// Channel Type (Voice, Stage) + /// + [DiscordEnum("MOVE_MEMBERS")] + MoveMembers = 1 << 24, + + /// + /// Allows for using voice-activity-detection in a voice channel + /// Channel Type (Voice) + /// + [DiscordEnum("USE_VAD")] + UseVad = 1 << 25, + + /// + /// Allows for modification of own nickname + /// + [DiscordEnum("CHANGE_NICKNAME")] + ChangeNickname = 1 << 26, + + /// + /// Allows for modification of other users nicknames + /// + [DiscordEnum("MANAGE_NICKNAMES")] + ManageNicknames = 1 << 27, + + /// + /// Allows management and editing of roles + /// Channel Type (Text, Voice, Stage) + /// + [DiscordEnum("MANAGE_ROLES")] + ManageRoles = 1 << 28, + + /// + /// Allows management and editing of webhooks + /// Channel Type (Text) + /// + [DiscordEnum("MANAGE_WEBHOOKS")] + ManageWebhooks = 1 << 29, + + /// + /// Allows for editing and deleting emojis, stickers, and soundboard sounds created by all users + /// + [DiscordEnum("MANAGE_GUILD_EXPRESSIONS")] + ManageGuildExpressions = 1 << 30, + + /// + /// Allows management and editing of emojis + /// + [DiscordEnum("MANAGE_EMOJIS_AND_STICKERS")] + [Obsolete("Replace with ManageGuildExpressions")] + ManageEmojisAndStickers = 1 << 30, + + /// + /// Allows members to use application commands, including slash commands and context menu commands. + /// + [DiscordEnum("USE_APPLICATION_COMMANDS")] + UseSlashCommands = 1ul << 31, + + /// + /// Allows for requesting to speak in stage channels. + /// Channel Type (Stage) + /// (This permission is under active development and may be changed or removed.) + /// + [DiscordEnum("REQUEST_TO_SPEAK")] + RequestToSpeak = 1ul << 32, + + /// + /// Allows for editing and deleting scheduled events created by all users + /// Channel Type (Voice, Stage) + /// + [DiscordEnum("MANAGE_EVENTS")] + ManageEvents = 1ul << 33, + + /// + /// Allows for deleting and archiving threads, and viewing all private threads + /// Channel Type (Text) + /// + [DiscordEnum("MANAGE_THREADS")] + ManageThreads = 1ul << 34, + + /// + /// Allows for creating and participating in threads + /// Channel Type (Text) + /// + [Obsolete("This flag has been deprecated and will be removed in a future update. This flag is replaced by CreatePublicThreads")] + [DiscordEnum("USE_PUBLIC_THREADS")] + UsePublicThreads = 1ul << 35, + + /// + /// Allows for creating threads + /// Channel Type (Text) + /// + [DiscordEnum("CREATE_PUBLIC_THREADS")] + CreatePublicThreads = 1ul << 35, + + /// + /// Allows for creating and participating in private threads + /// Channel Type (Text) + /// + [Obsolete("This flag has been deprecated and will be removed in a future update. This flag is replaced by CreatePrivateThreads")] + [DiscordEnum("USE_PRIVATE_THREADS")] + UsePrivateThreads = 1ul << 36, + + /// + /// Allows for creating private threads + /// Channel Type (Text) + /// + [DiscordEnum("CREATE_PRIVATE_THREADS")] + CreatePrivateThreads = 1ul << 36, + + /// + /// Allows the usage of custom stickers from other servers + /// Channel Type (Text) + /// + [DiscordEnum("USE_EXTERNAL_STICKERS")] + UseExternalStickers = 1ul << 37, + + /// + /// Allows for sending messages in threads + /// Channel Type (Text) + /// + [DiscordEnum("SEND_MESSAGES_IN_THREADS")] + SendMessagesInThreads = 1ul << 38, + + /// + /// Allows for launching activities (applications with the `EMBEDDED` flag) in a voice channel + /// Channel Type (Voice) + /// + [Obsolete("Replaced with UseEmbeddedActivities")] + [DiscordEnum("START_EMBEDDED_ACTIVITIES")] + StartEmbeddedActivities = 1ul << 39, + + /// + /// Allows for using Activities (applications with the `EMBEDDED` flag) in a voice channel + /// Channel Type (Voice) + /// + [DiscordEnum("USE_EMBEDDED_ACTIVITIES")] + UseEmbeddedActivities = 1ul << 39, + + /// + /// Allows for timing out users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels + /// + [DiscordEnum("MODERATE_MEMBERS")] + ModerateMembers = 1ul << 40, + + /// + /// Allows for viewing role subscription insights + /// + [DiscordEnum("VIEW_CREATOR_MONETIZATION_ANALYTICS")] + ViewCreatorMonetizationAnalytics = 1ul << 41, + + /// + /// Allows for using soundboard in a voice channel + /// + [DiscordEnum("USE_SOUNDBOARD")] + UseSoundboard = 1ul << 42, + + /// + /// Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user + /// + [DiscordEnum("CREATE_GUILD_EXPRESSIONS")] + CreateGuildExpressions = 1ul << 43, + + /// + /// Allows for creating scheduled events, and editing and deleting those created by the current user + /// + [DiscordEnum("CREATE_EVENTS")] + CreateEvents = 1ul << 44, + + /// + /// Allows the usage of custom soundboard sounds from other servers + /// + [DiscordEnum("USE_EXTERNAL_SOUNDS")] + UseExternalSounds = 1ul << 45, + + /// + /// Allows sending voice messages + /// + [DiscordEnum("SEND_VOICE_MESSAGES")] + SendVoiceMessages = 1ul << 46, + + /// + /// Allows sending polls + /// + [DiscordEnum("USE_CLYDE_AI")] + UseClydeAi = 1ul << 47, + + /// + /// Allows sending polls + /// + [DiscordEnum("SEND_POLLS")] + SendPolls = 1ul << 49, + + /// + /// Allows user-installed apps to send public responses. When disabled, users will still be allowed to use their apps but the responses will be ephemeral. This only applies to apps not also installed to the server. + /// + [DiscordEnum("USE_EXTERNAL_APPS")] + UseExternalApps = 1ul << 50, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Permissions/RoleFlags.cs b/Oxide.Ext.Discord/Entities/Permissions/RoleFlags.cs index 40176cabe..f2f5c6510 100644 --- a/Oxide.Ext.Discord/Entities/Permissions/RoleFlags.cs +++ b/Oxide.Ext.Discord/Entities/Permissions/RoleFlags.cs @@ -1,21 +1,20 @@ using System; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Role Flags +/// +[Flags] +public enum RoleFlags { /// - /// Represents Role Flags + /// No Role Flags /// - [Flags] - public enum RoleFlags - { - /// - /// No Role Flags - /// - None = 0, + None = 0, - /// - /// Role can be selected by members in an onboarding - /// - InPrompt = 1 << 0 - } + /// + /// Role can be selected by members in an onboarding + /// + InPrompt = 1 << 0 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Permissions/RoleSubscription.cs b/Oxide.Ext.Discord/Entities/Permissions/RoleSubscription.cs index 0114e7496..31ec3d081 100644 --- a/Oxide.Ext.Discord/Entities/Permissions/RoleSubscription.cs +++ b/Oxide.Ext.Discord/Entities/Permissions/RoleSubscription.cs @@ -1,35 +1,34 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Role Subscription Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class RoleSubscription { /// - /// Represents Role Subscription Structure + /// The id of the sku and listing that the user is subscribed to /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class RoleSubscription - { - /// - /// The id of the sku and listing that the user is subscribed to - /// - [JsonProperty("role_subscription_listing_id")] - public Snowflake RoleSubscriptionListingId { get; set; } + [JsonProperty("role_subscription_listing_id")] + public Snowflake RoleSubscriptionListingId { get; set; } - /// - /// The name of the tier that the user is subscribed to - /// - [JsonProperty("tier_name")] - public string TierName { get; set; } + /// + /// The name of the tier that the user is subscribed to + /// + [JsonProperty("tier_name")] + public string TierName { get; set; } - /// - /// The cumulative number of months that the user has been subscribed for - /// - [JsonProperty("total_months_subscribed")] - public int TotalMonthsSubscribed { get; set; } + /// + /// The cumulative number of months that the user has been subscribed for + /// + [JsonProperty("total_months_subscribed")] + public int TotalMonthsSubscribed { get; set; } - /// - /// Whether this notification is for a renewal rather than a new purchase - /// - [JsonProperty("is_renewal")] - public bool IsRenewal { get; set; } - } + /// + /// Whether this notification is for a renewal rather than a new purchase + /// + [JsonProperty("is_renewal")] + public bool IsRenewal { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Permissions/RoleTags.cs b/Oxide.Ext.Discord/Entities/Permissions/RoleTags.cs index e17592142..33e1b2680 100644 --- a/Oxide.Ext.Discord/Entities/Permissions/RoleTags.cs +++ b/Oxide.Ext.Discord/Entities/Permissions/RoleTags.cs @@ -1,49 +1,48 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Role Tags Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +[JsonConverter(typeof(RoleTagsConverter))] +public class RoleTags { /// - /// Represents Role Tags Structure + /// The id of the bot this role belongs to /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - [JsonConverter(typeof(RoleTagsConverter))] - public class RoleTags - { - /// - /// The id of the bot this role belongs to - /// - [JsonProperty("bot_id")] - public Snowflake? BotId { get; set; } + [JsonProperty("bot_id")] + public Snowflake? BotId { get; set; } - /// - /// The id of the integration this role belongs to - /// - [JsonProperty("integration_id")] - public Snowflake? IntegrationId { get; set; } + /// + /// The id of the integration this role belongs to + /// + [JsonProperty("integration_id")] + public Snowflake? IntegrationId { get; set; } - /// - /// Whether this is the guild's premium subscriber role - /// - [JsonProperty("premium_subscriber")] - public bool PremiumSubscriber { get; set; } + /// + /// Whether this is the guild's premium subscriber role + /// + [JsonProperty("premium_subscriber")] + public bool PremiumSubscriber { get; set; } - /// - /// The id of this role's subscription sku and listing - /// - [JsonProperty("subscription_listing_id")] - public Snowflake? SubscriptionListingId { get; set; } + /// + /// The id of this role's subscription sku and listing + /// + [JsonProperty("subscription_listing_id")] + public Snowflake? SubscriptionListingId { get; set; } - /// - /// whether this role is available for purchase - /// - [JsonProperty("available_for_purchase")] - public bool AvailableForPurchase { get; set; } + /// + /// whether this role is available for purchase + /// + [JsonProperty("available_for_purchase")] + public bool AvailableForPurchase { get; set; } - /// - /// Whether this role is a guild's linked role - /// - [JsonProperty("guild_connections")] - public bool GuildConnections { get; set; } - } + /// + /// Whether this role is a guild's linked role + /// + [JsonProperty("guild_connections")] + public bool GuildConnections { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Snowflake.cs b/Oxide.Ext.Discord/Entities/Snowflake.cs index 980864f5a..56de1028c 100644 --- a/Oxide.Ext.Discord/Entities/Snowflake.cs +++ b/Oxide.Ext.Discord/Entities/Snowflake.cs @@ -4,277 +4,294 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents an ID in discord. +/// +[JsonConverter(typeof(SnowflakeConverter))] +public readonly struct Snowflake : IComparable, IEquatable, IComparable, IEquatable, IDiscordKey { /// - /// Represents an ID in discord. + /// DateTimeOffset since discord Epoch /// - [JsonConverter(typeof(SnowflakeConverter))] - public struct Snowflake : IComparable, IEquatable, IComparable, IEquatable, IDiscordKey - { - /// - /// DateTimeOffset since discord Epoch - /// - public static readonly DateTimeOffset DiscordEpoch = new DateTimeOffset(2015, 1, 1, 0, 0, 0, TimeSpan.Zero); + public static readonly DateTimeOffset DiscordEpoch = new(2015, 1, 1, 0, 0, 0, TimeSpan.Zero); - /// - /// Snowflake Value - /// - public readonly ulong Id; + /// + /// Snowflake Value + /// + public readonly ulong Id; - /// - /// Create a new snowflake from a ulong - /// - /// - public Snowflake(ulong id) - { - Id = id; - } + /// + /// Create a new snowflake from a ulong + /// + /// + public Snowflake(ulong id) + { + Id = id; + } - /// - /// Create a new snowflake from a string - /// - /// - public Snowflake(string id): this(ulong.Parse(id)) {} + /// + /// Create a new snowflake from a string + /// + /// + public Snowflake(string id): this(ulong.Parse(id)) {} - /// - /// Create a new snowflake from a - /// - /// - public Snowflake(ReadOnlySpan span) : this(ulong.Parse(span)) {} + /// + /// Create a new snowflake from a + /// + /// + public Snowflake(ReadOnlySpan span) : this(ulong.Parse(span)) {} - /// - /// Create a snowflake from a DateTimeOffset and increment - /// - /// - /// Increment value of the snowflake - public Snowflake(DateTimeOffset offset, ulong increment = 0) - { - Id = ((ulong)(DiscordEpoch - offset).TotalMilliseconds << 22) + increment; - } + /// + /// Create a snowflake from a DateTimeOffset and increment + /// + /// + /// Increment value of the snowflake + public Snowflake(DateTimeOffset offset, ulong increment = 0) + { + Id = ((ulong)(DiscordEpoch - offset).TotalMilliseconds << 22) + increment; + } - /// - /// Returns when the ID was created - /// - /// - public DateTimeOffset GetCreationDate() - { - return DiscordEpoch + TimeSpan.FromMilliseconds(Id >> 22); - } + /// + /// Returns when the ID was created + /// + /// + public DateTimeOffset GetCreationDate() + { + return DiscordEpoch + TimeSpan.FromMilliseconds(Id >> 22); + } - /// - /// Returns if the ID value is not 0 - /// - /// - public bool IsValid() - { - return Id != 0; - } + /// + /// Returns if the ID value is not 0 + /// + /// + public bool IsValid() + { + return Id != 0; + } - /// - /// Try to parse the a string into a snowflake value - /// - /// String to parse - /// Snowflake to return - /// True if parse succeeded; false otherwise - public static bool TryParse(string value, out Snowflake snowflake) + /// + /// Try to parse the a string into a snowflake value + /// + /// String to parse + /// Snowflake to return + /// True if parse succeeded; false otherwise + public static bool TryParse(string value, out Snowflake snowflake) + { + if(ulong.TryParse(value, out ulong id)) { - if(ulong.TryParse(value, out ulong id)) - { - snowflake = new Snowflake(id); - return true; - } - - snowflake = default(Snowflake); - return false; + snowflake = new Snowflake(id); + return true; } - /// - /// Try to format the snowflake into the span - /// - /// Span to write the snowflake into - /// Number of characters written - /// Snowflake formatting - /// - /// - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default (ReadOnlySpan), IFormatProvider provider = null) + snowflake = default; + return false; + } + + /// + /// Try to parse the a string into a snowflake value + /// + /// String to parse + /// Snowflake to return + /// True if parse succeeded; false otherwise + public static bool TryParse(ReadOnlySpan value, out Snowflake snowflake) + { + if(ulong.TryParse(value, out ulong id)) { - return Id.TryFormat(destination, out charsWritten, format, provider); + snowflake = new Snowflake(id); + return true; } - /// - /// Returns if the two snowflakes are the same ID. - /// - /// Other snowflake to compare - /// True if the snowflake IDs match; false otherwise. - public bool Equals(Snowflake other) - { - return Id == other.Id; - } - - /// - /// Returns if the obj is snowflake or ulong with matching ID. - /// - /// Object to check - /// True if equal; False otherwise - public override bool Equals(object obj) - { - if (obj is Snowflake snowflake) - { - return Equals(snowflake); - } + snowflake = default; + return false; + } - if (obj is ulong id) - { - return Equals(id); - } + /// + /// Try to format the snowflake into the span + /// + /// Span to write the snowflake into + /// Number of characters written + /// Snowflake formatting + /// + /// + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider provider = null) + { + return Id.TryFormat(destination, out charsWritten, format, provider); + } - return false; - } + /// + /// Returns if the two snowflakes are the same ID. + /// + /// Other snowflake to compare + /// True if the snowflake IDs match; false otherwise. + public bool Equals(Snowflake other) + { + return Id == other.Id; + } - /// - /// Returns if other equals our ID - /// - /// Other to compare against - /// True if ID equals; False otherwise. - public bool Equals(ulong other) + /// + /// Returns if the obj is snowflake or ulong with matching ID. + /// + /// Object to check + /// True if equal; False otherwise + public override bool Equals(object obj) + { + if (obj is Snowflake snowflake) { - return Id == other; + return Equals(snowflake); } - /// - /// Returns the HashCode of the ID - /// - /// ID fields hashcode - public override int GetHashCode() + if (obj is ulong id) { - return Id.GetHashCode(); + return Equals(id); } - /// - /// Returns ID as a string - /// - /// ID as a string - public override string ToString() - { - return StringCache.Instance.ToString(Id); - } + return false; + } + + /// + /// Returns if other equals our ID + /// + /// Other to compare against + /// True if ID equals; False otherwise. + public bool Equals(ulong other) + { + return Id == other; + } - /// - /// Returns the ID field of num compared to this snowflakes ID field - /// - /// Value to compare ID to - /// A value indication if the num is less than, equal to, or greater than our ID - public int CompareTo(Snowflake num) - { - return Id.CompareTo(num.Id); - } + /// + /// Returns the HashCode of the ID + /// + /// ID fields hashcode + public override int GetHashCode() + { + return Id.GetHashCode(); + } + + /// + /// Returns ID as a string + /// + /// ID as a string + public override string ToString() + { + return StringCache.Instance.ToString(Id); + } + + /// + /// Returns the ID field of num compared to this snowflakes ID field + /// + /// Value to compare ID to + /// A value indication if the num is less than, equal to, or greater than our ID + public int CompareTo(Snowflake num) + { + return Id.CompareTo(num.Id); + } - /// - /// Returns the ID field of num compared to this snowflakes ID field - /// - /// Value to compare ID to - /// A value indication if the num is less than, equal to, or greater than our ID - public int CompareTo(ulong other) - { - return Id.CompareTo(other); - } + /// + /// Returns the ID field of num compared to this snowflakes ID field + /// + /// Value to compare ID to + /// A value indication if the num is less than, equal to, or greater than our ID + public int CompareTo(ulong other) + { + return Id.CompareTo(other); + } - /// - /// Returns true if left and right are equal - /// - /// Snowflake to compare - /// Snowflake to compare - /// True if the snowflake ID's are equal; false otherwise - public static bool operator == (Snowflake left, Snowflake right) - { - return left.Id == right.Id; - } + /// + /// Returns true if left and right are equal + /// + /// Snowflake to compare + /// Snowflake to compare + /// True if the snowflake ID's are equal; false otherwise + public static bool operator == (Snowflake left, Snowflake right) + { + return left.Id == right.Id; + } - /// - /// Returns true if left and right are not equal - /// - /// Snowflake to compare - /// Snowflake to compare - /// True if the snowflake ID's are not equal; false otherwise - public static bool operator !=(Snowflake left, Snowflake right) - { - return !(left == right); - } + /// + /// Returns true if left and right are not equal + /// + /// Snowflake to compare + /// Snowflake to compare + /// True if the snowflake ID's are not equal; false otherwise + public static bool operator !=(Snowflake left, Snowflake right) + { + return !(left == right); + } - /// - /// Returns true if left snowflake's ID is less than right's ID - /// - /// Snowflake to be less than - /// Snowflake to be greater than - /// True if left is less than right - public static bool operator <(Snowflake left, Snowflake right) - { - return left.CompareTo(right) < 0; - } + /// + /// Returns true if left snowflake's ID is less than right's ID + /// + /// Snowflake to be less than + /// Snowflake to be greater than + /// True if left is less than right + public static bool operator <(Snowflake left, Snowflake right) + { + return left.CompareTo(right) < 0; + } - /// - /// Returns true if left snowflake's ID is greater than right's ID - /// - /// Snowflake to be greater than - /// Snowflake to be less than - /// True if left is greater than right - public static bool operator >(Snowflake left, Snowflake right) - { - return left.CompareTo(right) > 0; - } + /// + /// Returns true if left snowflake's ID is greater than right's ID + /// + /// Snowflake to be greater than + /// Snowflake to be less than + /// True if left is greater than right + public static bool operator >(Snowflake left, Snowflake right) + { + return left.CompareTo(right) > 0; + } - /// - /// Returns true if left snowflake's ID is less than right's ID or equal - /// - /// Snowflake to be less than or equal - /// Snowflake to be greater than or equal - /// True if left is less than or equal to right - public static bool operator <=(Snowflake left, Snowflake right) - { - return left.CompareTo(right) <= 0; - } + /// + /// Returns true if left snowflake's ID is less than right's ID or equal + /// + /// Snowflake to be less than or equal + /// Snowflake to be greater than or equal + /// True if left is less than or equal to right + public static bool operator <=(Snowflake left, Snowflake right) + { + return left.CompareTo(right) <= 0; + } - /// - /// Returns true if left snowflake's ID is greater or equal to right's ID - /// - /// Snowflake to be greater than or equal - /// Snowflake to be less than or equal - /// True if left is greater or equal to right - public static bool operator >=(Snowflake left, Snowflake right) - { - return left.CompareTo(right) >= 0; - } + /// + /// Returns true if left snowflake's ID is greater or equal to right's ID + /// + /// Snowflake to be greater than or equal + /// Snowflake to be less than or equal + /// True if left is greater or equal to right + public static bool operator >=(Snowflake left, Snowflake right) + { + return left.CompareTo(right) >= 0; + } - /// - /// Converts snowflake to a ulong - /// - /// Snowflake to be converted to ulong - /// Snowflake ID as ulong - public static implicit operator ulong(Snowflake snowflake) => snowflake.Id; + /// + /// Converts snowflake to a ulong + /// + /// Snowflake to be converted to ulong + /// Snowflake ID as ulong + public static implicit operator ulong(Snowflake snowflake) => snowflake.Id; - /// - /// Converts a ulong to a snowflake - /// - /// Id to be converted to snowflake - /// ID converted to a snowflake - public static explicit operator Snowflake(ulong id) => new Snowflake(id); + /// + /// Converts a ulong to a snowflake + /// + /// Id to be converted to snowflake + /// ID converted to a snowflake + public static explicit operator Snowflake(ulong id) => new(id); - /// - /// Converts snowflake to a string - /// - /// Snowflake to be converted to string - /// Snowflake ID as string - public static implicit operator string(Snowflake snowflake) => snowflake.Id.ToString(); + /// + /// Converts snowflake to a string + /// + /// Snowflake to be converted to string + /// Snowflake ID as string + public static implicit operator string(Snowflake snowflake) => snowflake.Id.ToString(); - /// - /// Converts a string to a snowflake - /// - /// Id to be converted to snowflake - /// ID converted to a snowflake - public static explicit operator Snowflake(string id) - { - return TryParse(id, out Snowflake snowflake) ? snowflake : default(Snowflake); - } + /// + /// Converts a string to a snowflake + /// + /// Id to be converted to snowflake + /// ID converted to a snowflake + public static explicit operator Snowflake(string id) + { + return TryParse(id, out Snowflake snowflake) ? snowflake : default; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Stickers/DiscordSticker.cs b/Oxide.Ext.Discord/Entities/Stickers/DiscordSticker.cs index c5ab8553a..d93a8c25d 100644 --- a/Oxide.Ext.Discord/Entities/Stickers/DiscordSticker.cs +++ b/Oxide.Ext.Discord/Entities/Stickers/DiscordSticker.cs @@ -4,130 +4,129 @@ using Oxide.Ext.Discord.Helpers; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Sticker Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordSticker : ISnowflakeEntity { /// - /// Represents a Discord Sticker Structure + /// ID of the sticker /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordSticker : ISnowflakeEntity - { - /// - /// ID of the sticker - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// ID of the pack the sticker is from - /// - [JsonProperty("pack_id")] - public Snowflake? PackId { get; set; } + /// + /// ID of the pack the sticker is from + /// + [JsonProperty("pack_id")] + public Snowflake? PackId { get; set; } - /// - /// Name of the sticker - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the sticker + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Description of the sticker - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of the sticker + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// For guild stickers, a unicode emoji representing the sticker's expression. - /// For nitro stickers, a comma-separated list of related expressions. - /// autocomplete/suggestion tags for the sticker (max 200 characters) - /// - [JsonProperty("tags")] - public string Tags { get; set; } + /// + /// For guild stickers, a unicode emoji representing the sticker's expression. + /// For nitro stickers, a comma-separated list of related expressions. + /// autocomplete/suggestion tags for the sticker (max 200 characters) + /// + [JsonProperty("tags")] + public string Tags { get; set; } - /// - /// Type of sticker. - /// - [JsonProperty("type")] - public StickerType Type { get; set; } + /// + /// Type of sticker. + /// + [JsonProperty("type")] + public StickerType Type { get; set; } - /// - /// Type of sticker format - /// - /// - [JsonProperty("format_type")] - public StickerFormatType FormatType { get; set; } + /// + /// Type of sticker format + /// + /// + [JsonProperty("format_type")] + public StickerFormatType FormatType { get; set; } - /// - /// Whether or not the sticker is available - /// - [JsonProperty("available")] - public bool? Available { get; set; } + /// + /// Whether or not the sticker is available + /// + [JsonProperty("available")] + public bool? Available { get; set; } - /// - /// Id of the guild that owns this sticker - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// Id of the guild that owns this sticker + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// The user that uploaded the sticker - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } + /// + /// The user that uploaded the sticker + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } - /// - /// A sticker's sort order within a pack - /// - [JsonProperty("sort_value")] - public int? SortValue { get; set; } + /// + /// A sticker's sort order within a pack + /// + [JsonProperty("sort_value")] + public int? SortValue { get; set; } - /// - /// Returns the Url for the sticker - /// - public string StickerUrl => DiscordCdn.GetSticker(this); + /// + /// Returns the Url for the sticker + /// + public string StickerUrl => DiscordCdn.GetSticker(this); - /// - /// Returns a sticker object for the given sticker ID. - /// See Get Sticker - /// - /// Client to use - /// ID of the sticker - public static IPromise Get(DiscordClient client, Snowflake stickerId) - { - InvalidSnowflakeException.ThrowIfInvalid(stickerId, nameof(stickerId)); - return client.Bot.Rest.Get(client,$"stickers/{stickerId}"); - } + /// + /// Returns a sticker object for the given sticker ID. + /// See Get Sticker + /// + /// Client to use + /// ID of the sticker + public static IPromise Get(DiscordClient client, Snowflake stickerId) + { + InvalidSnowflakeException.ThrowIfInvalid(stickerId); + return client.Bot.Rest.Get(client,$"stickers/{stickerId}"); + } - /// - /// Modify the given sticker. - /// Requires the MANAGE_EMOJIS_AND_STICKERS permission. - /// Returns the updated sticker object on success. - /// See Modify Guild Sticker - /// - /// Client to use - public IPromise ModifyGuildSticker(DiscordClient client) - { - InvalidGuildStickerException.ThrowIfNotGuildType(Type, "This endpoint can only be used for guild stickers"); - return client.Bot.Rest.Patch(client,$"guilds/{GuildId}/stickers/{Id}", this); - } + /// + /// Modify the given sticker. + /// Requires the MANAGE_EMOJIS_AND_STICKERS permission. + /// Returns the updated sticker object on success. + /// See Modify Guild Sticker + /// + /// Client to use + public IPromise ModifyGuildSticker(DiscordClient client) + { + InvalidGuildStickerException.ThrowIfNotGuildType(Type, "This endpoint can only be used for guild stickers"); + return client.Bot.Rest.Patch(client,$"guilds/{GuildId}/stickers/{Id}", this); + } - /// - /// Delete the given sticker. - /// Requires the MANAGE_EMOJIS_AND_STICKERS permission. - /// See Delete Guild Sticker - /// - /// Client to use - public IPromise DeleteGuildSticker(DiscordClient client) - { - InvalidGuildStickerException.ThrowIfNotGuildType(Type, "This endpoint can only be used for guild stickers"); - return client.Bot.Rest.Delete(client,$"guilds/{GuildId}/stickers/{Id}"); - } + /// + /// Delete the given sticker. + /// Requires the MANAGE_EMOJIS_AND_STICKERS permission. + /// See Delete Guild Sticker + /// + /// Client to use + public IPromise DeleteGuildSticker(DiscordClient client) + { + InvalidGuildStickerException.ThrowIfNotGuildType(Type, "This endpoint can only be used for guild stickers"); + return client.Bot.Rest.Delete(client,$"guilds/{GuildId}/stickers/{Id}"); + } - internal void Update(DiscordSticker sticker) - { - if (sticker.Name != null) Name = sticker.Name; - if (sticker.Description != null) Description = sticker.Description; - if (sticker.Tags != null) Tags = sticker.Tags; - } + internal void Update(DiscordSticker sticker) + { + if (sticker.Name != null) Name = sticker.Name; + if (sticker.Description != null) Description = sticker.Description; + if (sticker.Tags != null) Tags = sticker.Tags; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Stickers/DiscordStickerPack.cs b/Oxide.Ext.Discord/Entities/Stickers/DiscordStickerPack.cs index 759ee5709..105725896 100644 --- a/Oxide.Ext.Discord/Entities/Stickers/DiscordStickerPack.cs +++ b/Oxide.Ext.Discord/Entities/Stickers/DiscordStickerPack.cs @@ -3,64 +3,63 @@ using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Sticker Pack Object +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordStickerPack { /// - /// Represents a Sticker Pack Object + /// ID of the sticker pack /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordStickerPack - { - /// - /// ID of the sticker pack - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The stickers in the pack - /// - [JsonProperty("stickers")] - public List Stickers { get; set; } + /// + /// The stickers in the pack + /// + [JsonProperty("stickers")] + public List Stickers { get; set; } - /// - /// Name of the sticker pack - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the sticker pack + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// ID of the pack's SKU - /// - [JsonProperty("sku_id")] - public Snowflake SkuId { get; set; } + /// + /// ID of the pack's SKU + /// + [JsonProperty("sku_id")] + public Snowflake SkuId { get; set; } - /// - /// ID of a sticker in the pack which is shown as the pack's icon - /// - [JsonProperty("cover_sticker_id")] - public Snowflake? CoverStickerId { get; set; } + /// + /// ID of a sticker in the pack which is shown as the pack's icon + /// + [JsonProperty("cover_sticker_id")] + public Snowflake? CoverStickerId { get; set; } - /// - /// Description of the sticker pack - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of the sticker pack + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// ID of the sticker pack's banner image - /// - [JsonProperty("banner_asset_id")] - public Snowflake? BannerAssetId { get; set; } + /// + /// ID of the sticker pack's banner image + /// + [JsonProperty("banner_asset_id")] + public Snowflake? BannerAssetId { get; set; } - /// - /// Returns the list of sticker packs available to Nitro subscribers. - /// See List Nitro Sticker Packs - /// - /// Client to use - public static IPromise> GetStickerPacks(DiscordClient client) - { - return client.Bot.Rest.Get>(client,"sticker-packs"); - } + /// + /// Returns the list of sticker packs available to Nitro subscribers. + /// See List Nitro Sticker Packs + /// + /// Client to use + public static IPromise> GetStickerPacks(DiscordClient client) + { + return client.Bot.Rest.Get>(client,"sticker-packs"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Stickers/GuildStickerCreate.cs b/Oxide.Ext.Discord/Entities/Stickers/GuildStickerCreate.cs index 3734d5f97..1ac832179 100644 --- a/Oxide.Ext.Discord/Entities/Stickers/GuildStickerCreate.cs +++ b/Oxide.Ext.Discord/Entities/Stickers/GuildStickerCreate.cs @@ -4,68 +4,67 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Sticker Pack Object +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class GuildStickerCreate : IFileAttachments, IDiscordValidation { /// - /// Represents a Sticker Pack Object + /// Name of the sticker (2-30 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class GuildStickerCreate : IFileAttachments, IDiscordValidation - { - /// - /// Name of the sticker (2-30 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Description of the sticker (empty or 2-100 characters) - /// - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Description of the sticker (empty or 2-100 characters) + /// + [JsonProperty("description")] + public string Description { get; set; } - /// - /// Autocomplete/suggestion tags for the sticker (max 200 characters) - /// Each tag should be seperated by a command and space IE ', ' - /// - [JsonProperty("tags")] - public string Tags { get; set; } + /// + /// Autocomplete/suggestion tags for the sticker (max 200 characters) + /// Each tag should be seperated by a command and space IE ', ' + /// + [JsonProperty("tags")] + public string Tags { get; set; } - /// - /// Sticker image attachment - /// - public List FileAttachments { get; set; } + /// + /// Sticker image attachment + /// + public List FileAttachments { get; set; } - /// - /// Adds the sticker for guild sticker create - /// - /// Name of the file - /// Content type of the file - /// sticker image bytes - /// - /// Throw if more than 1 sticker is added. - /// Thrown if the data is more than 500KB - /// Thrown if the file extension is not .png, .apng, .gif, or .json - /// - public void AddSticker(string fileName, string contentType, byte[] sticker) + /// + /// Adds the sticker for guild sticker create + /// + /// Name of the file + /// Content type of the file + /// sticker image bytes + /// + /// Throw if more than 1 sticker is added. + /// Thrown if the data is more than 500KB + /// Thrown if the file extension is not .png, .apng, .gif, or .json + /// + public void AddSticker(string fileName, string contentType, byte[] sticker) + { + if (FileAttachments == null) { - if (FileAttachments == null) - { - FileAttachments = new List(); - } + FileAttachments = new List(); + } - InvalidGuildStickerException.ThrowIfMoreThanOneImage(FileAttachments.Count); - InvalidGuildStickerException.ThrowIfImageTooLarge(sticker); - InvalidGuildStickerException.ThrowIfInvalidFileExtension(fileName); + InvalidGuildStickerException.ThrowIfMoreThanOneImage(FileAttachments.Count); + InvalidGuildStickerException.ThrowIfImageTooLarge(sticker); + InvalidGuildStickerException.ThrowIfInvalidFileExtension(fileName); - FileAttachments.Add(new MessageFileAttachment(fileName, sticker, contentType)); - } + FileAttachments.Add(new MessageFileAttachment(fileName, sticker, contentType)); + } - /// - public void Validate() - { - InvalidGuildStickerException.ThrowIfInvalidName(Name, false); - InvalidGuildStickerException.ThrowIfInvalidDescription(Description, false); - } + /// + public void Validate() + { + InvalidGuildStickerException.ThrowIfInvalidName(Name, false); + InvalidGuildStickerException.ThrowIfInvalidDescription(Description, false); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Stickers/StickerFormatType.cs b/Oxide.Ext.Discord/Entities/Stickers/StickerFormatType.cs index cfe993fe7..18d703ea4 100644 --- a/Oxide.Ext.Discord/Entities/Stickers/StickerFormatType.cs +++ b/Oxide.Ext.Discord/Entities/Stickers/StickerFormatType.cs @@ -1,34 +1,33 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Sticker Format Types +/// +public enum StickerFormatType : byte { /// - /// Represents Sticker Format Types + /// Sticker format type PNG /// - public enum StickerFormatType : byte - { - /// - /// Sticker format type PNG - /// - [DiscordEnum("PNG")] - Png = 1, + [DiscordEnum("PNG")] + Png = 1, - /// - /// Sticker format type APNG - /// - [DiscordEnum("APNG")] - Apng = 2, + /// + /// Sticker format type APNG + /// + [DiscordEnum("APNG")] + Apng = 2, - /// - /// Sticker format type LOTTIE - /// - [DiscordEnum("LOTTIE")] - Lottie = 3, + /// + /// Sticker format type LOTTIE + /// + [DiscordEnum("LOTTIE")] + Lottie = 3, - /// - /// Sticker format type GIF - /// - [DiscordEnum("GIF")] - Gif = 4 - } + /// + /// Sticker format type GIF + /// + [DiscordEnum("GIF")] + Gif = 4 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Stickers/StickerType.cs b/Oxide.Ext.Discord/Entities/Stickers/StickerType.cs index e2e340eec..a6a15635f 100644 --- a/Oxide.Ext.Discord/Entities/Stickers/StickerType.cs +++ b/Oxide.Ext.Discord/Entities/Stickers/StickerType.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Sticker Types +/// +public enum StickerType : byte { /// - /// Represents a Sticker Types + /// An official sticker in a pack /// - public enum StickerType : byte - { - /// - /// An official sticker in a pack - /// - Standard = 1, + Standard = 1, - /// - /// A sticker uploaded to a guild for the guild's members - /// - Guild = 2 - } + /// + /// A sticker uploaded to a guild for the guild's members + /// + Guild = 2 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Teams/DiscordTeam.cs b/Oxide.Ext.Discord/Entities/Teams/DiscordTeam.cs index cb47eeb49..ff9ed7647 100644 --- a/Oxide.Ext.Discord/Entities/Teams/DiscordTeam.cs +++ b/Oxide.Ext.Discord/Entities/Teams/DiscordTeam.cs @@ -2,54 +2,53 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Helpers; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Team Object +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordTeam { /// - /// Represents a Team Object + /// Unique ID of the team /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordTeam - { - /// - /// Unique ID of the team - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Hash of the image of the team's icon - /// - [JsonProperty("icon")] - public string Icon { get; set; } + /// + /// Hash of the image of the team's icon + /// + [JsonProperty("icon")] + public string Icon { get; set; } - /// - /// Members of the team - /// See - /// - [JsonProperty("members")] - public List Members { get; set; } + /// + /// Members of the team + /// See + /// + [JsonProperty("members")] + public List Members { get; set; } - /// - /// Name of the team - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the team + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// User ID of the current team owner - /// - [JsonProperty("owner_user_id")] - public Snowflake OwnerUserId { get; set; } + /// + /// User ID of the current team owner + /// + [JsonProperty("owner_user_id")] + public Snowflake OwnerUserId { get; set; } - /// - /// Role of the team member - /// - [JsonProperty("role")] - public TeamRole Role { get; set; } + /// + /// Role of the team member + /// + [JsonProperty("role")] + public TeamRole Role { get; set; } - /// - /// Returns the url for the team icon - /// - public string GetTeamIconUrl => DiscordCdn.GetTeamIconUrl(Id, Icon); - } + /// + /// Returns the url for the team icon + /// + public string GetTeamIconUrl => DiscordCdn.GetTeamIconUrl(Id, Icon); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Teams/TeamMember.cs b/Oxide.Ext.Discord/Entities/Teams/TeamMember.cs index f29c8679f..122918f9a 100644 --- a/Oxide.Ext.Discord/Entities/Teams/TeamMember.cs +++ b/Oxide.Ext.Discord/Entities/Teams/TeamMember.cs @@ -1,37 +1,36 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Team Members Object +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class TeamMember { /// - /// Represents Team Members Object + /// The user's membership state on the team /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class TeamMember - { - /// - /// The user's membership state on the team - /// - [JsonProperty("membership_state")] - public TeamMembershipState MembershipState { get; set; } + [JsonProperty("membership_state")] + public TeamMembershipState MembershipState { get; set; } - /// - /// The teams permissions - /// Will always be ["*"] - /// - [JsonProperty("permissions")] - public List Permissions { get; set; } + /// + /// The teams permissions + /// Will always be ["*"] + /// + [JsonProperty("permissions")] + public List Permissions { get; set; } - /// - /// The id of the parent team of which they are a member - /// - [JsonProperty("team_id")] - public Snowflake TeamId { get; set; } + /// + /// The id of the parent team of which they are a member + /// + [JsonProperty("team_id")] + public Snowflake TeamId { get; set; } - /// - /// The avatar, discriminator, id, and username of the user - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } - } + /// + /// The avatar, discriminator, id, and username of the user + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Teams/TeamMembershipState.cs b/Oxide.Ext.Discord/Entities/Teams/TeamMembershipState.cs index 41c4518e2..a7f65454d 100644 --- a/Oxide.Ext.Discord/Entities/Teams/TeamMembershipState.cs +++ b/Oxide.Ext.Discord/Entities/Teams/TeamMembershipState.cs @@ -1,22 +1,21 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Membership State Enum +/// +public enum TeamMembershipState : byte { /// - /// Represents Membership State Enum + /// If the user has been invited /// - public enum TeamMembershipState : byte - { - /// - /// If the user has been invited - /// - [DiscordEnum("INVITED")] - Invited = 1, + [DiscordEnum("INVITED")] + Invited = 1, - /// - /// If the is part of the team - /// - [DiscordEnum("ACCEPTED")] - Accepted = 2 - } + /// + /// If the is part of the team + /// + [DiscordEnum("ACCEPTED")] + Accepted = 2 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Teams/TeamRole.cs b/Oxide.Ext.Discord/Entities/Teams/TeamRole.cs index 4e90483dc..e12802e8d 100644 --- a/Oxide.Ext.Discord/Entities/Teams/TeamRole.cs +++ b/Oxide.Ext.Discord/Entities/Teams/TeamRole.cs @@ -2,36 +2,35 @@ using Oxide.Ext.Discord.Attributes; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Team Role Types +/// +[JsonConverter(typeof(DiscordEnumConverter))] +public enum TeamRole : byte { /// - /// Represents Team Role Types + /// Owners are the most permissible role, and can take destructive, irreversible actions like deleting team-owned apps or the team itself. Teams are limited to 1 owner. /// - [JsonConverter(typeof(DiscordEnumConverter))] - public enum TeamRole : byte - { - /// - /// Owners are the most permissible role, and can take destructive, irreversible actions like deleting team-owned apps or the team itself. Teams are limited to 1 owner. - /// - [DiscordEnum("")] - Owner, + [DiscordEnum("")] + Owner, - /// - /// Admins have similar access as owners, except they cannot take destructive actions on the team or team-owned apps. - /// - [DiscordEnum("admin")] - Admin, + /// + /// Admins have similar access as owners, except they cannot take destructive actions on the team or team-owned apps. + /// + [DiscordEnum("admin")] + Admin, - /// - /// Developers can access information about team-owned apps, like the client secret or public key. They can also take limited actions on team-owned apps, like configuring interaction endpoints or resetting the bot token. Members with the Developer role cannot manage the team or its members, or take destructive actions on team-owned apps. - /// - [DiscordEnum("developer")] - Developer, + /// + /// Developers can access information about team-owned apps, like the client secret or public key. They can also take limited actions on team-owned apps, like configuring interaction endpoints or resetting the bot token. Members with the Developer role cannot manage the team or its members, or take destructive actions on team-owned apps. + /// + [DiscordEnum("developer")] + Developer, - /// - /// Read-only members can access information about a team and any team-owned apps. Some examples include getting the IDs of applications and exporting payout records. - /// - [DiscordEnum("read_only")] - ReadOnly - } + /// + /// Read-only members can access information about a team and any team-owned apps. Some examples include getting the IDs of applications and exporting payout records. + /// + [DiscordEnum("read_only")] + ReadOnly } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Users/AvatarDecorationData.cs b/Oxide.Ext.Discord/Entities/Users/AvatarDecorationData.cs new file mode 100644 index 000000000..7bb58cacd --- /dev/null +++ b/Oxide.Ext.Discord/Entities/Users/AvatarDecorationData.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Avatar Decoration Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class AvatarDecorationData +{ + /// + /// The avatar decoration hash + /// + [JsonProperty("asset")] + public string Asset { get; set; } + + /// + /// Id of the avatar decoration's SKU + /// + [JsonProperty("sku_id")] + public Snowflake SkuId { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Users/Connections/Connection.cs b/Oxide.Ext.Discord/Entities/Users/Connections/Connection.cs index 82ebefb6b..19d7cf5f3 100644 --- a/Oxide.Ext.Discord/Entities/Users/Connections/Connection.cs +++ b/Oxide.Ext.Discord/Entities/Users/Connections/Connection.cs @@ -2,76 +2,75 @@ using Oxide.Ext.Discord.Json; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Discord Users Connection +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class Connection { /// - /// Represents a Discord Users Connection + /// ID of the connection account /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class Connection - { - /// - /// ID of the connection account - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The username of the connection account - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// The username of the connection account + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// The service of the connection (twitch, youtube) - /// - /// - [JsonProperty("type")] - public ConnectionType Type { get; set; } + /// + /// The service of the connection (twitch, youtube) + /// + /// + [JsonProperty("type")] + public ConnectionType Type { get; set; } - /// - /// Whether the connection is revoked - /// - [JsonProperty("revoked")] - public bool? Revoked { get; set; } + /// + /// Whether the connection is revoked + /// + [JsonProperty("revoked")] + public bool? Revoked { get; set; } - /// - /// An array of partial server integrations - /// - /// - [JsonConverter(typeof(HashListConverter))] - [JsonProperty("integrations")] - public Hash Integrations { get; set; } + /// + /// An array of partial server integrations + /// + /// + [JsonConverter(typeof(HashListConverter))] + [JsonProperty("integrations")] + public Hash Integrations { get; set; } - /// - /// Whether the connection is verified - /// - [JsonProperty("verified")] - public bool Verified { get; set; } + /// + /// Whether the connection is verified + /// + [JsonProperty("verified")] + public bool Verified { get; set; } - /// - /// Whether friend sync is enabled for this connection - /// - [JsonProperty("friend_sync")] - public bool FriendSync { get; set; } + /// + /// Whether friend sync is enabled for this connection + /// + [JsonProperty("friend_sync")] + public bool FriendSync { get; set; } - /// - /// Whether this connection has a corresponding third party OAuth2 token - /// - [JsonProperty("two_way_link")] - public bool TwoWayLink { get; set; } + /// + /// Whether this connection has a corresponding third party OAuth2 token + /// + [JsonProperty("two_way_link")] + public bool TwoWayLink { get; set; } - /// - /// Whether activities related to this connection will be shown in presence updates - /// - [JsonProperty("show_activity")] - public bool ShowActivity { get; set; } + /// + /// Whether activities related to this connection will be shown in presence updates + /// + [JsonProperty("show_activity")] + public bool ShowActivity { get; set; } - /// - /// Visibility of this connection - /// - /// - [JsonProperty("visibility")] - public ConnectionVisibilityType Visibility { get; set; } - } -} + /// + /// Visibility of this connection + /// + /// + [JsonProperty("visibility")] + public ConnectionVisibilityType Visibility { get; set; } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Users/Connections/ConnectionType.cs b/Oxide.Ext.Discord/Entities/Users/Connections/ConnectionType.cs index 1e1027da7..b8386bac9 100644 --- a/Oxide.Ext.Discord/Entities/Users/Connections/ConnectionType.cs +++ b/Oxide.Ext.Discord/Entities/Users/Connections/ConnectionType.cs @@ -2,118 +2,132 @@ using Oxide.Ext.Discord.Attributes; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Connection Type for a connection +/// +[JsonConverter(typeof(DiscordEnumConverter))] +public enum ConnectionType : byte { /// - /// Represents a Connection Type for a connection - /// - [JsonConverter(typeof(DiscordEnumConverter))] - public enum ConnectionType : byte - { - /// - /// Discord Extension doesn't currently support this connection type - /// - Unknown, - - /// - /// Connection type is Battle.net - /// - [DiscordEnum("battlenet")] BattleNet, - - /// - /// Connection type is Epic Games - /// - // ReSharper disable once InconsistentNaming - [DiscordEnum("ebay")] eBay, - - /// - /// Connection type is Epic Games - /// - [DiscordEnum("epicgames")] EpicGames, - - /// - /// Connection type is Facebook - /// - [DiscordEnum("facebook")] Facebook, - - /// - /// Connection type is GitHub - /// - [DiscordEnum("github")] GitHub, - - /// - /// Connection type is Instagram - /// - [DiscordEnum("instagram")] Instagram, - - /// - /// Connection type is League of Legends - /// - [DiscordEnum("paypal")] PayPal, - - /// - /// Connection type is League of Legends - /// - [DiscordEnum("leagueoflegends")] LeagueOfLegends, - - /// - /// Connection type is PlayStation Network - /// - [DiscordEnum("playstation")] PlayStationNetwork, - - /// - /// Connection type is Reddit - /// - [DiscordEnum("reddit")] Reddit, - - /// - /// Connection type is Reddit - /// - [DiscordEnum("riotgames")] RiotGames, + /// Discord Extension doesn't currently support this connection type + /// + Unknown, + + /// + /// Connection type is Battle.net + /// + [DiscordEnum("battlenet")] BattleNet, + + /// + /// Connection type is Bungie.net + /// + [DiscordEnum("bungie")] Bungie, + + /// + /// Connection type is Domain + /// + [DiscordEnum("domain")] Domain, + + /// + /// Connection type is Epic Games + /// + // ReSharper disable once InconsistentNaming + [DiscordEnum("ebay")] eBay, + + /// + /// Connection type is Epic Games + /// + [DiscordEnum("epicgames")] EpicGames, + + /// + /// Connection type is Facebook + /// + [DiscordEnum("facebook")] Facebook, + + /// + /// Connection type is GitHub + /// + [DiscordEnum("github")] GitHub, + + /// + /// Connection type is Instagram + /// + [DiscordEnum("instagram")] Instagram, + + /// + /// Connection type is League of Legends + /// + [DiscordEnum("paypal")] PayPal, + + /// + /// Connection type is League of Legends + /// + [DiscordEnum("leagueoflegends")] LeagueOfLegends, + + /// + /// Connection type is PlayStation Network + /// + [DiscordEnum("playstation")] PlayStationNetwork, + + /// + /// Connection type is Reddit + /// + [DiscordEnum("reddit")] Reddit, + + /// + /// Connection type is Riot Games + /// + [DiscordEnum("riotgames")] RiotGames, + + /// + /// Connection type is Roblox + /// + [DiscordEnum("roblox")] Roblox, - /// - /// Connection type is Spotify - /// - [DiscordEnum("spotify")] Spotify, - - /// - /// Connection type is Skype - /// - [DiscordEnum("skype")] Skype, - - /// - /// Connection type is Steam - /// - [DiscordEnum("steam")] Steam, - - /// - /// Connection type is TikTok - /// - [DiscordEnum("tiktok")] TikTok, - - /// - /// Connection type is Twitch - /// - [DiscordEnum("twitch")] Twitch, - - /// - /// Connection type is Twitter - /// - [DiscordEnum("twitter")] Twitter, - - /// - /// Connection type is X (Twitter) - /// - [DiscordEnum("twitter")] X, - - /// - /// Connection type is Xbox - /// - [DiscordEnum("xbox")] Xbox, - - /// - /// Connection type is Youtube - /// - [DiscordEnum("youtube")] Youtube, - } + /// + /// Connection type is Spotify + /// + [DiscordEnum("spotify")] Spotify, + + /// + /// Connection type is Skype + /// + [DiscordEnum("skype")] Skype, + + /// + /// Connection type is Steam + /// + [DiscordEnum("steam")] Steam, + + /// + /// Connection type is TikTok + /// + [DiscordEnum("tiktok")] TikTok, + + /// + /// Connection type is Twitch + /// + [DiscordEnum("twitch")] Twitch, + + /// + /// Connection type is Twitter + /// + [DiscordEnum("twitter")] Twitter, + + /// + /// Connection type is X (Twitter) + /// + [DiscordEnum("twitter")] X, + + /// + /// Connection type is Xbox + /// + [DiscordEnum("xbox")] Xbox, + + /// + /// Connection type is Youtube + /// + [DiscordEnum("youtube")] Youtube, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Users/Connections/ConnectionVisibilityType.cs b/Oxide.Ext.Discord/Entities/Users/Connections/ConnectionVisibilityType.cs index 54b2295e3..5e5bbff9d 100644 --- a/Oxide.Ext.Discord/Entities/Users/Connections/ConnectionVisibilityType.cs +++ b/Oxide.Ext.Discord/Entities/Users/Connections/ConnectionVisibilityType.cs @@ -1,18 +1,17 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents connection Visibility Types +/// +public enum ConnectionVisibilityType : byte { /// - /// Represents connection Visibility Types + /// Invisible to everyone except the user themselves /// - public enum ConnectionVisibilityType : byte - { - /// - /// Invisible to everyone except the user themselves - /// - None = 0, + None = 0, - /// - /// Visible to everyone - /// - Everyone = 1 - } + /// + /// Visible to everyone + /// + Everyone = 1 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Users/DiscordUser.cs b/Oxide.Ext.Discord/Entities/Users/DiscordUser.cs index 50c696934..0235b8565 100644 --- a/Oxide.Ext.Discord/Entities/Users/DiscordUser.cs +++ b/Oxide.Ext.Discord/Entities/Users/DiscordUser.cs @@ -14,470 +14,469 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents User Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordUser : ISnowflakeEntity, IDiscordCacheable, IDebugLoggable { + #region Discord Fields /// - /// Represents User Structure + /// The user's id /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordUser : ISnowflakeEntity, IDiscordCacheable, IDebugLoggable - { - #region Discord Fields - /// - /// The user's id - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } - - /// - /// The user's username, not unique across the platform - /// - [JsonProperty("username")] - public string Username { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } + + /// + /// The user's username, not unique across the platform + /// + [JsonProperty("username")] + public string Username { get; set; } - /// - /// The user's global name - /// - [JsonProperty("global_name")] - public string GlobalName { get; set; } - - /// - /// The user's 4-digit discord-tag - /// - [JsonProperty("discriminator")] - [Obsolete("This field will be removed by discord in a future API version")] - public string Discriminator { get; set; } - - /// - /// The user's avatar hash - /// - [JsonProperty("avatar")] - public string Avatar { get; set; } - - /// - /// Whether the user belongs to an OAuth2 application - /// - [JsonProperty("bot")] - public bool? Bot { get; set; } - - /// - /// Whether the user is an Official Discord System user (part of the urgent message system) - /// - [JsonProperty("system")] - public bool? System { get; set; } - - /// - /// Whether the user has two factor enabled on their account - /// - [JsonProperty("mfa_enabled")] - public bool? MfaEnabled { get; set; } + /// + /// The user's global name + /// + [JsonProperty("global_name")] + public string GlobalName { get; set; } + + /// + /// The user's 4-digit discord-tag + /// + [JsonProperty("discriminator")] + [Obsolete("This field will be removed by discord in a future API version")] + public string Discriminator { get; set; } + + /// + /// The user's avatar hash + /// + [JsonProperty("avatar")] + public string Avatar { get; set; } + + /// + /// Whether the user belongs to an OAuth2 application + /// + [JsonProperty("bot")] + public bool? Bot { get; set; } + + /// + /// Whether the user is an Official Discord System user (part of the urgent message system) + /// + [JsonProperty("system")] + public bool? System { get; set; } + + /// + /// Whether the user has two factor enabled on their account + /// + [JsonProperty("mfa_enabled")] + public bool? MfaEnabled { get; set; } - /// - /// The user's banner, or null if unset - /// - [JsonProperty("banner")] - public string Banner { get; set; } + /// + /// The user's banner, or null if unset + /// + [JsonProperty("banner")] + public string Banner { get; set; } - /// - /// The user's banner color encoded as an integer representation of hexadecimal color code - /// - [JsonProperty("accent_color")] - public DiscordColor? AccentColor { get; set; } + /// + /// The user's banner color encoded as an integer representation of hexadecimal color code + /// + [JsonProperty("accent_color")] + public DiscordColor? AccentColor { get; set; } - /// - /// The user's chosen language option - /// - [JsonProperty("locale")] - public string Locale { get; set; } - - /// - /// Whether the email on this account has been verified - /// - [JsonProperty("verified")] - public bool? Verified { get; set; } - - /// - /// The user's email - /// - [JsonProperty("email")] - public string Email { get; set; } - - /// - /// The flags on a user's account - /// - /// - [JsonProperty("flags")] - public UserFlags? Flags { get; set; } - - /// - /// The type of Nitro subscription on a user's account - /// - /// - [JsonProperty("premium_type")] - public UserPremiumType? PremiumType { get; set; } - - /// - /// The public flags on a user's account - /// - /// - [JsonProperty("public_flags")] - public UserFlags? PublicFlags { get; set; } + /// + /// The user's chosen language option + /// + [JsonProperty("locale")] + public string Locale { get; set; } + + /// + /// Whether the email on this account has been verified + /// + [JsonProperty("verified")] + public bool? Verified { get; set; } + + /// + /// The user's email + /// + [JsonProperty("email")] + public string Email { get; set; } + + /// + /// The flags on a user's account + /// + /// + [JsonProperty("flags")] + public UserFlags? Flags { get; set; } + + /// + /// The type of Nitro subscription on a user's account + /// + /// + [JsonProperty("premium_type")] + public UserPremiumType? PremiumType { get; set; } + + /// + /// The public flags on a user's account + /// + /// + [JsonProperty("public_flags")] + public UserFlags? PublicFlags { get; set; } - /// - /// The user's avatar decoration hash - /// - [JsonProperty("avatar_decoration")] - public string AvatarDecoration { get; set; } - #endregion - - #region Helper Properties - /// - /// Returns a string to mention this users nickname in a message - /// - public string Mention => DiscordFormatting.MentionUser(Id); - - /// - /// Default Avatar Url for the User - /// - public string GetDefaultAvatarUrl => DiscordCdn.GetUserDefaultAvatarUrl(Discriminator); - - /// - /// Avatar Url for the user - /// - public string GetAvatarUrl => DiscordCdn.GetUserAvatarUrl(Id, Avatar); + /// + /// The user's avatar decoration + /// + [JsonProperty("avatar_decoration_data")] + public AvatarDecorationData AvatarDecoration { get; set; } + #endregion + + #region Helper Properties + /// + /// Returns a string to mention this users nickname in a message + /// + public string Mention => DiscordFormatting.MentionUser(Id); + + /// + /// Default Avatar Url for the User + /// + public string GetDefaultAvatarUrl => DiscordCdn.GetUserDefaultAvatarUrl(Discriminator); + + /// + /// Avatar Url for the user + /// + public string GetAvatarUrl => DiscordCdn.GetUserAvatarUrl(Id, Avatar); - /// - /// Avatar Decoration Url for the user - /// - public string GetAvatarDecorationUrl => DiscordCdn.GetUserAvatarDecoration(Id, AvatarDecoration); + /// + /// Avatar Decoration Url for the user + /// + public string GetAvatarDecorationUrl => DiscordCdn.GetUserAvatarDecoration(AvatarDecoration); - /// - /// Banner Url for the user - /// - public string GetBannerUrl => DiscordCdn.GetUserBanner(Id, Banner); - - /// - /// Returns the username#discriminator for the user - /// - public string FullUserName => Discriminator == "0" ? Username : $"{Username}#{Discriminator}"; - - /// - /// The display name for the user - /// - public string DisplayName => GlobalName ?? Username; - - /// - /// Returns if the DiscordUser is a bot - /// - public bool IsBot => Bot.HasValue && Bot.Value; + /// + /// Banner Url for the user + /// + public string GetBannerUrl => DiscordCdn.GetUserBanner(Id, Banner); + + /// + /// Returns the username#discriminator for the user + /// + public string FullUserName => Discriminator == "0" ? Username : $"{Username}#{Discriminator}"; + + /// + /// The display name for the user + /// + public string DisplayName => GlobalName ?? Username; + + /// + /// Returns if the DiscordUser is a bot + /// + public bool IsBot => Bot.HasValue && Bot.Value; - /// - /// Returns if the DiscordUser is a system user - /// - public bool IsSystem => System.HasValue && System.Value; - - /// - /// Returns true if the user has upgraded their username to the new username format - /// - public bool HasUpdatedUsername => !string.IsNullOrEmpty(Discriminator) && Discriminator == "0"; - - /// - /// Returns the IPlayer for the discord user if linked; null otherwise - /// - public IPlayer Player => DiscordLink.Instance.GetPlayer(Id); - #endregion - - #region API Methods - /// - /// Returns the currently logged in user account - /// See Get Current User - /// - /// Client to use - public static IPromise GetCurrentUser(DiscordClient client) - { - return client.Bot.Rest.Get(client,"users/@me"); - } + /// + /// Returns if the DiscordUser is a system user + /// + public bool IsSystem => System.HasValue && System.Value; - /// - /// Returns the user for the given user Id - /// See Get User - /// - /// Client to use - /// User ID to lookup - public static IPromise GetUser(DiscordClient client, Snowflake userId) - { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - return client.Bot.Rest.Get(client,$"users/{userId}"); - } + /// + /// Returns true if the user has upgraded their username to the new username format + /// + public bool HasUpdatedUsername => !string.IsNullOrEmpty(Discriminator) && Discriminator == "0"; - /// - /// Send a message to a user in a direct message channel - /// - /// Client to use - /// Message to be created - public IPromise SendDirectMessage(DiscordClient client, MessageCreate message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - return CreateDirectMessageChannel(client, Id) - .Then(channel => channel.CreateMessage(client, message)); - } + /// + /// Returns the IPlayer for the discord user if linked; null otherwise + /// + public IPlayer Player => DiscordLink.Instance.GetPlayer(Id); + #endregion - /// - /// Send a message to a user in a direct message channel - /// - /// Client to use - /// Content of the message - public IPromise SendDirectMessage(DiscordClient client, string message) - { - return SendDirectMessage(client, new MessageCreate{Content = message}); - } + #region API Methods + /// + /// Returns the currently logged in user account + /// See Get Current User + /// + /// Client to use + public static IPromise GetCurrentUser(DiscordClient client) + { + return client.Bot.Rest.Get(client,"users/@me"); + } - /// - /// Send a message to a user in a direct message channel - /// - /// Client to use - /// Embeds to be send in the message - public IPromise SendDirectMessage(DiscordClient client, List embeds) - { - if (embeds == null) throw new ArgumentNullException(nameof(embeds)); - return SendDirectMessage(client, new MessageCreate{Embeds = embeds}); - } + /// + /// Returns the user for the given user Id + /// See Get User + /// + /// Client to use + /// User ID to lookup + public static IPromise GetUser(DiscordClient client, Snowflake userId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + return client.Bot.Rest.Get(client,$"users/{userId}"); + } - /// - /// Send a message in a DM to the user using a localized message template - /// - /// Client to use - /// Template Name - /// Oxide language to use - /// Message to use (optional) - /// Placeholders to apply (optional) - public IPromise SendTemplateDirectMessage(DiscordClient client, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, MessageCreate message = null, PlaceholderData placeholders = null) - { - MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, language).ToMessage(placeholders, message); - return SendDirectMessage(client, template); - } + /// + /// Send a message to a user in a direct message channel + /// + /// Client to use + /// Message to be created + public IPromise SendDirectMessage(DiscordClient client, MessageCreate message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + return CreateDirectMessageChannel(client, Id) + .Then(channel => channel.CreateMessage(client, message)); + } - /// - /// Reply to a message using a global message template - /// - /// Client to use - /// Template Name - /// Message to use (optional) - /// Placeholders to apply (optional) - public IPromise SendGlobalTemplateDirectMessage(DiscordClient client, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) - { - MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(client.Plugin, templateName).ToMessage(placeholders, message); - return SendDirectMessage(client, template); - } + /// + /// Send a message to a user in a direct message channel + /// + /// Client to use + /// Content of the message + public IPromise SendDirectMessage(DiscordClient client, string message) + { + return SendDirectMessage(client, new MessageCreate{Content = message}); + } + + /// + /// Send a message to a user in a direct message channel + /// + /// Client to use + /// Embeds to be send in the message + public IPromise SendDirectMessage(DiscordClient client, List embeds) + { + if (embeds == null) throw new ArgumentNullException(nameof(embeds)); + return SendDirectMessage(client, new MessageCreate{Embeds = embeds}); + } + + /// + /// Send a message in a DM to the user using a localized message template + /// + /// Client to use + /// Template Name + /// Oxide language to use + /// Message to use (optional) + /// Placeholders to apply (optional) + public IPromise SendTemplateDirectMessage(DiscordClient client, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, MessageCreate message = null, PlaceholderData placeholders = null) + { + MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, language).ToMessage(placeholders, message); + return SendDirectMessage(client, template); + } + + /// + /// Reply to a message using a global message template + /// + /// Client to use + /// Template Name + /// Message to use (optional) + /// Placeholders to apply (optional) + public IPromise SendGlobalTemplateDirectMessage(DiscordClient client, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) + { + MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(client.Plugin, templateName).ToMessage(placeholders, message); + return SendDirectMessage(client, template); + } + + /// + /// Modify the currently logged in user + /// See Modify Current User + /// + /// Client to use + /// The updated current user information + public IPromise ModifyCurrentUser(DiscordClient client, UserModifyCurrent current) + { + if (current == null) throw new ArgumentNullException(nameof(current)); + return client.Bot.Rest.Patch(client,"users/@me", current); + } + + /// + /// Returns the guilds for the currently logged in user + /// See Get Current User Guilds + /// + /// Client to use + /// Request parameters for filtering guilds + public IPromise> GetCurrentUserGuilds(DiscordClient client, UserGuildsRequest request = null) + { + return client.Bot.Rest.Get>(client,$"users/@me/guilds{request?.ToQueryString()}"); + } - /// - /// Modify the currently logged in user - /// See Modify Current User - /// - /// Client to use - /// The updated current user information - public IPromise ModifyCurrentUser(DiscordClient client, UserModifyCurrent current) + /// + /// Leave the guild that the currently logged in user is in + /// See Leave Guild + /// + /// Client to use + /// Guild ID to leave + public IPromise LeaveGuild(DiscordClient client, Snowflake guildId) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Delete(client,$"users/@me/guilds/{guildId}"); + } + + /// + /// Create a Direct Message to the current User + /// See Create DM + /// + /// Client to use + public IPromise CreateDirectMessageChannel(DiscordClient client) => CreateDirectMessageChannel(client, Id); + + /// + /// Create a Direct Message to the current User + /// See Create DM + /// + /// Client to use + /// User ID to send the message to + public static IPromise CreateDirectMessageChannel(DiscordClient client, Snowflake userId) + { + InvalidSnowflakeException.ThrowIfInvalid(userId); + InvalidChannelException.ThrowIfChannelToSelf(userId, client); + + UserData userData = client.Bot.DirectMessagesByUserId[userId]?.UserData; + DateTime? isBlocked = userData?.GetBlockedUntil(); + + if (isBlocked.HasValue && isBlocked.Value > DateTime.UtcNow) { - if (current == null) throw new ArgumentNullException(nameof(current)); - return client.Bot.Rest.Patch(client,"users/@me", current); + DiscordUser user = userData.GetUser(); + client.Logger.Debug("Blocking CreateMessage. User {0} ({1}) is DM blocked until {2}.", user.FullUserName, user.Id, userData.GetBlockedUntil()); + return Promise.Rejected(new BlockedUserException(userData.GetUser(), isBlocked.Value)); } - - /// - /// Returns the guilds for the currently logged in user - /// See Get Current User Guilds - /// - /// Client to use - /// Request parameters for filtering guilds - public IPromise> GetCurrentUserGuilds(DiscordClient client, UserGuildsRequest request = null) + + DiscordChannel channel = client.Bot.DirectMessagesByUserId[userId]; + if (channel != null) { - return client.Bot.Rest.Get>(client,$"users/@me/guilds{request?.ToQueryString()}"); + return Promise.Resolved(channel); } - /// - /// Leave the guild that the currently logged in user is in - /// See Leave Guild - /// - /// Client to use - /// Guild ID to leave - public IPromise LeaveGuild(DiscordClient client, Snowflake guildId) + Dictionary data = new() { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Delete(client,$"users/@me/guilds/{guildId}"); - } + ["recipient_id"] = userId + }; - /// - /// Create a Direct Message to the current User - /// See Create DM - /// - /// Client to use - public IPromise CreateDirectMessageChannel(DiscordClient client) => CreateDirectMessageChannel(client, Id); - - /// - /// Create a Direct Message to the current User - /// See Create DM - /// - /// Client to use - /// User ID to send the message to - public static IPromise CreateDirectMessageChannel(DiscordClient client, Snowflake userId) + IPromise response = client.Bot.Rest.Post(client, "users/@me/channels", data).Then(newChannel => { - InvalidSnowflakeException.ThrowIfInvalid(userId, nameof(userId)); - InvalidChannelException.ThrowIfChannelToSelf(userId, client); + client.Bot.AddDirectChannel(newChannel); + }); - UserData userData = client.Bot.DirectMessagesByUserId[userId]?.UserData; - DateTime? isBlocked = userData?.GetBlockedUntil(); - - if (isBlocked.HasValue && isBlocked.Value > DateTime.UtcNow) - { - DiscordUser user = userData.GetUser(); - client.Logger.Debug("Blocking CreateMessage. User {0} ({1}) is DM blocked until {2}.", user.FullUserName, user.Id, userData.GetBlockedUntil()); - return Promise.Rejected(new BlockedUserException(userData.GetUser(), isBlocked.Value)); - } - - DiscordChannel channel = client.Bot.DirectMessagesByUserId[userId]; - if (channel != null) + response.Catch(error => + { + if (error.DiscordError == null || error.DiscordError.Code != 50007) { - return Promise.Resolved(channel); + return; } - Dictionary data = new Dictionary + if (userData == null) { - ["recipient_id"] = userId - }; - - IPromise response = client.Bot.Rest.Post(client, "users/@me/channels", data).Then(newChannel => - { - client.Bot.AddDirectChannel(newChannel); - }); - - response.Catch(error => - { - if (error.DiscordError == null || error.DiscordError.Code != 50007) - { - return; - } - - if (userData == null) - { - BotData bot = DiscordUserData.Instance.GetBotData(client.Bot.BotUser.Id); - userData = bot.GetUserData(userId); - } + BotData bot = DiscordUserData.Instance.GetBotData(client.Bot.BotUser.Id); + userData = bot.GetUserData(userId); + } - userData.ProcessError(client, error); - }); + userData.ProcessError(client, error); + }); - return response; - } + return response; + } - /// - /// Create a Group Direct Message - /// - /// Client to use - /// access tokens of users that have granted your app the gdm.join scope - /// a list of user ids to their respective nicknames - public IPromise CreateGroupDm(DiscordClient client, string[] accessTokens, Hash nicks) + /// + /// Create a Group Direct Message + /// + /// Client to use + /// access tokens of users that have granted your app the gdm.join scope + /// a list of user ids to their respective nicknames + public IPromise CreateGroupDm(DiscordClient client, string[] accessTokens, Hash nicks) + { + Dictionary data = new() { - Dictionary data = new Dictionary - { - ["access_tokens"] = accessTokens, - ["nicks"] = nicks - }; + ["access_tokens"] = accessTokens, + ["nicks"] = nicks + }; - return client.Bot.Rest.Post(client,"users/@me/channels", data); - } + return client.Bot.Rest.Post(client,"users/@me/channels", data); + } - /// - /// Returns a list of connection objects. - /// Requires the connections OAuth2 scope. - /// - /// Client to use - public IPromise> GetUserConnections(DiscordClient client) - { - return client.Bot.Rest.Get>(client,"users/@me/connections"); - } + /// + /// Returns a list of connection objects. + /// Requires the connections OAuth2 scope. + /// + /// Client to use + public IPromise> GetUserConnections(DiscordClient client) + { + return client.Bot.Rest.Get>(client,"users/@me/connections"); + } + + /// + /// Adds a recipient to a Group DM using their access token + /// See Group DM Add Recipient + /// + /// Client to use + /// Channel to add recipient to + /// Users access token + public IPromise GroupDmAddRecipient(DiscordClient client, DiscordChannel channel, string accessToken) => GroupDmAddRecipient(client, channel.Id, accessToken, Username); - /// - /// Adds a recipient to a Group DM using their access token - /// See Group DM Add Recipient - /// - /// Client to use - /// Channel to add recipient to - /// Users access token - public IPromise GroupDmAddRecipient(DiscordClient client, DiscordChannel channel, string accessToken) => GroupDmAddRecipient(client, channel.Id, accessToken, Username); - - /// - /// Adds a recipient to a Group DM using their access token - /// See Group DM Add Recipient - /// - /// Client to use - /// Channel ID to add user to - /// Users access token - /// User nickname - public IPromise GroupDmAddRecipient(DiscordClient client, Snowflake channelId, string accessToken, string nick) + /// + /// Adds a recipient to a Group DM using their access token + /// See Group DM Add Recipient + /// + /// Client to use + /// Channel ID to add user to + /// Users access token + /// User nickname + public IPromise GroupDmAddRecipient(DiscordClient client, Snowflake channelId, string accessToken, string nick) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + Dictionary data = new() { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - Dictionary data = new Dictionary - { - ["access_token"] = accessToken, - ["nick"] = nick - }; + ["access_token"] = accessToken, + ["nick"] = nick + }; - return client.Bot.Rest.Put(client,$"channels/{channelId}/recipients/{Id}", data); - } + return client.Bot.Rest.Put(client,$"channels/{channelId}/recipients/{Id}", data); + } - /// - /// Removes a recipient from a Group DM - /// - /// Client to use - /// Channel to remove recipient from - public IPromise GroupDmRemoveRecipient(DiscordClient client, DiscordChannel channel) => GroupDmRemoveRecipient(client, channel.Id); - - /// - /// Removes a recipient from a Group DM - /// - /// Client to use - /// Channel ID to remove recipient from - public IPromise GroupDmRemoveRecipient(DiscordClient client, Snowflake channelId) - { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - return client.Bot.Rest.Delete(client,$"channels/{channelId}/recipients/{Id}"); - } - #endregion + /// + /// Removes a recipient from a Group DM + /// + /// Client to use + /// Channel to remove recipient from + public IPromise GroupDmRemoveRecipient(DiscordClient client, DiscordChannel channel) => GroupDmRemoveRecipient(client, channel.Id); + + /// + /// Removes a recipient from a Group DM + /// + /// Client to use + /// Channel ID to remove recipient from + public IPromise GroupDmRemoveRecipient(DiscordClient client, Snowflake channelId) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + return client.Bot.Rest.Delete(client,$"channels/{channelId}/recipients/{Id}"); + } + #endregion - [OnDeserialized] - internal void OnDeserializedMethod(StreamingContext context) - { - DiscordUser update = EntityCache.Instance.Update(this); - Update(update); - } + [OnDeserialized] + internal void OnDeserializedMethod(StreamingContext context) + { + DiscordUser update = EntityCache.Instance.Update(this); + Update(update); + } - /// - /// Updates the user data with the passed in user - /// - /// - public void Update(DiscordUser update) - { - if (update.Username != null) Username = update.Username; - if (update.GlobalName != null) GlobalName = update.GlobalName; - if (update.Discriminator != null) Discriminator = update.Discriminator; - if (update.Avatar != null) Avatar = update.Avatar; - if (update.MfaEnabled.HasValue) MfaEnabled = update.MfaEnabled; - if (update.Banner != null) Banner = update.Banner; - if (update.AccentColor.HasValue) AccentColor = update.AccentColor; - if (update.Locale != null) Locale = update.Locale; - if (update.Verified.HasValue) Verified = update.Verified; - if (update.Email != null) Email = update.Email; - if (update.Flags.HasValue) Flags = update.Flags; - if (update.PremiumType.HasValue) PremiumType = update.PremiumType; - if (update.PublicFlags.HasValue) PublicFlags = update.PublicFlags; - if (update.AvatarDecoration != null) AvatarDecoration = update.AvatarDecoration; - } + /// + /// Updates the user data with the passed in user + /// + /// + public void Update(DiscordUser update) + { + if (update.Username != null) Username = update.Username; + if (update.GlobalName != null) GlobalName = update.GlobalName; + if (update.Discriminator != null) Discriminator = update.Discriminator; + if (update.Avatar != null) Avatar = update.Avatar; + if (update.MfaEnabled.HasValue) MfaEnabled = update.MfaEnabled; + if (update.Banner != null) Banner = update.Banner; + if (update.AccentColor.HasValue) AccentColor = update.AccentColor; + if (update.Locale != null) Locale = update.Locale; + if (update.Verified.HasValue) Verified = update.Verified; + if (update.Email != null) Email = update.Email; + if (update.Flags.HasValue) Flags = update.Flags; + if (update.PremiumType.HasValue) PremiumType = update.PremiumType; + if (update.PublicFlags.HasValue) PublicFlags = update.PublicFlags; + if (update.AvatarDecoration != null) AvatarDecoration = update.AvatarDecoration; + } - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendField("Id", Id); - logger.AppendField("Name", FullUserName); - logger.AppendField("Bot", IsBot); - } + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("Id", Id); + logger.AppendField("Name", FullUserName); + logger.AppendField("Bot", IsBot); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Users/UserFlags.cs b/Oxide.Ext.Discord/Entities/Users/UserFlags.cs index 8989ece5d..67fb3f91c 100644 --- a/Oxide.Ext.Discord/Entities/Users/UserFlags.cs +++ b/Oxide.Ext.Discord/Entities/Users/UserFlags.cs @@ -1,91 +1,90 @@ using System; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents User Flags +/// +[Flags] +public enum UserFlags { /// - /// Represents User Flags + /// Default value for flags, when none are given to an account. /// - [Flags] - public enum UserFlags - { - /// - /// Default value for flags, when none are given to an account. - /// - None = 0, + None = 0, - /// - /// Flag given to users who are a Discord employee - /// - Staff = 1 << 0, + /// + /// Flag given to users who are a Discord employee + /// + Staff = 1 << 0, - /// - /// Flag given to users who are owners of a partnered Discord server - /// - Partner = 1 << 1, + /// + /// Flag given to users who are owners of a partnered Discord server + /// + Partner = 1 << 1, - /// - /// Flag given to users who are HypeSquad Events Member - /// - HypeSquad = 1 << 2, + /// + /// Flag given to users who are HypeSquad Events Member + /// + HypeSquad = 1 << 2, - /// - /// Flag given to users who have participated in the 𝐁ug report program and are level 1. - /// - BugHunterLevel1 = 1 << 3, + /// + /// Flag given to users who have participated in the 𝐁ug report program and are level 1. + /// + BugHunterLevel1 = 1 << 3, - /// - /// Flag given to users who are in the HypeSquad House of Bravery. - /// - HypeSquadOnlineHouse1 = 1 << 6, + /// + /// Flag given to users who are in the HypeSquad House of Bravery. + /// + HypeSquadOnlineHouse1 = 1 << 6, - /// - /// Flag given to users who are in the HypeSquad House of Brilliance. - /// - HypeSquadOnlineHouse2 = 1 << 7, + /// + /// Flag given to users who are in the HypeSquad House of Brilliance. + /// + HypeSquadOnlineHouse2 = 1 << 7, - /// - /// Flag given to users who are in the HypeSquad House of Balance. - /// - HypeSquadOnlineHouse3 = 1 << 8, + /// + /// Flag given to users who are in the HypeSquad House of Balance. + /// + HypeSquadOnlineHouse3 = 1 << 8, - /// - /// Flag given to users who subscribed to Nitro before games were added. - /// - PremiumEarlySupporter = 1 << 9, + /// + /// Flag given to users who subscribed to Nitro before games were added. + /// + PremiumEarlySupporter = 1 << 9, - /// - /// Flag given to users who are part of a team. - /// - TeamPseudoUser = 1 << 10, + /// + /// Flag given to users who are part of a team. + /// + TeamPseudoUser = 1 << 10, - /// - /// Flag given to users who have participated in the 𝐁ug report program and are level 2. - /// - BugHunterLevel2 = 1 << 14, + /// + /// Flag given to users who have participated in the 𝐁ug report program and are level 2. + /// + BugHunterLevel2 = 1 << 14, - /// - /// Flag given to users who are verified bots. - /// - VerifiedBot = 1 << 16, + /// + /// Flag given to users who are verified bots. + /// + VerifiedBot = 1 << 16, - /// - /// Flag given to users that developed bots and early verified their accounts. - /// - VerifiedDeveloper = 1 << 17, + /// + /// Flag given to users that developed bots and early verified their accounts. + /// + VerifiedDeveloper = 1 << 17, - /// - /// Flag given to users that are Moderator Programs Alumni - /// - CertifiedModerator = 1 << 18, + /// + /// Flag given to users that are Moderator Programs Alumni + /// + CertifiedModerator = 1 << 18, - /// - /// User is a Bot uses only HTTP interactions and is shown in the online member list - /// - BotHttpInteractions = 1 << 19, + /// + /// User is a Bot uses only HTTP interactions and is shown in the online member list + /// + BotHttpInteractions = 1 << 19, - /// - /// User is an Active Developer - /// - ActiveDeveloper = 1 << 22, - } + /// + /// User is an Active Developer + /// + ActiveDeveloper = 1 << 22, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Users/UserGuildsRequest.cs b/Oxide.Ext.Discord/Entities/Users/UserGuildsRequest.cs index d9cc7826b..72282242a 100644 --- a/Oxide.Ext.Discord/Entities/Users/UserGuildsRequest.cs +++ b/Oxide.Ext.Discord/Entities/Users/UserGuildsRequest.cs @@ -1,46 +1,44 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Users Guild Request +/// +public class UserGuildsRequest : IDiscordQueryString { /// - /// Represents a Users Guild Request + /// Get guilds before this guild ID /// - public class UserGuildsRequest : IDiscordQueryString - { - /// - /// Get guilds before this guild ID - /// - public Snowflake? Before { get; set; } + public Snowflake? Before { get; set; } - /// - /// Get guilds after this guild ID - /// - public Snowflake? After { get; set; } + /// + /// Get guilds after this guild ID + /// + public Snowflake? After { get; set; } - /// - /// Max number of guilds to return (1-200) - /// - public int Limit { get; set; } = 200; + /// + /// Max number of guilds to return (1-200) + /// + public int Limit { get; set; } = 200; - /// - public virtual string ToQueryString() - { - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); - builder.Add("limit", Limit.ToString()); + /// + public virtual string ToQueryString() + { + QueryStringBuilder builder = new(); + builder.Add("limit", Limit.ToString()); - if (Before.HasValue) - { - builder.Add("before", Before.ToString()); - } + if (Before.HasValue) + { + builder.Add("before", Before.ToString()); + } - if (After.HasValue) - { - builder.Add("after", After.ToString()); - } - - return builder.ToStringAndFree(); + if (After.HasValue) + { + builder.Add("after", After.ToString()); } + + return builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Users/UserModifyCurrent.cs b/Oxide.Ext.Discord/Entities/Users/UserModifyCurrent.cs index d33f2a379..c774041cb 100644 --- a/Oxide.Ext.Discord/Entities/Users/UserModifyCurrent.cs +++ b/Oxide.Ext.Discord/Entities/Users/UserModifyCurrent.cs @@ -2,29 +2,34 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Modify Current User Structure +/// +public class UserModifyCurrent : IDiscordValidation { /// - /// Represents a Modify Current User Structure + /// User's username, if changed may cause the user's discriminator to be randomized. /// - public class UserModifyCurrent : IDiscordValidation - { - /// - /// User's username, if changed may cause the user's discriminator to be randomized. - /// - [JsonProperty("username")] - public string Username { get; set; } + [JsonProperty("username")] + public string Username { get; set; } + + /// + /// If passed, modifies the user's avatar + /// + [JsonProperty("avatar")] + public DiscordImageData Avatar { get; set; } - /// - /// If passed, modifies the user's avatar - /// - [JsonProperty("avatar")] - public string Avatar { get; set; } + /// + /// If passed, modifies the user's banner + /// + [JsonProperty("banner")] + public DiscordImageData Banner { get; set; } - /// - public void Validate() - { - InvalidUserException.ThrowIfInvalidUserName(Username); - } + /// + public void Validate() + { + InvalidUserException.ThrowIfInvalidUserName(Username); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Users/UserPremiumType.cs b/Oxide.Ext.Discord/Entities/Users/UserPremiumType.cs index 66a65c9d1..2f37df245 100644 --- a/Oxide.Ext.Discord/Entities/Users/UserPremiumType.cs +++ b/Oxide.Ext.Discord/Entities/Users/UserPremiumType.cs @@ -1,28 +1,27 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Discord User Premium Types +/// +public enum UserPremiumType : byte { /// - /// Represents Discord User Premium Types + /// User has no premium /// - public enum UserPremiumType : byte - { - /// - /// User has no premium - /// - None = 0, + None = 0, - /// - /// User has nitro classic premium - /// - NitroClassic = 1, + /// + /// User has nitro classic premium + /// + NitroClassic = 1, - /// - /// User has nitro premium - /// - Nitro = 2, + /// + /// User has nitro premium + /// + Nitro = 2, - /// - /// User has nitro basic - /// - NitroBasic = 3 - } -} + /// + /// User has nitro basic + /// + NitroBasic = 3 +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Users/UserStatusType.cs b/Oxide.Ext.Discord/Entities/Users/UserStatusType.cs index 4ca9da0df..58ba996c8 100644 --- a/Oxide.Ext.Discord/Entities/Users/UserStatusType.cs +++ b/Oxide.Ext.Discord/Entities/Users/UserStatusType.cs @@ -1,35 +1,34 @@ using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Discord User Status Types +/// +public enum UserStatusType : byte { /// - /// Represents Discord User Status Types + /// User is online /// - public enum UserStatusType : byte - { - /// - /// User is online - /// - [DiscordEnum("online")] Online, + [DiscordEnum("online")] Online, - /// - /// User has Do Not Disturb - /// - [DiscordEnum("dnd")] Dnd, + /// + /// User has Do Not Disturb + /// + [DiscordEnum("dnd")] Dnd, - /// - /// User is idle - /// - [DiscordEnum("idle")] Idle, + /// + /// User is idle + /// + [DiscordEnum("idle")] Idle, - /// - /// User is invisible - /// - [DiscordEnum("invisible")] Invisible, + /// + /// User is invisible + /// + [DiscordEnum("invisible")] Invisible, - /// - /// User is offline - /// - [DiscordEnum("offline")] Offline - } + /// + /// User is offline + /// + [DiscordEnum("offline")] Offline } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Voice/VoiceRegion.cs b/Oxide.Ext.Discord/Entities/Voice/VoiceRegion.cs index 64530c87f..3cfa2c90a 100644 --- a/Oxide.Ext.Discord/Entities/Voice/VoiceRegion.cs +++ b/Oxide.Ext.Discord/Entities/Voice/VoiceRegion.cs @@ -3,52 +3,51 @@ using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Voice Region Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class VoiceRegion { /// - /// Represents Voice Region Structure + /// Unique ID for the region /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class VoiceRegion - { - /// - /// Unique ID for the region - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// Name of the region - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// Name of the region + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// True for a single server that is closest to the current user's client - /// - [JsonProperty("optimal")] - public bool Optimal { get; set; } + /// + /// True for a single server that is closest to the current user's client + /// + [JsonProperty("optimal")] + public bool Optimal { get; set; } - /// - /// Whether this is a deprecated voice region (avoid switching to these) - /// - [JsonProperty("deprecated")] - public bool Deprecated { get; set; } + /// + /// Whether this is a deprecated voice region (avoid switching to these) + /// + [JsonProperty("deprecated")] + public bool Deprecated { get; set; } - /// - /// Whether this is a custom voice region (used for events/etc) - /// - [JsonProperty("custom")] - public bool Custom { get; set; } + /// + /// Whether this is a custom voice region (used for events/etc) + /// + [JsonProperty("custom")] + public bool Custom { get; set; } - /// - /// Returns an array of voice region objects that can be used when creating servers. - /// See List Voice Regions - /// - /// Client to use - public static IPromise> ListVoiceRegions(DiscordClient client) - { - return client.Bot.Rest.Get>(client,"voice/regions"); - } + /// + /// Returns an array of voice region objects that can be used when creating servers. + /// See List Voice Regions + /// + /// Client to use + public static IPromise> ListVoiceRegions(DiscordClient client) + { + return client.Bot.Rest.Get>(client,"voice/regions"); } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Voice/VoiceState.cs b/Oxide.Ext.Discord/Entities/Voice/VoiceState.cs index 61704854f..5bda924af 100644 --- a/Oxide.Ext.Discord/Entities/Voice/VoiceState.cs +++ b/Oxide.Ext.Discord/Entities/Voice/VoiceState.cs @@ -2,119 +2,118 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Voice State Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class VoiceState : ISnowflakeEntity { /// - /// Represents Voice State Structure + /// User ID for the voice state /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class VoiceState : ISnowflakeEntity - { - /// - /// User ID for the voice state - /// - public Snowflake Id => UserId; - - /// - /// The guild id this voice state is for - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } - - /// - /// The channel id this user is connected to - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } - - /// - /// The user id this voice state is for - /// - [JsonProperty("user_id")] - public Snowflake UserId { get; set; } + public Snowflake Id => UserId; + + /// + /// The guild id this voice state is for + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } + + /// + /// The channel id this user is connected to + /// + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } + + /// + /// The user id this voice state is for + /// + [JsonProperty("user_id")] + public Snowflake UserId { get; set; } - /// - /// The guild member this voice state is for - /// - [JsonProperty("member")] - public GuildMember Member { get; set; } - - /// - /// The session id for this voice state - /// - [JsonProperty("session_id")] - public string SessionId { get; set; } - - /// - /// Whether this user is deafened by the server - /// - [JsonProperty("deaf")] - public bool Deaf { get; set; } - - /// - /// Whether this user is muted by the server - /// - [JsonProperty("mute")] - public bool Mute { get; set; } - - /// - /// Whether this user is locally deafened - /// - [JsonProperty("self_deaf")] - public bool SelfDeaf { get; set; } - - /// - /// Whether this user is locally muted - /// - [JsonProperty("self_mute")] - public bool SelfMute { get; set; } + /// + /// The guild member this voice state is for + /// + [JsonProperty("member")] + public GuildMember Member { get; set; } + + /// + /// The session id for this voice state + /// + [JsonProperty("session_id")] + public string SessionId { get; set; } + + /// + /// Whether this user is deafened by the server + /// + [JsonProperty("deaf")] + public bool Deaf { get; set; } + + /// + /// Whether this user is muted by the server + /// + [JsonProperty("mute")] + public bool Mute { get; set; } + + /// + /// Whether this user is locally deafened + /// + [JsonProperty("self_deaf")] + public bool SelfDeaf { get; set; } + + /// + /// Whether this user is locally muted + /// + [JsonProperty("self_mute")] + public bool SelfMute { get; set; } - /// - /// Whether this user is streaming using "Go Live" - /// - [JsonProperty("self_stream")] - public bool? SelfStream { get; set; } + /// + /// Whether this user is streaming using "Go Live" + /// + [JsonProperty("self_stream")] + public bool? SelfStream { get; set; } - /// - /// Whether this user's camera is enabled - /// - [JsonProperty("self_video")] - public bool SelfVideo { get; set; } - - /// - /// whether this user's permission to speak is denied - /// - [JsonProperty("suppress")] - public bool Suppress { get; set; } + /// + /// Whether this user's camera is enabled + /// + [JsonProperty("self_video")] + public bool SelfVideo { get; set; } + + /// + /// whether this user's permission to speak is denied + /// + [JsonProperty("suppress")] + public bool Suppress { get; set; } - /// - /// Whether this user is muted by the current user - /// - [JsonProperty("request_to_speak_timestamp")] - public DateTime? RequestToSpeakTimestamp { get; set; } + /// + /// Whether this user is muted by the current user + /// + [JsonProperty("request_to_speak_timestamp")] + public DateTime? RequestToSpeakTimestamp { get; set; } - internal void Update(VoiceState state) - { - if (state.ChannelId != ChannelId) - ChannelId = state.ChannelId; + internal void Update(VoiceState state) + { + if (state.ChannelId != ChannelId) + ChannelId = state.ChannelId; - if (state.SessionId != SessionId) - SessionId = state.SessionId; + if (state.SessionId != SessionId) + SessionId = state.SessionId; - Deaf = state.Deaf; - Mute = state.Mute; - SelfDeaf = state.SelfDeaf; - SelfMute = state.SelfMute; + Deaf = state.Deaf; + Mute = state.Mute; + SelfDeaf = state.SelfDeaf; + SelfMute = state.SelfMute; - if (state.SelfStream != SelfStream) - SelfStream = state.SelfStream; + if (state.SelfStream != SelfStream) + SelfStream = state.SelfStream; - SelfVideo = state.SelfVideo; - Suppress = state.Suppress; + SelfVideo = state.SelfVideo; + Suppress = state.Suppress; - if (state.RequestToSpeakTimestamp != RequestToSpeakTimestamp) - RequestToSpeakTimestamp = state.RequestToSpeakTimestamp; + if (state.RequestToSpeakTimestamp != RequestToSpeakTimestamp) + RequestToSpeakTimestamp = state.RequestToSpeakTimestamp; - } } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Webhooks/DiscordWebhook.cs b/Oxide.Ext.Discord/Entities/Webhooks/DiscordWebhook.cs index 6e8d47e47..a5effc169 100644 --- a/Oxide.Ext.Discord/Entities/Webhooks/DiscordWebhook.cs +++ b/Oxide.Ext.Discord/Entities/Webhooks/DiscordWebhook.cs @@ -8,366 +8,378 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Webhook Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordWebhook { /// - /// Represents Webhook Structure + /// The id of the webhook /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordWebhook - { - /// - /// The id of the webhook - /// - [JsonProperty("id")] - public Snowflake Id { get; set; } + [JsonProperty("id")] + public Snowflake Id { get; set; } - /// - /// The type of the webhook - /// See - /// - [JsonProperty("type")] - public WebhookType Type { get; set; } + /// + /// The type of the webhook + /// See + /// + [JsonProperty("type")] + public WebhookType Type { get; set; } - /// - /// The guild id this webhook is for, if any - /// - [JsonProperty("guild_id")] - public Snowflake? GuildId { get; set; } + /// + /// The guild id this webhook is for, if any + /// + [JsonProperty("guild_id")] + public Snowflake? GuildId { get; set; } - /// - /// The channel id this webhook is for, if any - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } + /// + /// The channel id this webhook is for, if any + /// + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } - /// - /// The user this webhook was created by - /// not returned when getting a webhook with its token - /// - [JsonProperty("user")] - public DiscordUser User { get; set; } + /// + /// The user this webhook was created by + /// not returned when getting a webhook with its token + /// + [JsonProperty("user")] + public DiscordUser User { get; set; } - /// - /// The default name of the webhook - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// The default name of the webhook + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// the default user avatar hash of the webhook - /// - [JsonProperty("avatar")] - public string Avatar { get; set; } + /// + /// the default user avatar hash of the webhook + /// + [JsonProperty("avatar")] + public string Avatar { get; set; } - /// - /// The secure token of the webhook - /// returned for Incoming Webhooks - /// - [JsonProperty("token")] - public string Token { get; set; } + /// + /// The secure token of the webhook + /// returned for Incoming Webhooks + /// + [JsonProperty("token")] + public string Token { get; set; } - /// - /// The bot/OAuth2 application that created this webhook - /// - [JsonProperty("application_id")] - public Snowflake ApplicationId { get; set; } + /// + /// The bot/OAuth2 application that created this webhook + /// + [JsonProperty("application_id")] + public Snowflake ApplicationId { get; set; } - /// - /// The guild of the channel that this webhook is following (returned for Channel Follower Webhooks) - /// - [JsonProperty("source_guild")] - public DiscordGuild SourceGuild { get; set; } + /// + /// The guild of the channel that this webhook is following (returned for Channel Follower Webhooks) + /// + [JsonProperty("source_guild")] + public DiscordGuild SourceGuild { get; set; } - /// - /// The channel that this webhook is following (returned for Channel Follower Webhooks) - /// - [JsonProperty("source_channel")] - public Snowflake SourceChannel { get; set; } + /// + /// The channel that this webhook is following (returned for Channel Follower Webhooks) + /// + [JsonProperty("source_channel")] + public Snowflake SourceChannel { get; set; } + + /// + /// Client for the webhook + /// + public WebhookClient Client { get; internal set; } + + private BaseClient GetClient(DiscordClient client) => (BaseClient)Client ?? client.Bot; - /// - /// Create a new webhook. - /// Requires the MANAGE_WEBHOOKS permission. - /// See Create Webhook - /// - /// Client to use - /// Channel ID for the webhook - /// Webhook create request - public static IPromise CreateWebhook(DiscordClient client, Snowflake channelId, WebhookCreate create) - { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - return client.Bot.Rest.Post(client,$"channels/{channelId}/webhooks", create); - } + /// + /// Create a new webhook. + /// Requires the MANAGE_WEBHOOKS permission. + /// See Create Webhook + /// + /// Client to use + /// Channel ID for the webhook + /// Webhook create request + public static IPromise CreateWebhook(DiscordClient client, Snowflake channelId, WebhookCreate create) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + return client.Bot.Rest.Post(client,$"channels/{channelId}/webhooks", create); + } - /// - /// Returns a list of channel webhook. - /// See Get Channel Webhooks - /// - /// Client to use - /// Channel ID to get webhooks for - public static IPromise> GetChannelWebhooks(DiscordClient client, Snowflake channelId) - { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - return client.Bot.Rest.Get>(client,$"channels/{channelId}/webhooks"); - } + /// + /// Returns a list of channel webhook. + /// See Get Channel Webhooks + /// + /// Client to use + /// Channel ID to get webhooks for + public static IPromise> GetChannelWebhooks(DiscordClient client, Snowflake channelId) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + return client.Bot.Rest.Get>(client,$"channels/{channelId}/webhooks"); + } - /// - /// Returns a list of guild webhooks - /// See Get Guild Webhooks - /// - /// Client to use - /// Guild ID to get webhooks for - public static IPromise> GetGuildWebhooks(DiscordClient client, Snowflake guildId) - { - InvalidSnowflakeException.ThrowIfInvalid(guildId, nameof(guildId)); - return client.Bot.Rest.Get>(client,$"guilds/{guildId}/webhooks"); - } + /// + /// Returns a list of guild webhooks + /// See Get Guild Webhooks + /// + /// Client to use + /// Guild ID to get webhooks for + public static IPromise> GetGuildWebhooks(DiscordClient client, Snowflake guildId) + { + InvalidSnowflakeException.ThrowIfInvalid(guildId); + return client.Bot.Rest.Get>(client,$"guilds/{guildId}/webhooks"); + } - /// - /// Returns the webhook with the given webhook ID - /// See Get Webhook - /// - /// Client to use - /// Webhook ID to get - public static IPromise GetWebhook(DiscordClient client, Snowflake webhookId) - { - InvalidSnowflakeException.ThrowIfInvalid(webhookId, nameof(webhookId)); - return client.Bot.Rest.Get(client,$"webhooks/{webhookId}"); - } + /// + /// Returns the webhook with the given webhook ID + /// See Get Webhook + /// + /// Client to use + /// Webhook ID to get + public static IPromise GetWebhook(DiscordClient client, Snowflake webhookId) + { + InvalidSnowflakeException.ThrowIfInvalid(webhookId); + return client.Bot.Rest.Get(client,$"webhooks/{webhookId}"); + } - /// - /// Returns the webhook with the given ID & Token - /// This call does not required authentication - /// No user is returned in webhook object - /// See Get Webhook with Token - /// - /// Client to use - /// Webhook ID to get - /// Webhook Token - public static IPromise GetWebhookWithToken(DiscordClient client, Snowflake webhookId, string webhookToken) - { - InvalidSnowflakeException.ThrowIfInvalid(webhookId, nameof(webhookId)); - return client.Bot.Rest.Get(client,$"webhooks/{webhookId}/{webhookToken}"); - } + /// + /// Returns the webhook with the given ID & Token + /// This call does not required authentication + /// No user is returned in webhook object + /// See Get Webhook with Token + /// + /// Client to use + /// Webhook ID to get + /// Webhook Token + public static IPromise GetWebhookWithToken(DiscordClient client, Snowflake webhookId, string webhookToken) + { + InvalidSnowflakeException.ThrowIfInvalid(webhookId); + return client.Bot.Rest.Get(client,$"webhooks/{webhookId}/{webhookToken}"); + } + + internal static IPromise GetWebhookWithToken(DiscordClient client, WebhookClient webhookClient, Snowflake webhookId, string webhookToken) + { + InvalidSnowflakeException.ThrowIfInvalid(webhookId); + return webhookClient.Rest.Get(client,$"webhooks/{webhookId}/{webhookToken}"); + } - /// - /// Returns the webhook with the given ID & Token - /// This call does not required authentication - /// No user is returned in webhook object - /// See Get Webhook with Token - /// - /// Client to use - /// Returns the webhook for the specified URL - public static IPromise GetWebhookWithUrl(DiscordClient client, string webhookUrl) - { - string[] webhookInfo = webhookUrl.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); - string id = webhookInfo[webhookInfo.Length - 2]; - string token = webhookInfo[webhookInfo.Length - 1]; + /// + /// Returns the webhook with the given ID & Token + /// This call does not required authentication + /// No user is returned in webhook object + /// See Get Webhook with Token + /// + /// Client to use + /// Returns the webhook for the specified URL + public static IPromise GetWebhookWithUrl(DiscordClient client, string webhookUrl) + { + string[] webhookInfo = webhookUrl.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); + string id = webhookInfo[webhookInfo.Length - 2]; + string token = webhookInfo[webhookInfo.Length - 1]; - return client.Bot.Rest.Get(client,$"webhooks/{id}/{token}"); - } + return client.Bot.Rest.Get(client,$"webhooks/{id}/{token}"); + } - /// - /// Modify a webhook. - /// Requires the MANAGE_WEBHOOKS permission. - /// See Modify Webhook - /// - /// Client to use - /// Edit request for the webhook - public IPromise EditWebhook(DiscordClient client, WebhookEdit edit) - { - return client.Bot.Rest.Patch(client,$"webhooks/{Id}", edit); - } + /// + /// Modify a webhook. + /// Requires the MANAGE_WEBHOOKS permission. + /// See Modify Webhook + /// + /// Client to use + /// Edit request for the webhook + public IPromise EditWebhook(DiscordClient client, WebhookEdit edit) + { + return client.Bot.Rest.Patch(client,$"webhooks/{Id}", edit); + } - /// - /// Modify a webhook. - /// Requires the MANAGE_WEBHOOKS permission. - /// See Modify Webhook with Token - /// - /// Client to use - /// Edit request for the webhook - public IPromise ModifyWebhookWithToken(DiscordClient client, WebhookEdit edit) - { - return client.Bot.Rest.Patch(client,$"webhooks/{Id}/{Token}", edit); - } + /// + /// Modify a webhook. + /// Requires the MANAGE_WEBHOOKS permission. + /// See Modify Webhook with Token + /// + /// Client to use + /// Edit request for the webhook + public IPromise ModifyWebhookWithToken(DiscordClient client, WebhookEdit edit) + { + return GetClient(client).Rest.Patch(client,$"webhooks/{Id}/{Token}", edit); + } - /// - /// Delete a webhook permanently. - /// Requires the MANAGE_WEBHOOKS permission. - /// See Delete Webhook - /// - /// Client to use - public IPromise DeleteWebhook(DiscordClient client) - { - return client.Bot.Rest.Delete(client,$"webhooks/{Id}"); - } + /// + /// Delete a webhook permanently. + /// Requires the MANAGE_WEBHOOKS permission. + /// See Delete Webhook + /// + /// Client to use + public IPromise DeleteWebhook(DiscordClient client) + { + return client.Bot.Rest.Delete(client,$"webhooks/{Id}"); + } - /// - /// Delete a webhook permanently. - /// Does not require authentication. - /// See Delete Webhook with Token - /// - /// Client to use - public IPromise DeleteWebhookWithToken(DiscordClient client) - { - return client.Bot.Rest.Delete(client,$"webhooks/{Id}/{Token}"); - } + /// + /// Delete a webhook permanently. + /// Does not require authentication. + /// See Delete Webhook with Token + /// + /// Client to use + public IPromise DeleteWebhookWithToken(DiscordClient client) + { + return GetClient(client).Rest.Delete(client,$"webhooks/{Id}/{Token}"); + } - /// - /// Executes a webhook - /// See Execute Webhook - /// - /// Client to use - /// Message data - /// Webhook execution parameters - public IPromise ExecuteWebhook(DiscordClient client, WebhookCreateMessage message, WebhookExecuteParams executeParams = null) + /// + /// Executes a webhook + /// See Execute Webhook + /// + /// Client to use + /// Message data + /// Webhook execution parameters + public IPromise ExecuteWebhook(DiscordClient client, WebhookCreateMessage message, WebhookExecuteParams executeParams = null) + { + if (executeParams == null) { - if (executeParams == null) - { - executeParams = WebhookExecuteParams.Default; - } - - return client.Bot.Rest.Post(client,$"webhooks/{Id}/{Token}{executeParams.GetWebhookFormat()}{executeParams.ToQueryString()}", message); + executeParams = WebhookExecuteParams.Default; } + + return GetClient(client).Rest.Post(client,$"webhooks/{Id}/{Token}{executeParams.GetWebhookFormat()}{executeParams.ToQueryString()}", message); + } - /// - /// Executes a webhook - /// See Execute Webhook - /// - /// Client to use - /// Builder for the message - /// Webhook execution parameters - public IPromise ExecuteWebhook(DiscordClient client, WebhookMessageBuilder builder, WebhookExecuteParams executeParams = null) - { - return ExecuteWebhook(client, builder.Build(), executeParams); - } + /// + /// Executes a webhook + /// See Execute Webhook + /// + /// Client to use + /// Builder for the message + /// Webhook execution parameters + public IPromise ExecuteWebhook(DiscordClient client, WebhookMessageBuilder builder, WebhookExecuteParams executeParams = null) + { + return ExecuteWebhook(client, builder.Build(), executeParams); + } - /// - /// Executes a webhook - /// See Execute Webhook - /// - /// Client to use - /// Message data - /// Webhook execution parameters - public IPromise ExecuteWebhookWithMessage(DiscordClient client, WebhookCreateMessage message, WebhookExecuteParams executeParams = null) + /// + /// Executes a webhook + /// See Execute Webhook + /// + /// Client to use + /// Message data + /// Webhook execution parameters + public IPromise ExecuteWebhookWithMessage(DiscordClient client, WebhookCreateMessage message, WebhookExecuteParams executeParams = null) + { + if (executeParams == null) { - if (executeParams == null) - { - executeParams = WebhookExecuteParams.DefaultWait; - } - - return client.Bot.Rest.Post(client,$"webhooks/{Id}/{Token}{executeParams.GetWebhookFormat()}{executeParams.ToQueryString()}", message); + executeParams = WebhookExecuteParams.DefaultWait; } + + return GetClient(client).Rest.Post(client,$"webhooks/{Id}/{Token}{executeParams.GetWebhookFormat()}{executeParams.ToQueryString()}", message); + } - /// - /// Executes a webhook - /// See Execute Webhook - /// - /// Client to use - /// Builder for the message - /// Webhook execution parameters - public IPromise ExecuteWebhookWithMessage(DiscordClient client, WebhookMessageBuilder builder, WebhookExecuteParams executeParams = null) - { - return ExecuteWebhookWithMessage(client, builder.Build(), executeParams); - } + /// + /// Executes a webhook + /// See Execute Webhook + /// + /// Client to use + /// Builder for the message + /// Webhook execution parameters + public IPromise ExecuteWebhookWithMessage(DiscordClient client, WebhookMessageBuilder builder, WebhookExecuteParams executeParams = null) + { + return ExecuteWebhookWithMessage(client, builder.Build(), executeParams); + } - /// - /// Send a message to a webhook using a global message template - /// - /// Client to use - /// Template Name - /// Message to use (optional) - /// Placeholders to apply (optional) - /// Webhook execution parameters - public IPromise ExecuteWebhookGlobalTemplate(DiscordClient client, TemplateKey templateName, WebhookCreateMessage message = null, PlaceholderData placeholders = null, WebhookExecuteParams executeParams = null) - { - WebhookCreateMessage template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(client.Plugin, templateName).ToMessage(placeholders, message); - return ExecuteWebhookWithMessage(client, template, executeParams); - } + /// + /// Send a message to a webhook using a global message template + /// + /// Client to use + /// Template Name + /// Message to use (optional) + /// Placeholders to apply (optional) + /// Webhook execution parameters + public IPromise ExecuteWebhookGlobalTemplate(DiscordClient client, TemplateKey templateName, WebhookCreateMessage message = null, PlaceholderData placeholders = null, WebhookExecuteParams executeParams = null) + { + WebhookCreateMessage template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(client.Plugin, templateName).ToMessage(placeholders, message); + return ExecuteWebhookWithMessage(client, template, executeParams); + } - /// - /// Send a message to a webhook using a localized message template - /// - /// Client to use - /// Template Name - /// Oxide language to use - /// Message to use (optional) - /// Placeholders to apply (optional) - /// Webhook execution parameters - public IPromise ExecuteWebhookTemplate(DiscordClient client, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, WebhookCreateMessage message = null, PlaceholderData placeholders = null, WebhookExecuteParams executeParams = null) - { - WebhookCreateMessage template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, language).ToMessage(placeholders, message); - return ExecuteWebhookWithMessage(client, template, executeParams); - } + /// + /// Send a message to a webhook using a localized message template + /// + /// Client to use + /// Template Name + /// Oxide language to use + /// Message to use (optional) + /// Placeholders to apply (optional) + /// Webhook execution parameters + public IPromise ExecuteWebhookTemplate(DiscordClient client, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, WebhookCreateMessage message = null, PlaceholderData placeholders = null, WebhookExecuteParams executeParams = null) + { + WebhookCreateMessage template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(client.Plugin, templateName, language).ToMessage(placeholders, message); + return ExecuteWebhookWithMessage(client, template, executeParams); + } - /// - /// Gets a previously-sent webhook message from the same token. - /// See Edit Webhook Message - /// - /// Client to use - /// Message ID to get - /// Message Params - public IPromise GetWebhookMessage(DiscordClient client, Snowflake messageId, WebhookMessageParams messageParams = null) - { - InvalidSnowflakeException.ThrowIfInvalid(messageId, nameof(messageId)); - return client.Bot.Rest.Get(client,$"webhooks/{Id}/{Token}/messages/{messageId}{messageParams?.ToQueryString()}"); - } + /// + /// Gets a previously-sent webhook message from the same token. + /// See Edit Webhook Message + /// + /// Client to use + /// Message ID to get + /// Message Params + public IPromise GetWebhookMessage(DiscordClient client, Snowflake messageId, WebhookMessageParams messageParams = null) + { + InvalidSnowflakeException.ThrowIfInvalid(messageId); + return GetClient(client).Rest.Get(client,$"webhooks/{Id}/{Token}/messages/{messageId}{messageParams?.ToQueryString()}"); + } - /// - /// Edits a previously-sent webhook message from the same token. - /// See Edit Webhook Message - /// - /// Client to use - /// Message ID to edit - /// Message Params - /// The updated message - public IPromise EditWebhookMessage(DiscordClient client, Snowflake messageId, WebhookEditMessage message, WebhookMessageParams messageParams = null) - { - return client.Bot.Rest.Patch(client,$"webhooks/{Id}/{Token}/messages/{messageId}{messageParams?.ToQueryString()}", message); - } + /// + /// Edits a previously-sent webhook message from the same token. + /// See Edit Webhook Message + /// + /// Client to use + /// Message ID to edit + /// Message Params + /// The updated message + public IPromise EditWebhookMessage(DiscordClient client, Snowflake messageId, WebhookEditMessage message, WebhookMessageParams messageParams = null) + { + return GetClient(client).Rest.Patch(client,$"webhooks/{Id}/{Token}/messages/{messageId}{messageParams?.ToQueryString()}", message); + } - /// - /// Edit a message from a webhook using a global message template - /// - /// Client to use - /// Message ID of the message to edit - /// Plugin for the template - /// Template Name - /// Message to use (optional) - /// Placeholders to apply (optional) - /// Message Params - public IPromise EditWebhookMessageGlobalTemplate(DiscordClient client, Snowflake messageId, Plugin plugin, TemplateKey templateName, WebhookEditMessage message = null, PlaceholderData placeholders = null, WebhookMessageParams messageParams = null) - { - WebhookEditMessage template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(plugin, templateName).ToMessage(placeholders, message); - return EditWebhookMessage(client, messageId, template, messageParams); - } + /// + /// Edit a message from a webhook using a global message template + /// + /// Client to use + /// Message ID of the message to edit + /// Plugin for the template + /// Template Name + /// Message to use (optional) + /// Placeholders to apply (optional) + /// Message Params + public IPromise EditWebhookMessageGlobalTemplate(DiscordClient client, Snowflake messageId, Plugin plugin, TemplateKey templateName, WebhookEditMessage message = null, PlaceholderData placeholders = null, WebhookMessageParams messageParams = null) + { + WebhookEditMessage template = DiscordExtension.DiscordMessageTemplates.GetGlobalTemplate(plugin, templateName).ToMessage(placeholders, message); + return EditWebhookMessage(client, messageId, template, messageParams); + } - /// - /// Edit a message from a webhook using a localized message template - /// - /// Client to use - /// Message ID of the message to edit - /// Plugin for the template - /// Template Name - /// Oxide language to use - /// Message to use (optional) - /// Placeholders to apply (optional) - /// Message Params - public IPromise EditWebhookMessageTemplate(DiscordClient client, Snowflake messageId, Plugin plugin, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, WebhookEditMessage message = null, PlaceholderData placeholders = null, WebhookMessageParams messageParams = null) - { - WebhookEditMessage template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(plugin, templateName, language).ToMessage(placeholders, message); - return EditWebhookMessage(client, messageId, template, messageParams); - } + /// + /// Edit a message from a webhook using a localized message template + /// + /// Client to use + /// Message ID of the message to edit + /// Plugin for the template + /// Template Name + /// Oxide language to use + /// Message to use (optional) + /// Placeholders to apply (optional) + /// Message Params + public IPromise EditWebhookMessageTemplate(DiscordClient client, Snowflake messageId, Plugin plugin, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage, WebhookEditMessage message = null, PlaceholderData placeholders = null, WebhookMessageParams messageParams = null) + { + WebhookEditMessage template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(plugin, templateName, language).ToMessage(placeholders, message); + return EditWebhookMessage(client, messageId, template, messageParams); + } - /// - /// Deletes a message that was created by the webhook. - /// - /// Client to use - /// Message ID to delete - public IPromise DeleteWebhookMessage(DiscordClient client, Snowflake messageId) - { - InvalidSnowflakeException.ThrowIfInvalid(messageId, nameof(messageId)); - return client.Bot.Rest.Delete(client,$"webhooks/{Id}/{Token}/messages/{messageId}"); - } + /// + /// Deletes a message that was created by the webhook. + /// + /// Client to use + /// Message ID to delete + public IPromise DeleteWebhookMessage(DiscordClient client, Snowflake messageId) + { + InvalidSnowflakeException.ThrowIfInvalid(messageId); + return GetClient(client).Rest.Delete(client,$"webhooks/{Id}/{Token}/messages/{messageId}"); } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Webhooks/WebhookCreate.cs b/Oxide.Ext.Discord/Entities/Webhooks/WebhookCreate.cs index b0197d53e..fcea94b93 100644 --- a/Oxide.Ext.Discord/Entities/Webhooks/WebhookCreate.cs +++ b/Oxide.Ext.Discord/Entities/Webhooks/WebhookCreate.cs @@ -2,30 +2,29 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Webhook Create Structure +/// +public class WebhookCreate : IDiscordValidation { /// - /// Represents a Webhook Create Structure + /// Name of the webhook (1-80 characters) /// - public class WebhookCreate : IDiscordValidation - { - /// - /// Name of the webhook (1-80 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Image for the default webhook avatar - /// - [JsonProperty("avatar")] - public DiscordImageData? Avatar { get; set; } + /// + /// Image for the default webhook avatar + /// + [JsonProperty("avatar")] + public DiscordImageData? Avatar { get; set; } - /// - public void Validate() - { - InvalidWebhookException.ThrowIfInvalidName(Name); - InvalidImageDataException.ThrowIfInvalidImageData(Avatar); - } + /// + public void Validate() + { + InvalidWebhookException.ThrowIfInvalidName(Name); + InvalidImageDataException.ThrowIfInvalidImageData(Avatar); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Webhooks/WebhookCreateMessage.cs b/Oxide.Ext.Discord/Entities/Webhooks/WebhookCreateMessage.cs index e8fe823e1..6b0657156 100644 --- a/Oxide.Ext.Discord/Entities/Webhooks/WebhookCreateMessage.cs +++ b/Oxide.Ext.Discord/Entities/Webhooks/WebhookCreateMessage.cs @@ -2,44 +2,43 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Webhook Create Message +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class WebhookCreateMessage : MessageCreate { /// - /// Represents Webhook Create Message + /// Override the default username of the webhook /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class WebhookCreateMessage : MessageCreate - { - /// - /// Override the default username of the webhook - /// - [JsonProperty("username")] - public string Username { get; set; } + [JsonProperty("username")] + public string Username { get; set; } - /// - /// Override the default avatar of the webhook - /// - [JsonProperty("avatar_url")] - public string AvatarUrl { get; set; } + /// + /// Override the default avatar of the webhook + /// + [JsonProperty("avatar_url")] + public string AvatarUrl { get; set; } - /// - /// Name of thread to create - /// Requires the webhook channel to be a forum channel - /// - [JsonProperty("thread_name")] - public string ThreadName { get; set; } + /// + /// Name of thread to create + /// Requires the webhook channel to be a forum channel + /// + [JsonProperty("thread_name")] + public string ThreadName { get; set; } - /// - /// Array of tag ids to apply to the thread - /// requires the webhook channel to be a forum or media channel - /// - [JsonProperty("applied_tags")] - public List AppliedTags { get; set; } + /// + /// Array of tag ids to apply to the thread + /// requires the webhook channel to be a forum or media channel + /// + [JsonProperty("applied_tags")] + public List AppliedTags { get; set; } - /// - protected override void ValidateFlags() - { - InvalidMessageException.ThrowIfInvalidFlags(Flags, MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications, "Invalid Message Flags Used for Webhook Message. Only supported flags are MessageFlags.SuppressEmbeds and MessageFlags.SuppressNotifications"); - } + /// + protected override void ValidateFlags() + { + InvalidMessageException.ThrowIfInvalidFlags(Flags, MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications, "Invalid Message Flags Used for Webhook Message. Only supported flags are MessageFlags.SuppressEmbeds and MessageFlags.SuppressNotifications"); } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Webhooks/WebhookEdit.cs b/Oxide.Ext.Discord/Entities/Webhooks/WebhookEdit.cs index 2ad988216..860c66765 100644 --- a/Oxide.Ext.Discord/Entities/Webhooks/WebhookEdit.cs +++ b/Oxide.Ext.Discord/Entities/Webhooks/WebhookEdit.cs @@ -2,37 +2,36 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents a Webhook Create Structure +/// +public class WebhookEdit : IDiscordValidation { /// - /// Represents a Webhook Create Structure + /// Name of the webhook (1-80 characters) /// - public class WebhookEdit : IDiscordValidation - { - /// - /// Name of the webhook (1-80 characters) - /// - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Image for the default webhook avatar - /// - [JsonProperty("avatar")] - public DiscordImageData? Avatar { get; set; } + /// + /// Image for the default webhook avatar + /// + [JsonProperty("avatar")] + public DiscordImageData? Avatar { get; set; } - /// - /// Channel ID of the webhook - /// - [JsonProperty("channel_id")] - public Snowflake? ChannelId { get; set; } + /// + /// Channel ID of the webhook + /// + [JsonProperty("channel_id")] + public Snowflake? ChannelId { get; set; } - /// - public void Validate() - { - InvalidWebhookException.ThrowIfInvalidName(Name); - InvalidImageDataException.ThrowIfInvalidImageData(Avatar); - InvalidSnowflakeException.ThrowIfInvalid(ChannelId, false, nameof(ChannelId)); - } + /// + public void Validate() + { + InvalidWebhookException.ThrowIfInvalidName(Name); + InvalidImageDataException.ThrowIfInvalidImageData(Avatar); + InvalidSnowflakeException.ThrowIfInvalid(ChannelId, false); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Webhooks/WebhookEditMessage.cs b/Oxide.Ext.Discord/Entities/Webhooks/WebhookEditMessage.cs index 956232780..cc216cef5 100644 --- a/Oxide.Ext.Discord/Entities/Webhooks/WebhookEditMessage.cs +++ b/Oxide.Ext.Discord/Entities/Webhooks/WebhookEditMessage.cs @@ -4,94 +4,94 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Webhook Edit Message Structure +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class WebhookEditMessage : IFileAttachments, IDiscordValidation, IDiscordMessageTemplate { /// - /// Represents Webhook Edit Message Structure + /// The message contents (up to 2000 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class WebhookEditMessage : IFileAttachments, IDiscordValidation, IDiscordMessageTemplate - { - /// - /// The message contents (up to 2000 characters) - /// - [JsonProperty("content")] - public string Content { get; set; } + [JsonProperty("content")] + public string Content { get; set; } - /// - /// Embedded rich content (Up to 10 embeds) - /// - [JsonProperty("embeds")] - public List Embeds { get; set; } - - /// - /// Allowed mentions for the message - /// - [JsonProperty("allowed_mentions")] - public AllowedMentions AllowedMentions { get; set; } + /// + /// Embedded rich content (Up to 10 embeds) + /// + [JsonProperty("embeds")] + public List Embeds { get; set; } - /// - /// Components to include with the message - /// - [JsonProperty("components")] - public List Components { get; set; } + /// + /// Allowed mentions for the message + /// + [JsonProperty("allowed_mentions")] + public AllowedMentions AllowedMentions { get; set; } - /// - /// Attachments for the message - /// - [JsonProperty("attachments")] - public List Attachments { get; set; } + /// + /// Components to include with the message + /// + [JsonProperty("components")] + public List Components { get; set; } - /// - /// Attachments for a discord message - /// - public List FileAttachments { get; set; } + /// + /// Attachments for the message + /// + [JsonProperty("attachments")] + public List Attachments { get; set; } - /// - /// Adds a new embed to the list of embed to send - /// - /// Embed to add - /// This - /// Thrown if more than 10 embeds are added in a send as that is the discord limit - public WebhookEditMessage AddEmbed(DiscordEmbed embed) - { - if (Embeds == null) Embeds = new List(); - if (Embeds.Count >= 10) throw new IndexOutOfRangeException("Only 10 embed are allowed per message"); - - Embeds.Add(embed); - return this; - } + /// + /// Attachments for a discord message + /// + public List FileAttachments { get; set; } - /// - /// Adds an attachment to the message - /// - /// Name of the file - /// byte[] of the attachment - /// Attachment content type - /// Description for the attachment - public void AddAttachment(string filename, byte[] data, string contentType, string description = null) - { - InvalidFileNameException.ThrowIfInvalid(filename); - InvalidMessageException.ThrowIfInvalidAttachmentDescription(description); + /// + /// Adds a new embed to the list of embed to send + /// + /// Embed to add + /// This + /// Thrown if more than 10 embeds are added in a send as that is the discord limit + public WebhookEditMessage AddEmbed(DiscordEmbed embed) + { + if (Embeds == null) Embeds = new List(); + if (Embeds.Count >= 10) throw new IndexOutOfRangeException("Only 10 embed are allowed per message"); - if (FileAttachments == null) - { - FileAttachments = new List(); - } + Embeds.Add(embed); + return this; + } - if (Attachments == null) - { - Attachments = new List(); - } + /// + /// Adds an attachment to the message + /// + /// Name of the file + /// byte[] of the attachment + /// Attachment content type + /// Description for the attachment + /// Title of the attachment + public void AddAttachment(string filename, byte[] data, string contentType, string description = null, string title = null) + { + InvalidFileNameException.ThrowIfInvalid(filename); + InvalidMessageException.ThrowIfInvalidAttachmentDescription(description); - FileAttachments.Add(new MessageFileAttachment(filename, data, contentType)); - Attachments.Add(new MessageAttachment {Id = new Snowflake((ulong)FileAttachments.Count), Filename = filename, Description = description}); + if (FileAttachments == null) + { + FileAttachments = new List(); } - /// - public void Validate() + if (Attachments == null) { - InvalidMessageException.ThrowIfInvalidContent(Content); + Attachments = new List(); } + + FileAttachments.Add(new MessageFileAttachment(filename, data, contentType)); + Attachments.Add(new MessageAttachment {Id = new Snowflake((ulong)FileAttachments.Count), Filename = filename, Description = description, Title = title}); + } + + /// + public void Validate() + { + InvalidMessageException.ThrowIfInvalidContent(Content); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Webhooks/WebhookExecuteParams.cs b/Oxide.Ext.Discord/Entities/Webhooks/WebhookExecuteParams.cs index 8d6c2b82d..ca654c63d 100644 --- a/Oxide.Ext.Discord/Entities/Webhooks/WebhookExecuteParams.cs +++ b/Oxide.Ext.Discord/Entities/Webhooks/WebhookExecuteParams.cs @@ -1,71 +1,66 @@ using System; using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents parameters to execute a webhook +/// +public class WebhookExecuteParams : IDiscordQueryString { + internal static readonly WebhookExecuteParams Default = new(); + internal static readonly WebhookExecuteParams DefaultWait = new() + {Wait = true}; + /// - /// Represents parameters to execute a webhook + /// Which type of webhook are we trying to send (Discord, Slack, Github) + /// Defaults to Discord /// - public class WebhookExecuteParams : IDiscordQueryString - { - internal static readonly WebhookExecuteParams Default = new WebhookExecuteParams(); - internal static readonly WebhookExecuteParams DefaultWait = new WebhookExecuteParams{Wait = true}; + public WebhookSendType SendType { get; set; } = WebhookSendType.Discord; - /// - /// Which type of webhook are we trying to send (Discord, Slack, Github) - /// Defaults to Discord - /// - public WebhookSendType SendType { get; set; } = WebhookSendType.Discord; - - /// - /// Should we wait for a webhook to return a message or is this a fire and forget. - /// Not settable by devs as it's controlled by which method is called - /// - public bool Wait { get; internal set; } + /// + /// Should we wait for a webhook to return a message or is this a fire and forget. + /// Not settable by devs as it's controlled by which method is called + /// + public bool Wait { get; internal set; } - /// - /// If you're sending a message to a thread instead of a channel put the ID of the thread here. - /// This field is optional and defaults to null - /// - public Snowflake? ThreadId { get; set; } + /// + /// If you're sending a message to a thread instead of a channel put the ID of the thread here. + /// This field is optional and defaults to null + /// + public Snowflake? ThreadId { get; set; } - /// - public string ToQueryString() + /// + public string ToQueryString() + { + QueryStringBuilder builder = new(); + if (Wait) { - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); - if (Wait) - { - builder.Add("wait", "true"); - } + builder.Add("wait", "true"); + } - if (ThreadId.HasValue) - { - builder.Add("thread_id", ThreadId.Value.ToString()); - } - - return builder.ToStringAndFree(); + if (ThreadId.HasValue) + { + builder.Add("thread_id", ThreadId.Value.ToString()); } + + return builder.ToString(); + } - /// - /// Returns the URL formatting for the webhook type - /// - /// - /// - public string GetWebhookFormat() + /// + /// Returns the URL formatting for the webhook type + /// + /// + /// + public string GetWebhookFormat() + { + return SendType switch { - switch (SendType) - { - case WebhookSendType.Discord: - return string.Empty; - case WebhookSendType.Slack: - return "/slack"; - case WebhookSendType.Github: - return "/github"; - default: - throw new ArgumentOutOfRangeException(nameof(SendType), SendType, null); - } - } + WebhookSendType.Discord => string.Empty, + WebhookSendType.Slack => "/slack", + WebhookSendType.Github => "/github", + _ => throw new ArgumentOutOfRangeException(nameof(SendType), SendType, null) + }; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Webhooks/WebhookMessageParams.cs b/Oxide.Ext.Discord/Entities/Webhooks/WebhookMessageParams.cs index dbcd710f5..34681d829 100644 --- a/Oxide.Ext.Discord/Entities/Webhooks/WebhookMessageParams.cs +++ b/Oxide.Ext.Discord/Entities/Webhooks/WebhookMessageParams.cs @@ -1,31 +1,29 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents webhook message query string parameters +/// +public class WebhookMessageParams : IDiscordQueryString { /// - /// Represents webhook message query string parameters + /// If the message exists in a thread + /// This field is optional and defaults to null /// - public class WebhookMessageParams : IDiscordQueryString - { - /// - /// If the message exists in a thread - /// This field is optional and defaults to null - /// - public Snowflake? ThreadId { get; set; } + public Snowflake? ThreadId { get; set; } - /// - public string ToQueryString() - { - QueryStringBuilder builder = QueryStringBuilder.Create(DiscordPool.Internal); + /// + public string ToQueryString() + { + QueryStringBuilder builder = new(); - if (ThreadId.HasValue) - { - builder.Add("thread_id", ThreadId.Value.ToString()); - } - - return builder.ToStringAndFree(); + if (ThreadId.HasValue) + { + builder.Add("thread_id", ThreadId.Value.ToString()); } + + return builder.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Webhooks/WebhookSendType.cs b/Oxide.Ext.Discord/Entities/Webhooks/WebhookSendType.cs index 74707cf90..3e83eaedc 100644 --- a/Oxide.Ext.Discord/Entities/Webhooks/WebhookSendType.cs +++ b/Oxide.Ext.Discord/Entities/Webhooks/WebhookSendType.cs @@ -1,23 +1,22 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Use to control which webhook execute url to call +/// +public enum WebhookSendType : byte { /// - /// Use to control which webhook execute url to call + /// Webhook is for Discord /// - public enum WebhookSendType : byte - { - /// - /// Webhook is for Discord - /// - Discord, + Discord, - /// - /// Webhook is for slack - /// - Slack, + /// + /// Webhook is for slack + /// + Slack, - /// - /// Webhook is for github - /// - Github - } + /// + /// Webhook is for github + /// + Github } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Entities/Webhooks/WebhookType.cs b/Oxide.Ext.Discord/Entities/Webhooks/WebhookType.cs index 94e69240f..7fb09ec47 100644 --- a/Oxide.Ext.Discord/Entities/Webhooks/WebhookType.cs +++ b/Oxide.Ext.Discord/Entities/Webhooks/WebhookType.cs @@ -1,23 +1,22 @@ -namespace Oxide.Ext.Discord.Entities +namespace Oxide.Ext.Discord.Entities; + +/// +/// Represents Webhook Types +/// +public enum WebhookType : byte { /// - /// Represents Webhook Types + /// Incoming Webhooks can post messages to channels with a generated token /// - public enum WebhookType : byte - { - /// - /// Incoming Webhooks can post messages to channels with a generated token - /// - Incoming = 1, + Incoming = 1, - /// - /// Channel Follower Webhooks are internal webhooks used with Channel Following to post new messages into channels - /// - ChannelFollower = 2, + /// + /// Channel Follower Webhooks are internal webhooks used with Channel Following to post new messages into channels + /// + ChannelFollower = 2, - /// - /// Application webhooks are webhooks used with Interactions - /// - Application = 3 - } + /// + /// Application webhooks are webhooks used with Interactions + /// + Application = 3 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/BaseDiscordException.cs b/Oxide.Ext.Discord/Exceptions/BaseDiscordException.cs index 3b03e0adf..63436cbe7 100644 --- a/Oxide.Ext.Discord/Exceptions/BaseDiscordException.cs +++ b/Oxide.Ext.Discord/Exceptions/BaseDiscordException.cs @@ -1,24 +1,23 @@ using System; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents a base discord extension +/// +public abstract class BaseDiscordException : Exception { /// - /// Represents a base discord extension + /// Constructor /// - public abstract class BaseDiscordException : Exception - { - /// - /// Constructor - /// - protected BaseDiscordException() {} + protected BaseDiscordException() {} - /// - /// Constructor - /// - /// Exception message - protected BaseDiscordException(string message) : base($"Discord Extension Exception ({DiscordExtension.FullExtensionVersion}): {message}") - { + /// + /// Constructor + /// + /// Exception message + protected BaseDiscordException(string message) : base($"Discord Extension Exception ({DiscordExtension.FullExtensionVersion}): {message}") + { - } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Builders/ApplicationCommandBuilderException.cs b/Oxide.Ext.Discord/Exceptions/Builders/ApplicationCommandBuilderException.cs index 6b8bee1fd..39be4016d 100644 --- a/Oxide.Ext.Discord/Exceptions/Builders/ApplicationCommandBuilderException.cs +++ b/Oxide.Ext.Discord/Exceptions/Builders/ApplicationCommandBuilderException.cs @@ -1,47 +1,46 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an error when building Application Commands +/// +public class ApplicationCommandBuilderException : BaseDiscordException { - /// - /// Represents an error when building Application Commands - /// - public class ApplicationCommandBuilderException : BaseDiscordException - { - private ApplicationCommandBuilderException(string message) : base(message) { } + private ApplicationCommandBuilderException(string message) : base(message) { } - internal static void ThrowIfMixingSubCommandGroups(CommandOptionType? type) + internal static void ThrowIfMixingSubCommandGroups(CommandOptionType? type) + { + if (type.HasValue && type.Value != CommandOptionType.SubCommandGroup + && type.Value != CommandOptionType.SubCommand) { - if (type.HasValue && type.Value != CommandOptionType.SubCommandGroup - && type.Value != CommandOptionType.SubCommand) - { - throw new ApplicationCommandBuilderException("Cannot mix sub command / sub command groups with command options"); - } - } + throw new ApplicationCommandBuilderException("Cannot mix sub command / sub command groups with command options"); + } + } - internal static void ThrowIfMixingCommandOptions(CommandOptionType? type) + internal static void ThrowIfMixingCommandOptions(CommandOptionType? type) + { + if (type.HasValue && (type.Value == CommandOptionType.SubCommandGroup + || type.Value == CommandOptionType.SubCommand)) { - if (type.HasValue && (type.Value == CommandOptionType.SubCommandGroup - || type.Value == CommandOptionType.SubCommand)) - { - throw new ApplicationCommandBuilderException("Cannot mix sub command / sub command groups with command options"); - } - } + throw new ApplicationCommandBuilderException("Cannot mix sub command / sub command groups with command options"); + } + } - internal static void ThrowIfAddingSubCommandToMessageOrUser(ApplicationCommandBuilder builder) + internal static void ThrowIfAddingSubCommandToMessageOrUser(ApplicationCommandBuilder builder) + { + if (builder.Command.Type == ApplicationCommandType.Message || builder.Command.Type == ApplicationCommandType.User) { - if (builder.Command.Type == ApplicationCommandType.Message || builder.Command.Type == ApplicationCommandType.User) - { - throw new ApplicationCommandBuilderException("Message and User commands cannot have sub command groups"); - } + throw new ApplicationCommandBuilderException("Message and User commands cannot have sub command groups"); } + } - internal static void ThrowIfInvalidCommandOptionType(CommandOptionType type) + internal static void ThrowIfInvalidCommandOptionType(CommandOptionType type) + { + if (type == CommandOptionType.SubCommand || type == CommandOptionType.SubCommandGroup) { - if (type == CommandOptionType.SubCommand || type == CommandOptionType.SubCommandGroup) - { - throw new ApplicationCommandBuilderException($"{type} cannot be SubCommand or SubCommandGroup for option type"); - } + throw new ApplicationCommandBuilderException($"{type} cannot be SubCommand or SubCommandGroup for option type"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Builders/InteractionResponseBuilderException.cs b/Oxide.Ext.Discord/Exceptions/Builders/InteractionResponseBuilderException.cs index ea1257413..29ce42438 100644 --- a/Oxide.Ext.Discord/Exceptions/Builders/InteractionResponseBuilderException.cs +++ b/Oxide.Ext.Discord/Exceptions/Builders/InteractionResponseBuilderException.cs @@ -1,36 +1,35 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an Interaction Response Builder Exception +/// +public class InteractionResponseBuilderException : BaseDiscordException { - /// - /// Represents an Interaction Response Builder Exception - /// - public class InteractionResponseBuilderException : BaseDiscordException - { - private InteractionResponseBuilderException(string message) : base(message) { } + private InteractionResponseBuilderException(string message) : base(message) { } - internal static void ThrowIfInteractionIsAutoComplete(InteractionType type) + internal static void ThrowIfInteractionIsAutoComplete(InteractionType type) + { + if (type == InteractionType.ApplicationCommandAutoComplete) { - if (type == InteractionType.ApplicationCommandAutoComplete) - { - throw new InteractionResponseBuilderException("Cannot call this method because you can only add Auto Complete Choices to this interaction response"); - } + throw new InteractionResponseBuilderException("Cannot call this method because you can only add Auto Complete Choices to this interaction response"); } + } - internal static void ThrowIfInteractionIsNotAutoComplete(InteractionType type) + internal static void ThrowIfInteractionIsNotAutoComplete(InteractionType type) + { + if (type != InteractionType.ApplicationCommandAutoComplete) { - if (type != InteractionType.ApplicationCommandAutoComplete) - { - throw new InteractionResponseBuilderException("Cannot call this method because this is not an Auto Complete interaction"); - } + throw new InteractionResponseBuilderException("Cannot call this method because this is not an Auto Complete interaction"); } + } - internal static void ThrowIfInteractionIsModalSubmit(InteractionType type) + internal static void ThrowIfInteractionIsModalSubmit(InteractionType type) + { + if (type == InteractionType.ModalSubmit) { - if (type == InteractionType.ModalSubmit) - { - throw new InteractionResponseBuilderException("You cannot open a modal from another modal"); - } + throw new InteractionResponseBuilderException("You cannot open a modal from another modal"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Builders/MessageComponentBuilderException.cs b/Oxide.Ext.Discord/Exceptions/Builders/MessageComponentBuilderException.cs index 3d9813377..bbd8dad40 100644 --- a/Oxide.Ext.Discord/Exceptions/Builders/MessageComponentBuilderException.cs +++ b/Oxide.Ext.Discord/Exceptions/Builders/MessageComponentBuilderException.cs @@ -1,21 +1,20 @@ using Oxide.Ext.Discord.Builders; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception in Message Component Builder +/// +public class MessageComponentBuilderException : BaseDiscordException { - /// - /// Represents an exception in Message Component Builder - /// - public class MessageComponentBuilderException : BaseDiscordException - { - private MessageComponentBuilderException(string message) : base(message) { } + private MessageComponentBuilderException(string message) : base(message) { } - internal static void ThrowIfInvalidActionButtonStyle(ButtonStyle style) + internal static void ThrowIfInvalidActionButtonStyle(ButtonStyle style) + { + if (style == ButtonStyle.Link) { - if (style == ButtonStyle.Link) - { - throw new MessageComponentBuilderException($"Cannot add link button as action button. Please use {nameof(MessageComponentBuilder.AddLinkButton)} instead"); - } + throw new MessageComponentBuilderException($"Cannot add link button as action button. Please use {nameof(MessageComponentBuilder.AddLinkButton)} instead"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Data/DataInfoNotFoundException.cs b/Oxide.Ext.Discord/Exceptions/Data/DataInfoNotFoundException.cs index 7c7b93f29..170366369 100644 --- a/Oxide.Ext.Discord/Exceptions/Data/DataInfoNotFoundException.cs +++ b/Oxide.Ext.Discord/Exceptions/Data/DataInfoNotFoundException.cs @@ -1,21 +1,20 @@ using System; using Oxide.Ext.Discord.Data; -namespace Oxide.Ext.Discord.Exceptions.Data +namespace Oxide.Ext.Discord.Exceptions.Data; + +/// +/// Exception for Data Info not being fouind +/// +public class DataInfoNotFoundException : BaseDiscordException { - /// - /// Exception for Data Info not being fouind - /// - public class DataInfoNotFoundException : BaseDiscordException - { - private DataInfoNotFoundException(string message) : base(message) { } + private DataInfoNotFoundException(string message) : base(message) { } - internal static void ThrowIfDataInfoNotFound(Type type, DataFileInfo info) + internal static void ThrowIfDataInfoNotFound(Type type, DataFileInfo info) + { + if (info == null) { - if (info == null) - { - throw new DataInfoNotFoundException($"Failed to find DataInfo for type: {type.FullName}"); - } + throw new DataInfoNotFoundException($"Failed to find DataInfo for type: {type.FullName}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/DiscordClientException.cs b/Oxide.Ext.Discord/Exceptions/DiscordClientException.cs index 9f9dc2a59..10d428ae7 100644 --- a/Oxide.Ext.Discord/Exceptions/DiscordClientException.cs +++ b/Oxide.Ext.Discord/Exceptions/DiscordClientException.cs @@ -1,14 +1,13 @@ using Oxide.Ext.Discord.Clients; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exceptions for the +/// +public class DiscordClientException : BaseDiscordException { - /// - /// Exceptions for the - /// - public class DiscordClientException : BaseDiscordException - { - private DiscordClientException(string message) : base(message) {} + private DiscordClientException(string message) : base(message) {} - internal static DiscordClientException NotConnected() => new DiscordClientException("DiscordClient is not connected."); - } + internal static DiscordClientException NotConnected() => new("DiscordClient is not connected."); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Applications/ApplicationRoleConnectionMetadataException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Applications/ApplicationRoleConnectionMetadataException.cs index b36ae8a7d..db063d29d 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Applications/ApplicationRoleConnectionMetadataException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Applications/ApplicationRoleConnectionMetadataException.cs @@ -1,65 +1,64 @@ using System.Text.RegularExpressions; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exceptions for +/// +public class ApplicationRoleConnectionMetadataException : BaseDiscordException { - /// - /// Exceptions for - /// - public class ApplicationRoleConnectionMetadataException : BaseDiscordException - { - private static readonly Regex KeyRegex = new Regex(@"^\w+$", RegexOptions.Compiled); + private static readonly Regex KeyRegex = new(@"^\w+$", RegexOptions.Compiled); - private ApplicationRoleConnectionMetadataException(string message) : base(message) { } + private ApplicationRoleConnectionMetadataException(string message) : base(message) { } - internal static void ThrowIfInvalidKeyException(string key) - { - const int MaxLength = 50; + internal static void ThrowIfInvalidKeyException(string key) + { + const int MaxLength = 50; - if (string.IsNullOrEmpty(key)) - { - throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Key)} cannot be null or empty"); - } + if (string.IsNullOrEmpty(key)) + { + throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Key)} cannot be null or empty"); + } - if (key.Length > MaxLength) - { - throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Key)} cannot be more than {MaxLength} characters"); - } + if (key.Length > MaxLength) + { + throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Key)} cannot be more than {MaxLength} characters"); + } - if (!KeyRegex.IsMatch(key)) - { - throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Key)} can only be the following characters a-z, 0-9, or _"); - } + if (!KeyRegex.IsMatch(key)) + { + throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Key)} can only be the following characters a-z, 0-9, or _"); } + } - internal static void ThrowIfInvalidNameException(string name) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidNameException(string name) + { + const int MaxLength = 100; - if (string.IsNullOrEmpty(name)) - { - throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Name)} cannot be null or empty"); - } + if (string.IsNullOrEmpty(name)) + { + throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Name)} cannot be null or empty"); + } - if (name.Length > MaxLength) - { - throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Name)} cannot be more than {MaxLength} characters"); - } + if (name.Length > MaxLength) + { + throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Name)} cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidDescriptionException(string name) - { - const int MaxLength = 200; + internal static void ThrowIfInvalidDescriptionException(string name) + { + const int MaxLength = 200; - if (string.IsNullOrEmpty(name)) - { - throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Description)} cannot be null or empty"); - } + if (string.IsNullOrEmpty(name)) + { + throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Description)} cannot be null or empty"); + } - if (name.Length > MaxLength) - { - throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Description)} cannot be more than {MaxLength} characters"); - } + if (name.Length > MaxLength) + { + throw new ApplicationRoleConnectionMetadataException($"{nameof(ApplicationRoleConnectionMetadata)}.{nameof(ApplicationRoleConnectionMetadata.Description)} cannot be more than {MaxLength} characters"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Applications/DiscordApplicationException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Applications/DiscordApplicationException.cs index 89bf9aa30..d0e105a6c 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Applications/DiscordApplicationException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Applications/DiscordApplicationException.cs @@ -1,28 +1,27 @@ using System.Collections.Generic; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exceptions for +/// +public class DiscordApplicationException : BaseDiscordException { - /// - /// Exceptions for - /// - public class DiscordApplicationException : BaseDiscordException - { - private DiscordApplicationException(string message) : base(message) { } + private DiscordApplicationException(string message) : base(message) { } - internal static void ThrowIfInvalidApplicationRoleConnectionMetadataLength(List records) - { - const int MaxLength = 5; + internal static void ThrowIfInvalidApplicationRoleConnectionMetadataLength(List records) + { + const int MaxLength = 5; - if (records == null) - { - throw new DiscordApplicationException($"{nameof(records)} cannot be null"); - } + if (records == null) + { + throw new DiscordApplicationException($"{nameof(records)} cannot be null"); + } - if (records.Count > MaxLength) - { - throw new DiscordApplicationException($"{nameof(records)} cannot have more than {MaxLength} records"); - } + if (records.Count > MaxLength) + { + throw new DiscordApplicationException($"{nameof(records)} cannot have more than {MaxLength} records"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/AutoMod/AutoModTriggerMetadataException.cs b/Oxide.Ext.Discord/Exceptions/Entities/AutoMod/AutoModTriggerMetadataException.cs index 6b09cd361..4093fec72 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/AutoMod/AutoModTriggerMetadataException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/AutoMod/AutoModTriggerMetadataException.cs @@ -1,131 +1,130 @@ using System.Collections.Generic; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exceptions for +/// +public class AutoModTriggerMetadataException : BaseDiscordException { - /// - /// Exceptions for - /// - public class AutoModTriggerMetadataException : BaseDiscordException - { - private AutoModTriggerMetadataException(string message) : base(message) { } + private AutoModTriggerMetadataException(string message) : base(message) { } - internal static void ThrowIfKeywordFilterInvalid(List filter) - { - const int MaxKeywordFilterLength = 1000; - const int MaxKeywordLength = 60; + internal static void ThrowIfKeywordFilterInvalid(List filter) + { + const int MaxKeywordFilterLength = 1000; + const int MaxKeywordLength = 60; - if (filter == null) - { - return; - } + if (filter == null) + { + return; + } - if (filter.Count > MaxKeywordFilterLength) - { - throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.KeywordFilter)} cannot have more than {MaxKeywordFilterLength} keywords"); - } + if (filter.Count > MaxKeywordFilterLength) + { + throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.KeywordFilter)} cannot have more than {MaxKeywordFilterLength} keywords"); + } - for (int index = 0; index < filter.Count; index++) + for (int index = 0; index < filter.Count; index++) + { + string keyword = filter[index]; + if (keyword.Length > MaxKeywordLength) { - string keyword = filter[index]; - if (keyword.Length > MaxKeywordLength) - { - throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.KeywordFilter)} keyword {keyword} cannot have more than {MaxKeywordLength} characters"); - } + throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.KeywordFilter)} keyword {keyword} cannot have more than {MaxKeywordLength} characters"); } } + } - internal static void ThrowIfRegexPatternsInvalid(List patterns) - { - const int MaxPatternsLength = 10; - const int MaxRegexLength = 260; + internal static void ThrowIfRegexPatternsInvalid(List patterns) + { + const int MaxPatternsLength = 10; + const int MaxRegexLength = 260; - if (patterns == null) - { - return; - } + if (patterns == null) + { + return; + } - if (patterns.Count > MaxPatternsLength) - { - throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.RegexPatterns)} cannot have more than {MaxPatternsLength} patterns"); - } + if (patterns.Count > MaxPatternsLength) + { + throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.RegexPatterns)} cannot have more than {MaxPatternsLength} patterns"); + } - for (int index = 0; index < patterns.Count; index++) + for (int index = 0; index < patterns.Count; index++) + { + string regex = patterns[index]; + if (regex.Length > MaxRegexLength) { - string regex = patterns[index]; - if (regex.Length > MaxRegexLength) - { - throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.KeywordFilter)} regex {regex} cannot have more than {MaxRegexLength} characters"); - } + throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.KeywordFilter)} regex {regex} cannot have more than {MaxRegexLength} characters"); } } + } - internal static void ThrowIfAllowListInvalid(List allowList, AutoModTriggerType type) + internal static void ThrowIfAllowListInvalid(List allowList, AutoModTriggerType type) + { + if (allowList == null) { - if (allowList == null) - { - return; - } - - switch (type) - { - case AutoModTriggerType.Keyword: - ThrowIfAllowListKeywordInvalid(allowList); - break; - case AutoModTriggerType.KeywordPreset: - ThrowIfAllowListKeywordPresetInvalid(allowList); - break; - } + return; } - private static void ThrowIfAllowListKeywordInvalid(List allowList) + switch (type) { - const int MaxAllowListLength = 100; - const int MaxAllowLength = 60; + case AutoModTriggerType.Keyword: + ThrowIfAllowListKeywordInvalid(allowList); + break; + case AutoModTriggerType.KeywordPreset: + ThrowIfAllowListKeywordPresetInvalid(allowList); + break; + } + } + + private static void ThrowIfAllowListKeywordInvalid(List allowList) + { + const int MaxAllowListLength = 100; + const int MaxAllowLength = 60; - if (allowList.Count > MaxAllowListLength) - { - throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.AllowList)} cannot have more than {MaxAllowListLength} allowed strings"); - } + if (allowList.Count > MaxAllowListLength) + { + throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.AllowList)} cannot have more than {MaxAllowListLength} allowed strings"); + } - for (int index = 0; index < allowList.Count; index++) + for (int index = 0; index < allowList.Count; index++) + { + string str = allowList[index]; + if (str.Length > MaxAllowLength) { - string str = allowList[index]; - if (str.Length > MaxAllowLength) - { - throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.AllowList)} strings {str} cannot have more than {MaxAllowLength} characters"); - } + throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.AllowList)} strings {str} cannot have more than {MaxAllowLength} characters"); } } + } - private static void ThrowIfAllowListKeywordPresetInvalid(List allowList) - { - const int MaxAllowListLength = 1000; - const int MaxAllowLength = 60; + private static void ThrowIfAllowListKeywordPresetInvalid(List allowList) + { + const int MaxAllowListLength = 1000; + const int MaxAllowLength = 60; - if (allowList.Count > MaxAllowListLength) - { - throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.AllowList)} cannot have more than {MaxAllowListLength} allowed strings"); - } + if (allowList.Count > MaxAllowListLength) + { + throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.AllowList)} cannot have more than {MaxAllowListLength} allowed strings"); + } - for (int index = 0; index < allowList.Count; index++) + for (int index = 0; index < allowList.Count; index++) + { + string str = allowList[index]; + if (str.Length > MaxAllowLength) { - string str = allowList[index]; - if (str.Length > MaxAllowLength) - { - throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.AllowList)} strings {str} cannot have more than {MaxAllowLength} characters"); - } + throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.AllowList)} strings {str} cannot have more than {MaxAllowLength} characters"); } } + } - internal static void ThrowIfInvalidMentionTotalLimit(int limit) - { - const int MaxLimit = 50; + internal static void ThrowIfInvalidMentionTotalLimit(int limit) + { + const int MaxLimit = 50; - if (limit > MaxLimit) - { - throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.AllowList)} cannot be more than {MaxLimit}"); - } + if (limit > MaxLimit) + { + throw new AutoModTriggerMetadataException($"{nameof(AutoModTriggerMetadata)}.{nameof(AutoModTriggerMetadata.AllowList)} cannot be more than {MaxLimit}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidChannelException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidChannelException.cs index d26ee936d..e9ed796fb 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidChannelException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidChannelException.cs @@ -1,147 +1,135 @@ using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents using an invalid channel +/// +public class InvalidChannelException : BaseDiscordException { - /// - /// Represents using an invalid channel - /// - public class InvalidChannelException : BaseDiscordException - { - private InvalidChannelException(string message): base(message) { } + private InvalidChannelException(string message): base(message) { } - internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) + { + const int MaxLength = 100; - if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) - { - throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Name)} cannot be less than 1 character"); - } + if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) + { + throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Name)} cannot be less than 1 character"); + } - if (name.Length > MaxLength) - { - throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Name)} cannot be more than {MaxLength} characters"); - } + if (name.Length > MaxLength) + { + throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Name)} cannot be more than {MaxLength} characters"); } + } + + internal static void ThrowIfInvalidTopic(string topic, ChannelType type, bool allowNullOrEmpty) + { + const int MaxForumLength = 4096; + const int MaxTopicLength = 1024; - internal static void ThrowIfInvalidTopic(string topic, ChannelType type, bool allowNullOrEmpty) + if (string.IsNullOrEmpty(topic)) { - const int MaxForumLength = 4096; - const int MaxTopicLength = 1024; - - if (!allowNullOrEmpty && string.IsNullOrEmpty(topic)) + if (!allowNullOrEmpty) { - throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Topic)} cannot be less than 1 character"); + throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Topic)} cannot be less than 1 character"); } + return; + } - if (type == ChannelType.GuildForum || type == ChannelType.GuildMedia) + if (type is ChannelType.GuildForum or ChannelType.GuildMedia) + { + if (topic.Length > MaxForumLength) { - if (topic.Length > MaxForumLength) - { - throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Topic)} cannot be more than {MaxForumLength} characters for Guild Forum or Guild Media Channels"); - } - - return; + throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Topic)} cannot be more than {MaxForumLength} characters for Guild Forum or Guild Media Channels"); } + + return; + } - if (topic.Length > MaxTopicLength) - { - throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Topic)} cannot be more than {MaxTopicLength} characters"); - } + if (topic.Length > MaxTopicLength) + { + throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Topic)} cannot be more than {MaxTopicLength} characters"); } + } - internal static void ThrowIfInvalidRateLimitPerUser(int? rateLimitPerUser) + internal static void ThrowIfInvalidRateLimitPerUser(int? rateLimitPerUser) + { + const int MinRateLimit = 0; + const int MaxRateLimit = 21600; + switch (rateLimitPerUser) { - const int MinRateLimit = 0; - const int MaxRateLimit = 21600; - if (!rateLimitPerUser.HasValue) - { + case null: return; - } - - if (rateLimitPerUser.Value < MinRateLimit) - { + case < MinRateLimit: throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.RateLimitPerUser)} cannot be less than {MinRateLimit}"); - } - - if (rateLimitPerUser.Value > MaxRateLimit) - { + case > MaxRateLimit: throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.RateLimitPerUser)} cannot be more than {MaxRateLimit}"); - } } + } - internal static void ThrowIfInvalidBitRate(int? bitRate) + internal static void ThrowIfInvalidBitRate(int? bitRate) + { + const int MinBitRate = 8000; + const int MaxBitRate = 128000; + switch (bitRate) { - const int MinBitRate = 8000; - const int MaxBitRate = 128000; - if (!bitRate.HasValue) - { + case null: return; - } - - if (bitRate.Value < MinBitRate) - { + case < MinBitRate: throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Bitrate)} cannot be less than {MinBitRate}"); - } - - if (bitRate.Value > MaxBitRate) - { + case > MaxBitRate: throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.Bitrate)} cannot be more than {MaxBitRate}"); - } } + } - internal static void ThrowIfInvalidUserLimit(int? userLimit) - { - const int MinUserLimit = 0; - const int MaxUserLimit = 99; + internal static void ThrowIfInvalidUserLimit(int? userLimit) + { + const int MinUserLimit = 0; + const int MaxUserLimit = 99; - if (!userLimit.HasValue) - { + switch (userLimit) + { + case null: return; - } - - if (userLimit.Value < MinUserLimit) - { + case < MinUserLimit: throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.UserLimit)} cannot be less than {MinUserLimit}"); - } - - if (userLimit.Value > MaxUserLimit) - { + case > MaxUserLimit: throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.UserLimit)} cannot be more than {MaxUserLimit}"); - } } + } - internal static void ThrowIfInvalidParentId(Snowflake? parentId) + internal static void ThrowIfInvalidParentId(Snowflake? parentId) + { + if (parentId.HasValue && !parentId.Value.IsValid()) { - if (parentId.HasValue && !parentId.Value.IsValid()) - { - throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.ParentId)} is not a valid snowflake"); - } + throw new InvalidChannelException($"{nameof(DiscordChannel)}.{nameof(DiscordChannel.ParentId)} is not a valid snowflake"); } + } - internal static void ThrowIfNotThread(DiscordChannel channel, string message) + internal static void ThrowIfNotThread(DiscordChannel channel, string message) + { + if (channel == null || !channel.IsThreadChannel()) { - if (channel == null || !channel.IsThreadChannel()) - { - throw new InvalidChannelException(message); - } + throw new InvalidChannelException(message); } + } - internal static void ThrowIfNotGuildChannel(DiscordChannel channel, string message) + internal static void ThrowIfNotGuildChannel(DiscordChannel channel, string message) + { + if (channel == null || !channel.IsDmChannel()) { - if (channel == null || !channel.IsDmChannel()) - { - throw new InvalidChannelException(message); - } + throw new InvalidChannelException(message); } + } - internal static void ThrowIfChannelToSelf(Snowflake userId, DiscordClient client) + internal static void ThrowIfChannelToSelf(Snowflake userId, DiscordClient client) + { + if (userId == client.Bot.BotUser.Id) { - if (userId == client.Bot.BotUser.Id) - { - throw new InvalidChannelException("Tried to create a direct message channel to yourself which is not allowed."); - } + throw new InvalidChannelException("Tried to create a direct message channel to yourself which is not allowed."); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidChannelInviteException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidChannelInviteException.cs index 80f700f03..cf4f85996 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidChannelInviteException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidChannelInviteException.cs @@ -1,62 +1,61 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an error in channel invite +/// +public class InvalidChannelInviteException : BaseDiscordException { - /// - /// Represents an error in channel invite - /// - public class InvalidChannelInviteException : BaseDiscordException - { - private InvalidChannelInviteException(string message) : base(message) { } + private InvalidChannelInviteException(string message) : base(message) { } - internal static void ThrowIfInvalidMaxAge(int? maxAge) - { - const int MinAge = 0; - const int MaxAge = 604800; + internal static void ThrowIfInvalidMaxAge(int? maxAge) + { + const int MinAge = 0; + const int MaxAge = 604800; - if (!maxAge.HasValue) - { - return; - } + if (!maxAge.HasValue) + { + return; + } - if (maxAge.Value < MinAge) - { - throw new InvalidChannelInviteException($"{nameof(ChannelInvite)}.{nameof(ChannelInvite.MaxAge)} cannot be less than {MinAge}"); - } + if (maxAge.Value < MinAge) + { + throw new InvalidChannelInviteException($"{nameof(ChannelInvite)}.{nameof(ChannelInvite.MaxAge)} cannot be less than {MinAge}"); + } - if (maxAge.Value > MaxAge) - { - throw new InvalidChannelInviteException($"{nameof(ChannelInvite)}.{nameof(ChannelInvite.MaxAge)} cannot be more than {MaxAge}"); - } + if (maxAge.Value > MaxAge) + { + throw new InvalidChannelInviteException($"{nameof(ChannelInvite)}.{nameof(ChannelInvite.MaxAge)} cannot be more than {MaxAge}"); } + } - internal static void ThrowIfInvalidMaxUses(int? maxUses) - { - const int MinUse = 0; - const int MaxUse = 100; + internal static void ThrowIfInvalidMaxUses(int? maxUses) + { + const int MinUse = 0; + const int MaxUse = 100; - if (!maxUses.HasValue) - { - return; - } + if (!maxUses.HasValue) + { + return; + } - if (maxUses.Value < MinUse) - { - throw new InvalidChannelInviteException($"{nameof(ChannelInvite)}.{nameof(ChannelInvite.MaxUses)} cannot be less than {MinUse}"); - } + if (maxUses.Value < MinUse) + { + throw new InvalidChannelInviteException($"{nameof(ChannelInvite)}.{nameof(ChannelInvite.MaxUses)} cannot be less than {MinUse}"); + } - if (maxUses.Value > MaxUse) - { - throw new InvalidChannelInviteException($"{nameof(ChannelInvite)}.{nameof(ChannelInvite.MaxUses)} cannot be more than {MaxUse}"); - } + if (maxUses.Value > MaxUse) + { + throw new InvalidChannelInviteException($"{nameof(ChannelInvite)}.{nameof(ChannelInvite.MaxUses)} cannot be more than {MaxUse}"); } + } - internal static void ThrowIfInvalidTargetUser(Snowflake? targetUser) + internal static void ThrowIfInvalidTargetUser(Snowflake? targetUser) + { + if (targetUser.HasValue && !targetUser.Value.IsValid()) { - if (targetUser.HasValue && !targetUser.Value.IsValid()) - { - throw new InvalidChannelInviteException($"{nameof(ChannelInvite)}.{nameof(ChannelInvite.TargetUser)} is not a valid snowflake ID"); - } + throw new InvalidChannelInviteException($"{nameof(ChannelInvite)}.{nameof(ChannelInvite.TargetUser)} is not a valid snowflake ID"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidForumTagException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidForumTagException.cs index ccd141dd5..571520783 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidForumTagException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidForumTagException.cs @@ -1,23 +1,22 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception for channel threads +/// +public class InvalidForumTagException : BaseDiscordException { - /// - /// Represents an exception for channel threads - /// - public class InvalidForumTagException : BaseDiscordException - { - private InvalidForumTagException(string message) : base(message) { } + private InvalidForumTagException(string message) : base(message) { } - internal static void ThrowIfInvalidName(string name) - { - const int MaxLength = 20; + internal static void ThrowIfInvalidName(string name) + { + const int MaxLength = 20; - if (!string.IsNullOrEmpty(name) && name.Length > MaxLength) - { - throw new InvalidForumTagException($"{nameof(ForumTag)}.{nameof(ForumTag.Name)} cannot be more than {MaxLength} characters"); - } + if (!string.IsNullOrEmpty(name) && name.Length > MaxLength) + { + throw new InvalidForumTagException($"{nameof(ForumTag)}.{nameof(ForumTag.Name)} cannot be more than {MaxLength} characters"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidThreadException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidThreadException.cs index f4c648441..58b7166d1 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidThreadException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Channels/InvalidThreadException.cs @@ -1,53 +1,52 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception for channel threads +/// +public class InvalidThreadException : BaseDiscordException { - /// - /// Represents an exception for channel threads - /// - public class InvalidThreadException : BaseDiscordException - { - private InvalidThreadException(string message) : base(message) { } + private InvalidThreadException(string message) : base(message) { } - internal static void ThrowIfInvalidAutoArchiveDuration(int? autoArchiveDuration) + internal static void ThrowIfInvalidAutoArchiveDuration(int? autoArchiveDuration) + { + if (!autoArchiveDuration.HasValue) { - if (!autoArchiveDuration.HasValue) - { - return; - } + return; + } - switch (autoArchiveDuration.Value) - { - case 60: - case 1440: - case 4320: - case 10080: - break; - default: - throw new InvalidThreadException("AutoArchiveDuration must be one of 60, 1440, 4320, or 10080"); - } + switch (autoArchiveDuration.Value) + { + case 60: + case 1440: + case 4320: + case 10080: + break; + default: + throw new InvalidThreadException("AutoArchiveDuration must be one of 60, 1440, 4320, or 10080"); } + } - internal static void ThrowIfInvalidChannelType(ChannelType type) + internal static void ThrowIfInvalidChannelType(ChannelType type) + { + switch (type) { - switch (type) - { - case ChannelType.GuildNewsThread: - case ChannelType.GuildPublicThread: - case ChannelType.GuildPrivateThread: - break; + case ChannelType.GuildNewsThread: + case ChannelType.GuildPublicThread: + case ChannelType.GuildPrivateThread: + break; - default: - throw new InvalidThreadException("Type must be one of GuildNewsThread, GuildPublicThread, or GuildPrivateThread"); - } + default: + throw new InvalidThreadException("Type must be one of GuildNewsThread, GuildPublicThread, or GuildPrivateThread"); } + } - internal static void ThrowIfInvalidForumCreateMessage(MessageCreate create) + internal static void ThrowIfInvalidForumCreateMessage(MessageCreate create) + { + if (create == null) { - if (create == null) - { - throw new InvalidThreadException("Message cannot be null for ThreadForumCreate"); - } + throw new InvalidThreadException("Message cannot be null for ThreadForumCreate"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Emojis/InvalidEmojiException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Emojis/InvalidEmojiException.cs index 132b9b838..20df227af 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Emojis/InvalidEmojiException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Emojis/InvalidEmojiException.cs @@ -1,72 +1,71 @@ using System.Text.RegularExpressions; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Error thrown when an emoji string fails validation +/// +public class InvalidEmojiException : BaseDiscordException { /// - /// Error thrown when an emoji string fails validation + /// Regex emoji validation matching discord emoji formatting standards /// - public class InvalidEmojiException : BaseDiscordException - { - /// - /// Regex emoji validation matching discord emoji formatting standards - /// - public static readonly Regex EmojiValidation = new Regex("^.+:[0-9]+$", RegexOptions.Compiled); + public static readonly Regex EmojiValidation = new("^.+:[0-9]+$", RegexOptions.Compiled); - private InvalidEmojiException(string emojiValue, string validationError) : base($"'{emojiValue}' failed emoji validation with error: {validationError}") { } + private InvalidEmojiException(string emojiValue, string validationError) : base($"'{emojiValue}' failed emoji validation with error: {validationError}") { } - private InvalidEmojiException(string message) : base(message) { } + private InvalidEmojiException(string message) : base(message) { } - internal static void ThrowIfInvalidEmojiString(string emoji) + internal static void ThrowIfInvalidEmojiString(string emoji) + { + if (string.IsNullOrEmpty(emoji)) { - if (string.IsNullOrEmpty(emoji)) - { - throw new InvalidEmojiException(emoji, "Emoji string cannot be null or empty."); - } + throw new InvalidEmojiException(emoji, "Emoji string cannot be null or empty."); + } - if (emoji.Length == 2 && !char.IsSurrogatePair(emoji[0], emoji[1])) - { - throw new InvalidEmojiException(emoji, "Emoji of length 2 must be a surrogate pair"); - } + if (emoji.Length == 2 && !char.IsSurrogatePair(emoji[0], emoji[1])) + { + throw new InvalidEmojiException(emoji, "Emoji of length 2 must be a surrogate pair"); + } - if (emoji.Length > 2 && !EmojiValidation.IsMatch(emoji)) - { - throw new InvalidEmojiException(emoji, "Emoji string is not in the correct format.\n" + - "If using a normal emoji please use the unicode character for that emoji.\n" + - "If using a custom emoji the format must be emojiName:emojiId\n" + - "If using a custom animated emoji the format must be a:emojiName:emojiId"); - } + if (emoji.Length > 2 && !EmojiValidation.IsMatch(emoji)) + { + throw new InvalidEmojiException(emoji, "Emoji string is not in the correct format.\n" + + "If using a normal emoji please use the unicode character for that emoji.\n" + + "If using a custom emoji the format must be emojiName:emojiId\n" + + "If using a custom animated emoji the format must be a:emojiName:emojiId"); } + } - internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) + internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) + { + if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) { - if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) - { - throw new InvalidEmojiException("Name cannot be less than 1 character"); - } + throw new InvalidEmojiException("Name cannot be less than 1 character"); } + } - internal static void ThrowIfInvalidImageData(DiscordImageData image) - { - const int MaxSize = 256; + internal static void ThrowIfInvalidImageData(DiscordImageData image) + { + const int MaxSize = 256; - if (!image.IsValid()) - { - throw new InvalidEmojiException("ImageData is required"); - } + if (!image.IsValid()) + { + throw new InvalidEmojiException("ImageData is required"); + } - if (image.GetImageSize(DiscordImageSize.KiloBytes) > MaxSize) - { - throw new InvalidEmojiException($"ImageData cannot be more than {MaxSize} kilobytes"); - } + if (image.GetImageSize(DiscordImageSize.KiloBytes) > MaxSize) + { + throw new InvalidEmojiException($"ImageData cannot be more than {MaxSize} kilobytes"); } + } - internal static void ThrowIfInvalidImageData(DiscordImageData? image) + internal static void ThrowIfInvalidImageData(DiscordImageData? image) + { + if (image.HasValue) { - if (image.HasValue) - { - ThrowIfInvalidImageData(image.Value); - } + ThrowIfInvalidImageData(image.Value); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildBanException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildBanException.cs index b76a66390..59a227e9c 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildBanException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildBanException.cs @@ -1,33 +1,32 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an error in channel ban +/// +public class InvalidGuildBanException : BaseDiscordException { - /// - /// Represents an error in channel ban - /// - public class InvalidGuildBanException : BaseDiscordException - { - private InvalidGuildBanException(string message) : base(message) { } + private InvalidGuildBanException(string message) : base(message) { } - internal static void ThrowIfInvalidDeleteMessageSeconds(int? seconds) - { - const int MinSeconds = 0; - const int MaxSeconds = 604800; + internal static void ThrowIfInvalidDeleteMessageSeconds(int? seconds) + { + const int MinSeconds = 0; + const int MaxSeconds = 604800; - if (!seconds.HasValue) - { - return; - } + if (!seconds.HasValue) + { + return; + } - if (seconds.Value < MinSeconds) - { - throw new InvalidGuildBanException($"{nameof(GuildBanCreate)}.{nameof(GuildBanCreate.DeleteMessageSeconds)} cannot be less than {MinSeconds} days"); - } + if (seconds.Value < MinSeconds) + { + throw new InvalidGuildBanException($"{nameof(GuildBanCreate)}.{nameof(GuildBanCreate.DeleteMessageSeconds)} cannot be less than {MinSeconds} days"); + } - if (seconds.Value < MaxSeconds) - { - throw new InvalidGuildBanException($"{nameof(GuildBanCreate)}.{nameof(GuildBanCreate.DeleteMessageSeconds)} cannot be more than {MaxSeconds} days"); - } + if (seconds.Value < MaxSeconds) + { + throw new InvalidGuildBanException($"{nameof(GuildBanCreate)}.{nameof(GuildBanCreate.DeleteMessageSeconds)} cannot be more than {MaxSeconds} days"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildException.cs index abd7d72c3..cc6953d18 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildException.cs @@ -1,28 +1,27 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception in guild +/// +public class InvalidGuildException : BaseDiscordException { - /// - /// Represents an exception in guild - /// - public class InvalidGuildException : BaseDiscordException - { - private InvalidGuildException(string message) : base(message) { } + private InvalidGuildException(string message) : base(message) { } - internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) - { - const int MinLength = 2; - const int MaxLength = 100; + internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) + { + const int MinLength = 2; + const int MaxLength = 100; - if (!allowNullOrEmpty && (string.IsNullOrEmpty(name) || name.Length < MinLength)) - { - throw new InvalidGuildException($"{nameof(GuildCreate)}.{nameof(GuildCreate.Name)} cannot be less than {MinLength} character"); - } + if (!allowNullOrEmpty && (string.IsNullOrEmpty(name) || name.Length < MinLength)) + { + throw new InvalidGuildException($"{nameof(GuildCreate)}.{nameof(GuildCreate.Name)} cannot be less than {MinLength} character"); + } - if (name.Length > MaxLength) - { - throw new InvalidGuildException($"{nameof(GuildCreate)}.{nameof(GuildCreate.Name)} cannot be more than {MaxLength} characters"); - } + if (name.Length > MaxLength) + { + throw new InvalidGuildException($"{nameof(GuildCreate)}.{nameof(GuildCreate.Name)} cannot be more than {MaxLength} characters"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildListMembersException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildListMembersException.cs index bacabd6d5..03a6e7e70 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildListMembersException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildListMembersException.cs @@ -1,28 +1,27 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception in guid list request +/// +public class InvalidGuildListMembersException : BaseDiscordException { - /// - /// Represents an exception in guid list request - /// - public class InvalidGuildListMembersException : BaseDiscordException - { - private InvalidGuildListMembersException(string message) : base(message) { } + private InvalidGuildListMembersException(string message) : base(message) { } - internal static void ThrowIfInvalidLimit(int? limit) - { - const int MinLimit = 0; - const int MaxLimit = 1000; + internal static void ThrowIfInvalidLimit(int? limit) + { + const int MinLimit = 0; + const int MaxLimit = 1000; - if (limit < MinLimit) - { - throw new InvalidGuildListMembersException($"{nameof(GuildListMembers)}.{nameof(GuildListMembers.Limit)} cannot be less than {MinLimit}"); - } + if (limit < MinLimit) + { + throw new InvalidGuildListMembersException($"{nameof(GuildListMembers)}.{nameof(GuildListMembers.Limit)} cannot be less than {MinLimit}"); + } - if (limit > MaxLimit) - { - throw new InvalidGuildListMembersException($"{nameof(GuildListMembers)}.{nameof(GuildListMembers.Limit)} cannot be more than {MaxLimit}"); - } + if (limit > MaxLimit) + { + throw new InvalidGuildListMembersException($"{nameof(GuildListMembers)}.{nameof(GuildListMembers.Limit)} cannot be more than {MaxLimit}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildMemberException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildMemberException.cs index 21782a3b9..a83345781 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildMemberException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildMemberException.cs @@ -1,22 +1,21 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception in guild member +/// +public class InvalidGuildMemberException : BaseDiscordException { - /// - /// Represents an exception in guild member - /// - public class InvalidGuildMemberException : BaseDiscordException - { - private InvalidGuildMemberException(string message) : base(message) { } + private InvalidGuildMemberException(string message) : base(message) { } - internal static void ThrowIfInvalidNickname(string nickname) - { - const int MaxLength = 32; + internal static void ThrowIfInvalidNickname(string nickname) + { + const int MaxLength = 32; - if (!string.IsNullOrEmpty(nickname) && nickname.Length > MaxLength) - { - throw new InvalidGuildMemberException($"{nameof(GuildMemberUpdate)}.{nameof(GuildMemberUpdate.Nick)} cannot be more than {MaxLength} characters"); - } + if (!string.IsNullOrEmpty(nickname) && nickname.Length > MaxLength) + { + throw new InvalidGuildMemberException($"{nameof(GuildMemberUpdate)}.{nameof(GuildMemberUpdate.Nick)} cannot be more than {MaxLength} characters"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildPruneException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildPruneException.cs index ae49d231b..52facb291 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildPruneException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildPruneException.cs @@ -1,28 +1,27 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception in guild prune requests +/// +public class InvalidGuildPruneException : BaseDiscordException { - /// - /// Represents an exception in guild prune requests - /// - public class InvalidGuildPruneException : BaseDiscordException + private InvalidGuildPruneException(string message) : base(message) { } + + internal static void ThrowIfInvalidDays(int days) { - private InvalidGuildPruneException(string message) : base(message) { } + const int MinDays = 1; + const int MaxDays = 30; - internal static void ThrowIfInvalidDays(int days) + if (days < MinDays) { - const int MinDays = 1; - const int MaxDays = 30; - - if (days < MinDays) - { - throw new InvalidGuildPruneException($"{nameof(GuildPruneGet)}.{nameof(GuildPruneGet.Days)} cannot be less than {MinDays}"); - } + throw new InvalidGuildPruneException($"{nameof(GuildPruneGet)}.{nameof(GuildPruneGet.Days)} cannot be less than {MinDays}"); + } - if (days > MaxDays) - { - throw new InvalidGuildPruneException($"{nameof(GuildPruneGet)}.{nameof(GuildPruneGet.Days)} cannot be more than {MaxDays}"); - } + if (days > MaxDays) + { + throw new InvalidGuildPruneException($"{nameof(GuildPruneGet)}.{nameof(GuildPruneGet.Days)} cannot be more than {MaxDays}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildRoleException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildRoleException.cs index 7f66c748a..b9e7d3713 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildRoleException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildRoleException.cs @@ -1,27 +1,26 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception for invalid guild roles +/// +public class InvalidGuildRoleException : BaseDiscordException { - /// - /// Represents an exception for invalid guild roles - /// - public class InvalidGuildRoleException : BaseDiscordException - { - private InvalidGuildRoleException(string message) : base(message) { } + private InvalidGuildRoleException(string message) : base(message) { } - internal static void ThrowIfInvalidRoleName(string name) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidRoleName(string name) + { + const int MaxLength = 100; - if (string.IsNullOrEmpty(name)) - { - throw new InvalidGuildRoleException($"{nameof(DiscordRole)}.{nameof(DiscordRole.Name)} cannot be null or empty"); - } + if (string.IsNullOrEmpty(name)) + { + throw new InvalidGuildRoleException($"{nameof(DiscordRole)}.{nameof(DiscordRole.Name)} cannot be null or empty"); + } - if (name.Length > MaxLength) - { - throw new InvalidGuildRoleException($"{nameof(DiscordRole)}.{nameof(DiscordRole.Name)} cannot be more than {MaxLength} characters"); - } + if (name.Length > MaxLength) + { + throw new InvalidGuildRoleException($"{nameof(DiscordRole)}.{nameof(DiscordRole.Name)} cannot be more than {MaxLength} characters"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildSearchMembersException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildSearchMembersException.cs index 3a3b5735e..eb9d246ba 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildSearchMembersException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Guild/InvalidGuildSearchMembersException.cs @@ -1,36 +1,35 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception in guild member search requests +/// +public class InvalidGuildSearchMembersException : BaseDiscordException { - /// - /// Represents an exception in guild member search requests - /// - public class InvalidGuildSearchMembersException : BaseDiscordException - { - private InvalidGuildSearchMembersException(string message) : base(message) { } + private InvalidGuildSearchMembersException(string message) : base(message) { } - internal static void ThrowIfInvalidQuery(string query) + internal static void ThrowIfInvalidQuery(string query) + { + if (string.IsNullOrEmpty(query)) { - if (string.IsNullOrEmpty(query)) - { - throw new InvalidGuildSearchMembersException($"{nameof(GuildSearchMembers)}.{nameof(GuildSearchMembers.Query)} cannot be less than 1 character"); - } + throw new InvalidGuildSearchMembersException($"{nameof(GuildSearchMembers)}.{nameof(GuildSearchMembers.Query)} cannot be less than 1 character"); } + } - internal static void ThrowIfInvalidLimit(int? limit) - { - const int MinLimit = 0; - const int MaxLimit = 1000; + internal static void ThrowIfInvalidLimit(int? limit) + { + const int MinLimit = 0; + const int MaxLimit = 1000; - if (limit < MinLimit) - { - throw new InvalidGuildSearchMembersException($"{nameof(GuildSearchMembers)}.{nameof(GuildSearchMembers.Limit)} cannot be less than {MinLimit}"); - } + if (limit < MinLimit) + { + throw new InvalidGuildSearchMembersException($"{nameof(GuildSearchMembers)}.{nameof(GuildSearchMembers.Limit)} cannot be less than {MinLimit}"); + } - if (limit > MaxLimit) - { - throw new InvalidGuildSearchMembersException($"{nameof(GuildSearchMembers)}.{nameof(GuildSearchMembers.Limit)} cannot be more than {MaxLimit}"); - } + if (limit > MaxLimit) + { + throw new InvalidGuildSearchMembersException($"{nameof(GuildSearchMembers)}.{nameof(GuildSearchMembers.Limit)} cannot be more than {MaxLimit}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Guild/ScheduledEvents/InvalidGuildScheduledEventException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Guild/ScheduledEvents/InvalidGuildScheduledEventException.cs index e4b8ea8e2..ce03df8eb 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Guild/ScheduledEvents/InvalidGuildScheduledEventException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Guild/ScheduledEvents/InvalidGuildScheduledEventException.cs @@ -1,45 +1,44 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception in guild scheduled events +/// +public class InvalidGuildScheduledEventException : BaseDiscordException { - /// - /// Represents an exception in guild scheduled events - /// - public class InvalidGuildScheduledEventException : BaseDiscordException - { - private InvalidGuildScheduledEventException(string message) : base(message) { } + private InvalidGuildScheduledEventException(string message) : base(message) { } - internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) + { + const int MaxLength = 100; - if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) - { - throw new InvalidGuildScheduledEventException($"Name cannot be less than 1 character"); - } + if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) + { + throw new InvalidGuildScheduledEventException($"Name cannot be less than 1 character"); + } - if (name.Length > MaxLength) - { - throw new InvalidGuildScheduledEventException($"Name cannot be more than {MaxLength} characters"); - } + if (name.Length > MaxLength) + { + throw new InvalidGuildScheduledEventException($"Name cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidDescription(string description) - { - const int MaxLength = 1000; + internal static void ThrowIfInvalidDescription(string description) + { + const int MaxLength = 1000; - if (!string.IsNullOrEmpty(description) && description.Length > MaxLength) - { - throw new InvalidGuildScheduledEventException($"Description cannot be more than {MaxLength} characters"); - } + if (!string.IsNullOrEmpty(description) && description.Length > MaxLength) + { + throw new InvalidGuildScheduledEventException($"Description cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidLocation(string location) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidLocation(string location) + { + const int MaxLength = 100; - if (!string.IsNullOrEmpty(location) && location.Length > 100) - { - throw new InvalidGuildScheduledEventException($"Location cannot be more than {MaxLength} characters"); - } + if (!string.IsNullOrEmpty(location) && location.Length > 100) + { + throw new InvalidGuildScheduledEventException($"Location cannot be more than {MaxLength} characters"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Guild/ScheduledEvents/InvalidGuildScheduledEventLookupException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Guild/ScheduledEvents/InvalidGuildScheduledEventLookupException.cs index 01af0e7eb..0d2bf45bb 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Guild/ScheduledEvents/InvalidGuildScheduledEventLookupException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Guild/ScheduledEvents/InvalidGuildScheduledEventLookupException.cs @@ -1,21 +1,20 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception in guild schedule event lookup requests +/// +public class InvalidGuildScheduledEventLookupException : BaseDiscordException { - /// - /// Represents an exception in guild schedule event lookup requests - /// - public class InvalidGuildScheduledEventLookupException : BaseDiscordException - { - private InvalidGuildScheduledEventLookupException(string message) : base(message) { } + private InvalidGuildScheduledEventLookupException(string message) : base(message) { } - internal static void ThrowIfInvalidLimit(int? limit) + internal static void ThrowIfInvalidLimit(int? limit) + { + const int MaxLimit = 100; + if (limit > MaxLimit) { - const int MaxLimit = 100; - if (limit > MaxLimit) - { - throw new InvalidGuildScheduledEventLookupException($"{nameof(ScheduledEventUsersLookup)}.{nameof(ScheduledEventUsersLookup.Limit)} cannot be greater than {MaxLimit}"); - } + throw new InvalidGuildScheduledEventLookupException($"{nameof(ScheduledEventUsersLookup)}.{nameof(ScheduledEventUsersLookup.Limit)} cannot be greater than {MaxLimit}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Images/InvalidImageDataException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Images/InvalidImageDataException.cs index 0ca36901e..d8d8982e1 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Images/InvalidImageDataException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Images/InvalidImageDataException.cs @@ -1,45 +1,44 @@ using System.Text.RegularExpressions; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception in discord image data +/// +public class InvalidImageDataException : BaseDiscordException { - /// - /// Represents an exception in discord image data - /// - public class InvalidImageDataException : BaseDiscordException - { - internal InvalidImageDataException(string message) : base(message) { } + internal InvalidImageDataException(string message) : base(message) { } - internal static void ThrowIfInvalidBase64String(Match match, string image) + internal static void ThrowIfInvalidBase64String(Match match, string image) + { + if (!match.Success || match.Groups.Count != 2) { - if (!match.Success || match.Groups.Count != 2) - { - throw new InvalidImageDataException($"'{image}' is not valid. Please make sure it's in the following format: https://discord.com/developers/docs/reference#image-data"); - } + throw new InvalidImageDataException($"'{image}' is not valid. Please make sure it's in the following format: https://discord.com/developers/docs/reference#image-data"); } + } - internal static void ThrowIfInvalidImageBytes(byte[] image) + internal static void ThrowIfInvalidImageBytes(byte[] image) + { + if (image == null || image.Length == 0) { - if (image == null || image.Length == 0) - { - throw new InvalidImageDataException("Image Byte[] cannot be null or empty"); - } + throw new InvalidImageDataException("Image Byte[] cannot be null or empty"); } + } - internal static void ThrowIfInvalidImageData(DiscordImageData image) + internal static void ThrowIfInvalidImageData(DiscordImageData image) + { + if (!image.IsValid()) { - if (!image.IsValid()) - { - throw new InvalidImageDataException("ImageData is not a valid image"); - } + throw new InvalidImageDataException("ImageData is not a valid image"); } + } - internal static void ThrowIfInvalidImageData(DiscordImageData? image) + internal static void ThrowIfInvalidImageData(DiscordImageData? image) + { + if (image.HasValue) { - if (image.HasValue) - { - ThrowIfInvalidImageData(image.Value); - } + ThrowIfInvalidImageData(image.Value); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidApplicationCommandException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidApplicationCommandException.cs index 081ed6860..cf87b078b 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidApplicationCommandException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidApplicationCommandException.cs @@ -1,52 +1,51 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an invalid application command +/// +public class InvalidApplicationCommandException : BaseDiscordException { /// - /// Represents an invalid application command + /// Constructor /// - public class InvalidApplicationCommandException : BaseDiscordException + /// Exception message + private InvalidApplicationCommandException(string message) : base(message) { - /// - /// Constructor - /// - /// Exception message - private InvalidApplicationCommandException(string message) : base(message) - { - } + } - internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) - { - const int MaxLength = 32; + internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) + { + const int MaxLength = 32; - if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) - { - throw new InvalidApplicationCommandException("Name cannot be less than 1 character"); - } + if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) + { + throw new InvalidApplicationCommandException("Name cannot be less than 1 character"); + } - if (name.Length > 32) - { - throw new InvalidApplicationCommandException($"Name cannot be more than {MaxLength} characters"); - } + if (name.Length > 32) + { + throw new InvalidApplicationCommandException($"Name cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidDescription(string description, ApplicationCommandType type) + internal static void ThrowIfInvalidDescription(string description, ApplicationCommandType type) + { + const int MaxLength = 100; + if (type == ApplicationCommandType.ChatInput) { - const int MaxLength = 100; - if (type == ApplicationCommandType.ChatInput) + if (!string.IsNullOrEmpty(description) && description.Length > MaxLength) { - if (!string.IsNullOrEmpty(description) && description.Length > MaxLength) - { - throw new InvalidApplicationCommandException($"Description cannot be more than {MaxLength} characters for {nameof(ApplicationCommandType)}.{type}"); - } + throw new InvalidApplicationCommandException($"Description cannot be more than {MaxLength} characters for {nameof(ApplicationCommandType)}.{type}"); } - else + } + else + { + if (!string.IsNullOrEmpty(description)) { - if (!string.IsNullOrEmpty(description)) - { - throw new InvalidApplicationCommandException($"Description must be null for {nameof(ApplicationCommandType)}.{type}"); - } + throw new InvalidApplicationCommandException($"Description must be null for {nameof(ApplicationCommandType)}.{type}"); } } } diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidCommandOptionChoiceException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidCommandOptionChoiceException.cs index 297651379..3ebd69501 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidCommandOptionChoiceException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidCommandOptionChoiceException.cs @@ -1,60 +1,59 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an error in application command option choice +/// +public class InvalidCommandOptionChoiceException : BaseDiscordException { - /// - /// Represents an error in application command option choice - /// - public class InvalidCommandOptionChoiceException : BaseDiscordException - { - private InvalidCommandOptionChoiceException(string message) : base(message) { } + private InvalidCommandOptionChoiceException(string message) : base(message) { } - internal static void ThrowIfMaxChoices(int count) - { - const int MaxChoices = 25; + internal static void ThrowIfMaxChoices(int count) + { + const int MaxChoices = 25; - if (count > MaxChoices) - { - throw new InvalidCommandOptionChoiceException($"Cannot have more than {MaxChoices} Command Option Choices"); - } + if (count > MaxChoices) + { + throw new InvalidCommandOptionChoiceException($"Cannot have more than {MaxChoices} Command Option Choices"); } + } - internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) + { + const int MaxLength = 100; - if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) - { - throw new InvalidCommandOptionChoiceException("Name cannot be less than 1 character"); - } + if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) + { + throw new InvalidCommandOptionChoiceException("Name cannot be less than 1 character"); + } - if (name.Length > MaxLength) - { - throw new InvalidCommandOptionChoiceException($"Name cannot be more than {MaxLength} characters"); - } + if (name.Length > MaxLength) + { + throw new InvalidCommandOptionChoiceException($"Name cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidStringValue(string value) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidStringValue(string value) + { + const int MaxLength = 100; - if (string.IsNullOrEmpty(value)) - { - throw new InvalidCommandOptionChoiceException("Value cannot be less than 1 character"); - } + if (string.IsNullOrEmpty(value)) + { + throw new InvalidCommandOptionChoiceException("Value cannot be less than 1 character"); + } - if (value.Length > MaxLength) - { - throw new InvalidCommandOptionChoiceException($"Value cannot be more than {MaxLength} characters"); - } + if (value.Length > MaxLength) + { + throw new InvalidCommandOptionChoiceException($"Value cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidType(CommandOptionType value, CommandOptionType expected) + internal static void ThrowIfInvalidType(CommandOptionType value, CommandOptionType expected) + { + if (value != expected) { - if (value != expected) - { - throw new InvalidCommandOptionChoiceException($"Cannot add a {value} choice type to type: {expected}"); - } + throw new InvalidCommandOptionChoiceException($"Cannot add a {value} choice type to type: {expected}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidCommandOptionException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidCommandOptionException.cs index 0890e01d2..1444c46de 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidCommandOptionException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/ApplicationCommands/InvalidCommandOptionException.cs @@ -1,138 +1,137 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an error in application command option +/// +public class InvalidCommandOptionException : BaseDiscordException { - /// - /// Represents an error in application command option - /// - public class InvalidCommandOptionException : BaseDiscordException - { - private InvalidCommandOptionException(string message) : base(message) { } + private InvalidCommandOptionException(string message) : base(message) { } - internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) - { - const int MaxLength = 32; + internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) + { + const int MaxLength = 32; - if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) - { - throw new InvalidCommandOptionException("Name cannot be less than 1 character"); - } + if (!allowNullOrEmpty && string.IsNullOrEmpty(name)) + { + throw new InvalidCommandOptionException("Name cannot be less than 1 character"); + } - if (name.Length > MaxLength) - { - throw new InvalidCommandOptionException($"Name cannot be more than {MaxLength} characters"); - } + if (name.Length > MaxLength) + { + throw new InvalidCommandOptionException($"Name cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidDescription(string description, bool allowNullOrEmpty) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidDescription(string description, bool allowNullOrEmpty) + { + const int MaxLength = 100; - if (!allowNullOrEmpty && string.IsNullOrEmpty(description)) - { - throw new InvalidCommandOptionException("Description cannot be less than 1 character"); - } + if (!allowNullOrEmpty && string.IsNullOrEmpty(description)) + { + throw new InvalidCommandOptionException("Description cannot be less than 1 character"); + } - if (description.Length > MaxLength) - { - throw new InvalidCommandOptionException($"Description cannot be more than {MaxLength} characters"); - } + if (description.Length > MaxLength) + { + throw new InvalidCommandOptionException($"Description cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidType(CommandOptionType type) + internal static void ThrowIfInvalidType(CommandOptionType type) + { + if (type == CommandOptionType.SubCommand || type == CommandOptionType.SubCommandGroup) { - if (type == CommandOptionType.SubCommand || type == CommandOptionType.SubCommandGroup) - { - throw new InvalidCommandOptionException($"{type} is not allowed to be used here. Valid types are any non command type."); - } + throw new InvalidCommandOptionException($"{type} is not allowed to be used here. Valid types are any non command type."); } + } - internal static void ThrowIfInvalidMinIntegerType(CommandOptionType type) + internal static void ThrowIfInvalidMinIntegerType(CommandOptionType type) + { + if (type != CommandOptionType.Integer && type != CommandOptionType.Number) { - if (type != CommandOptionType.Integer && type != CommandOptionType.Number) - { - throw new InvalidCommandOptionException("Can only set min value for Integer or Number Type"); - } + throw new InvalidCommandOptionException("Can only set min value for Integer or Number Type"); } + } - internal static void ThrowIfInvalidMinNumberType(CommandOptionType type) + internal static void ThrowIfInvalidMinNumberType(CommandOptionType type) + { + if (type != CommandOptionType.Number) { - if (type != CommandOptionType.Number) - { - throw new InvalidCommandOptionException("Can only set min value for Number Type"); - } + throw new InvalidCommandOptionException("Can only set min value for Number Type"); } + } - internal static void ThrowIfInvalidMaxIntegerType(CommandOptionType type) + internal static void ThrowIfInvalidMaxIntegerType(CommandOptionType type) + { + if (type != CommandOptionType.Integer && type != CommandOptionType.Number) { - if (type != CommandOptionType.Integer && type != CommandOptionType.Number) - { - throw new InvalidCommandOptionException("Can only set max value for Integer or Number Type"); - } + throw new InvalidCommandOptionException("Can only set max value for Integer or Number Type"); } + } - internal static void ThrowIfInvalidMaxNumberType(CommandOptionType type) + internal static void ThrowIfInvalidMaxNumberType(CommandOptionType type) + { + if (type != CommandOptionType.Number) { - if (type != CommandOptionType.Number) - { - throw new InvalidCommandOptionException("Can only set max value for Number Type"); - } + throw new InvalidCommandOptionException("Can only set max value for Number Type"); } + } - internal static void ThrowIfInvalidMinLengthType(CommandOptionType type) + internal static void ThrowIfInvalidMinLengthType(CommandOptionType type) + { + if (type != CommandOptionType.String) { - if (type != CommandOptionType.String) - { - throw new InvalidCommandOptionException("Can only set min length for string Type"); - } + throw new InvalidCommandOptionException("Can only set min length for string Type"); } + } - internal static void ThrowIfInvalidMaxLengthType(CommandOptionType type) + internal static void ThrowIfInvalidMaxLengthType(CommandOptionType type) + { + if (type != CommandOptionType.String) { - if (type != CommandOptionType.String) - { - throw new InvalidCommandOptionException("Can only set max length for string Type"); - } + throw new InvalidCommandOptionException("Can only set max length for string Type"); } + } - internal static void ThrowIfInvalidMinLength(int minLength) - { - const int MinLength = 0; - const int MaxLength = 6000; + internal static void ThrowIfInvalidMinLength(int minLength) + { + const int MinLength = 0; + const int MaxLength = 6000; - if (minLength < MinLength) - { - throw new InvalidCommandOptionException($"Min length cannot be less than {MinLength}"); - } + if (minLength < MinLength) + { + throw new InvalidCommandOptionException($"Min length cannot be less than {MinLength}"); + } - if (minLength > MaxLength) - { - throw new InvalidCommandOptionException($"Min length cannot be more than {MaxLength}"); - } + if (minLength > MaxLength) + { + throw new InvalidCommandOptionException($"Min length cannot be more than {MaxLength}"); } + } - internal static void ThrowIfInvalidMaxLength(int maxLength) - { - const int MinLength = 1; - const int MaxLength = 6000; + internal static void ThrowIfInvalidMaxLength(int maxLength) + { + const int MinLength = 1; + const int MaxLength = 6000; - if (maxLength < MinLength) - { - throw new InvalidCommandOptionException($"Max length cannot be less than {MinLength}"); - } + if (maxLength < MinLength) + { + throw new InvalidCommandOptionException($"Max length cannot be less than {MinLength}"); + } - if (maxLength > MaxLength) - { - throw new InvalidCommandOptionException($"Max length cannot be more than {MaxLength}"); - } + if (maxLength > MaxLength) + { + throw new InvalidCommandOptionException($"Max length cannot be more than {MaxLength}"); } + } - internal static void ThrowIfInvalidChannelType(CommandOptionType type) + internal static void ThrowIfInvalidChannelType(CommandOptionType type) + { + if (type != CommandOptionType.Channel) { - if (type != CommandOptionType.Channel) - { - throw new InvalidCommandOptionException("Can only set ChannelTypes for CommandOptionType.Channel"); - } + throw new InvalidCommandOptionException("Can only set ChannelTypes for CommandOptionType.Channel"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InteractionArgException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InteractionArgException.cs index f534afa0e..1456fa22e 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InteractionArgException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InteractionArgException.cs @@ -1,27 +1,26 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an error when an interaction arg does not match the requested type +/// +public class InteractionArgException : BaseDiscordException { - /// - /// Represents an error when an interaction arg does not match the requested type - /// - public class InteractionArgException : BaseDiscordException - { - private InteractionArgException(string message) : base(message) { } + private InteractionArgException(string message) : base(message) { } - internal static void ThrowIfInvalidArgType(string name, CommandOptionType arg, CommandOptionType requested) + internal static void ThrowIfInvalidArgType(string name, CommandOptionType arg, CommandOptionType requested) + { + if (arg != CommandOptionType.Mentionable) { - if (arg != CommandOptionType.Mentionable) + if (arg != requested) { - if (arg != requested) - { - throw new InteractionArgException($"Attempted to parse {name} {arg} type to: {requested} which is not valid."); - } - } - else if (requested != CommandOptionType.Role && requested != CommandOptionType.User) - { - throw new InteractionArgException($"Attempted to parse {name} role/user type to: {requested} which is not valid."); + throw new InteractionArgException($"Attempted to parse {name} {arg} type to: {requested} which is not valid."); } } + else if (requested != CommandOptionType.Role && requested != CommandOptionType.User) + { + throw new InteractionArgException($"Attempted to parse {name} role/user type to: {requested} which is not valid."); + } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InvalidAutoCompleteChoiceException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InvalidAutoCompleteChoiceException.cs index 3df00727a..738d94268 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InvalidAutoCompleteChoiceException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InvalidAutoCompleteChoiceException.cs @@ -1,37 +1,36 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception for invalid Auto Complete choices +/// +public class InvalidAutoCompleteChoiceException : BaseDiscordException { /// - /// Exception for invalid Auto Complete choices + /// Constructor /// - public class InvalidAutoCompleteChoiceException : BaseDiscordException - { - /// - /// Constructor - /// - /// Exception message - protected InvalidAutoCompleteChoiceException(string message) : base(message) { } + /// Exception message + protected InvalidAutoCompleteChoiceException(string message) : base(message) { } - internal static void ThrowIfInvalidName(string name) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidName(string name) + { + const int MaxLength = 100; - if (string.IsNullOrEmpty(name)) - { - throw new InvalidAutoCompleteChoiceException("Name must contain at least 1 character"); - } + if (string.IsNullOrEmpty(name)) + { + throw new InvalidAutoCompleteChoiceException("Name must contain at least 1 character"); + } - if (name.Length > MaxLength) - { - throw new InvalidAutoCompleteChoiceException($"Name cannot be greater than {MaxLength} characters"); - } + if (name.Length > MaxLength) + { + throw new InvalidAutoCompleteChoiceException($"Name cannot be greater than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidValue(object value) + internal static void ThrowIfInvalidValue(object value) + { + if (value == null) { - if (value == null) - { - throw new InvalidAutoCompleteChoiceException("Value cannot be null"); - } + throw new InvalidAutoCompleteChoiceException("Value cannot be null"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InvalidInteractionResponseException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InvalidInteractionResponseException.cs index 9eb5731a3..549ac94dc 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InvalidInteractionResponseException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/InvalidInteractionResponseException.cs @@ -1,78 +1,77 @@ using System; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Error thrown when an interaction response is invalid +/// +public class InvalidInteractionResponseException : BaseDiscordException { + private static readonly TimeSpan MaxInitialResponseDuration = TimeSpan.FromSeconds(3); + private static readonly TimeSpan MaxTokenLife = TimeSpan.FromMinutes(15); + /// - /// Error thrown when an interaction response is invalid + /// Constructor /// - public class InvalidInteractionResponseException : BaseDiscordException - { - private static readonly TimeSpan MaxInitialResponseDuration = TimeSpan.FromSeconds(3); - private static readonly TimeSpan MaxTokenLife = TimeSpan.FromMinutes(15); - - /// - /// Constructor - /// - /// Exception message - private InvalidInteractionResponseException(string message) : base(message) { } + /// Exception message + private InvalidInteractionResponseException(string message) : base(message) { } - internal static void ThrowIfAlreadyResponded(bool responded) + internal static void ThrowIfAlreadyResponded(bool responded) + { + if (responded) { - if (responded) - { - throw new InvalidInteractionResponseException($"This interaction has already been responded too and can't be responded to again. Please use {nameof(DiscordInteraction)}.{nameof(DiscordInteraction.CreateFollowUpMessage)} to create a follow up message"); - } + throw new InvalidInteractionResponseException($"This interaction has already been responded too and can't be responded to again. Please use {nameof(DiscordInteraction)}.{nameof(DiscordInteraction.CreateFollowUpMessage)} to create a follow up message"); } + } - internal static void ThrowIfNotResponded(bool responded) + internal static void ThrowIfNotResponded(bool responded) + { + if (!responded) { - if (!responded) - { - throw new InvalidInteractionResponseException($"You cannot use this endpoint because {nameof(DiscordInteraction)}.{nameof(DiscordInteraction.CreateResponse)} hasn't been called yet"); - } + throw new InvalidInteractionResponseException($"You cannot use this endpoint because {nameof(DiscordInteraction)}.{nameof(DiscordInteraction.CreateResponse)} hasn't been called yet"); } + } - internal static void ThrowIfInitialResponseTimeElapsed(DateTime createdDate) + internal static void ThrowIfInitialResponseTimeElapsed(DateTime createdDate) + { + if (DateTime.UtcNow - createdDate > MaxInitialResponseDuration) { - if (DateTime.UtcNow - createdDate > MaxInitialResponseDuration) - { - throw new InvalidInteractionResponseException($"This interaction has expired as it took longer than {MaxInitialResponseDuration.TotalSeconds:0} seconds to respond to the interaction. The interaction took: {(DateTime.UtcNow - createdDate).TotalSeconds:0.0000} seconds to respond."); - } + throw new InvalidInteractionResponseException($"This interaction has expired as it took longer than {MaxInitialResponseDuration.TotalSeconds:0} seconds to respond to the interaction. The interaction took: {(DateTime.UtcNow - createdDate).TotalSeconds:0.0000} seconds to respond."); } + } - internal static void ThrowIfMaxResponseTimeElapsed(DateTime createdDate) + internal static void ThrowIfMaxResponseTimeElapsed(DateTime createdDate) + { + if (DateTime.UtcNow - createdDate > MaxTokenLife) { - if (DateTime.UtcNow - createdDate > MaxTokenLife) - { - throw new InvalidInteractionResponseException($"This interaction has expired as it has been longer than {MaxTokenLife.TotalMinutes:0} minutes"); - } + throw new InvalidInteractionResponseException($"This interaction has expired as it has been longer than {MaxTokenLife.TotalMinutes:0} minutes"); } + } - internal static void ThrowIfInvalidResponseType(InteractionType type, InteractionResponseType responseType) + internal static void ThrowIfInvalidResponseType(InteractionType type, InteractionResponseType responseType) + { + switch (type) { - switch (type) - { - case InteractionType.Ping when responseType != InteractionResponseType.Pong: - throw new InvalidInteractionResponseException( - $"You can only response to {nameof(InteractionType)}.{nameof(InteractionType.Ping)} with {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.Pong)}"); + case InteractionType.Ping when responseType != InteractionResponseType.Pong: + throw new InvalidInteractionResponseException( + $"You can only response to {nameof(InteractionType)}.{nameof(InteractionType.Ping)} with {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.Pong)}"); - case InteractionType.ApplicationCommand when responseType != InteractionResponseType.ChannelMessageWithSource && responseType != InteractionResponseType.DeferredChannelMessageWithSource && responseType != InteractionResponseType.Modal: - throw new InvalidInteractionResponseException( - $"You can only response to {nameof(InteractionType)}.{nameof(InteractionType.ApplicationCommand)} with {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.ChannelMessageWithSource)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.DeferredChannelMessageWithSource)}, or {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.Modal)}"); + case InteractionType.ApplicationCommand when responseType != InteractionResponseType.ChannelMessageWithSource && responseType != InteractionResponseType.DeferredChannelMessageWithSource && responseType != InteractionResponseType.Modal: + throw new InvalidInteractionResponseException( + $"You can only response to {nameof(InteractionType)}.{nameof(InteractionType.ApplicationCommand)} with {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.ChannelMessageWithSource)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.DeferredChannelMessageWithSource)}, or {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.Modal)}"); - case InteractionType.MessageComponent when responseType != InteractionResponseType.ChannelMessageWithSource && responseType != InteractionResponseType.DeferredChannelMessageWithSource && responseType != InteractionResponseType.UpdateMessage && responseType != InteractionResponseType.DeferredUpdateMessage && responseType != InteractionResponseType.Modal: - throw new InvalidInteractionResponseException( - $"You can only response to {nameof(InteractionType)}.{nameof(InteractionType.MessageComponent)} with {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.ChannelMessageWithSource)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.DeferredChannelMessageWithSource)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.UpdateMessage)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.DeferredUpdateMessage)}, or {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.Modal)}"); + case InteractionType.MessageComponent when responseType != InteractionResponseType.ChannelMessageWithSource && responseType != InteractionResponseType.DeferredChannelMessageWithSource && responseType != InteractionResponseType.UpdateMessage && responseType != InteractionResponseType.DeferredUpdateMessage && responseType != InteractionResponseType.Modal: + throw new InvalidInteractionResponseException( + $"You can only response to {nameof(InteractionType)}.{nameof(InteractionType.MessageComponent)} with {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.ChannelMessageWithSource)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.DeferredChannelMessageWithSource)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.UpdateMessage)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.DeferredUpdateMessage)}, or {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.Modal)}"); - case InteractionType.ApplicationCommandAutoComplete when responseType != InteractionResponseType.ApplicationCommandAutocompleteResult: - throw new InvalidInteractionResponseException( - $"You can only response to {nameof(InteractionType)}.{nameof(InteractionType.ApplicationCommandAutoComplete)} with {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.ApplicationCommandAutocompleteResult)}"); + case InteractionType.ApplicationCommandAutoComplete when responseType != InteractionResponseType.ApplicationCommandAutocompleteResult: + throw new InvalidInteractionResponseException( + $"You can only response to {nameof(InteractionType)}.{nameof(InteractionType.ApplicationCommandAutoComplete)} with {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.ApplicationCommandAutocompleteResult)}"); - case InteractionType.ModalSubmit when responseType == InteractionResponseType.Modal || responseType == InteractionResponseType.Pong: - throw new InvalidInteractionResponseException( - $"You can only response to {nameof(InteractionType)}.{nameof(InteractionType.ModalSubmit)} with {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.ChannelMessageWithSource)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.DeferredChannelMessageWithSource)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.UpdateMessage)}, or {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.DeferredUpdateMessage)}"); - } + case InteractionType.ModalSubmit when responseType == InteractionResponseType.Modal || responseType == InteractionResponseType.Pong: + throw new InvalidInteractionResponseException( + $"You can only response to {nameof(InteractionType)}.{nameof(InteractionType.ModalSubmit)} with {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.ChannelMessageWithSource)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.DeferredChannelMessageWithSource)}, {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.UpdateMessage)}, or {nameof(InteractionResponseType)}.{nameof(InteractionResponseType.DeferredUpdateMessage)}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/MessageComponents/InvalidMessageComponentException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/MessageComponents/InvalidMessageComponentException.cs index 512d67984..385aeea52 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/MessageComponents/InvalidMessageComponentException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/MessageComponents/InvalidMessageComponentException.cs @@ -1,133 +1,132 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an invalid message component +/// +public class InvalidMessageComponentException : BaseDiscordException { /// - /// Represents an invalid message component + /// Constructor /// - public class InvalidMessageComponentException : BaseDiscordException + /// Exception message + private InvalidMessageComponentException(string message) : base(message) { - /// - /// Constructor - /// - /// Exception message - private InvalidMessageComponentException(string message) : base(message) - { - } + } - internal static void ThrowIfInvalidCustomId(string customId) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidCustomId(string customId) + { + const int MaxLength = 100; - if (!string.IsNullOrEmpty(customId) && customId.Length > MaxLength) - { - throw new InvalidMessageComponentException($"CustomID cannot be more than {MaxLength} characters"); - } + if (!string.IsNullOrEmpty(customId) && customId.Length > MaxLength) + { + throw new InvalidMessageComponentException($"CustomID cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidButtonLabel(string label) + internal static void ThrowIfInvalidButtonLabel(string label) + { + const int MaxLength = 80; + if (!string.IsNullOrEmpty(label) && label.Length > MaxLength) { - const int MaxLength = 80; - if (!string.IsNullOrEmpty(label) && label.Length > MaxLength) - { - throw new InvalidMessageComponentException($"Button Label cannot be more than {MaxLength} characters"); - } + throw new InvalidMessageComponentException($"Button Label cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidButtonUrl(string url) + internal static void ThrowIfInvalidButtonUrl(string url) + { + if (string.IsNullOrEmpty(url)) { - if (string.IsNullOrEmpty(url)) - { - throw new InvalidMessageComponentException("Button Url cannot be null or empty"); - } + throw new InvalidMessageComponentException("Button Url cannot be null or empty"); } + } - internal static void ThrowIfInvalidTextInputLabel(string label) - { - const int MaxLength = 45; + internal static void ThrowIfInvalidTextInputLabel(string label) + { + const int MaxLength = 45; - if (string.IsNullOrEmpty(label)) - { - throw new InvalidMessageComponentException("Text Input Label cannot be less than 1 character"); - } + if (string.IsNullOrEmpty(label)) + { + throw new InvalidMessageComponentException("Text Input Label cannot be less than 1 character"); + } - if (label.Length > MaxLength) - { - throw new InvalidMessageComponentException($"Text Input Label cannot be more than {MaxLength} characters"); - } + if (label.Length > MaxLength) + { + throw new InvalidMessageComponentException($"Text Input Label cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidTextInputValue(string value) - { - const int MaxLength = 4000; + internal static void ThrowIfInvalidTextInputValue(string value) + { + const int MaxLength = 4000; - if (!string.IsNullOrEmpty(value) && value.Length > MaxLength) - { - throw new InvalidMessageComponentException($"Text Input Value cannot be more than {MaxLength} characters"); - } + if (!string.IsNullOrEmpty(value) && value.Length > MaxLength) + { + throw new InvalidMessageComponentException($"Text Input Value cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidTextInputLength(int? minLength, int? maxLength) - { - const int MinMinLength = 0; - const int MaxMinLength = 4000; - const int MinMaxLength = 1; - const int MaxMaxLength = 4000; + internal static void ThrowIfInvalidTextInputLength(int? minLength, int? maxLength) + { + const int MinMinLength = 0; + const int MaxMinLength = 4000; + const int MinMaxLength = 1; + const int MaxMaxLength = 4000; - if (!minLength.HasValue && !maxLength.HasValue) - { - return; - } + if (!minLength.HasValue && !maxLength.HasValue) + { + return; + } - if (minLength < MinMinLength) - { - throw new InvalidMessageComponentException($"Text Input Min Length cannot be less than {MinMinLength}"); - } + if (minLength < MinMinLength) + { + throw new InvalidMessageComponentException($"Text Input Min Length cannot be less than {MinMinLength}"); + } - if (minLength > MaxMinLength) - { - throw new InvalidMessageComponentException($"Text Input Min Length cannot be greater than {MaxMinLength}"); - } + if (minLength > MaxMinLength) + { + throw new InvalidMessageComponentException($"Text Input Min Length cannot be greater than {MaxMinLength}"); + } - if (maxLength < MinMaxLength) - { - throw new InvalidMessageComponentException($"Text Input Max Length cannot be less than {MinMaxLength}"); - } + if (maxLength < MinMaxLength) + { + throw new InvalidMessageComponentException($"Text Input Max Length cannot be less than {MinMaxLength}"); + } - if (maxLength > MaxMaxLength) - { - throw new InvalidMessageComponentException($"Text Input Max Length cannot be greater than {MaxMaxLength}"); - } + if (maxLength > MaxMaxLength) + { + throw new InvalidMessageComponentException($"Text Input Max Length cannot be greater than {MaxMaxLength}"); + } - if (maxLength < minLength) - { - throw new InvalidMessageComponentException($"Text Input Max Length {maxLength} cannot be less than Min Length {minLength}"); - } + if (maxLength < minLength) + { + throw new InvalidMessageComponentException($"Text Input Max Length {maxLength} cannot be less than Min Length {minLength}"); + } - if (minLength > maxLength) - { - throw new InvalidMessageComponentException($"Text Input Min Length {minLength} cannot be greater than Max Length {maxLength}"); - } + if (minLength > maxLength) + { + throw new InvalidMessageComponentException($"Text Input Min Length {minLength} cannot be greater than Max Length {maxLength}"); } + } - internal static void ThrowIfInvalidMaxActionRows(int count) + internal static void ThrowIfInvalidMaxActionRows(int count) + { + if (count > 5) { - if (count > 5) - { - throw new InvalidMessageComponentException("Cannot have more than 5 action rows for message components"); - } + throw new InvalidMessageComponentException("Cannot have more than 5 action rows for message components"); } + } - internal static void ThrowIfInvalidModalTitle(string title) + internal static void ThrowIfInvalidModalTitle(string title) + { + if (string.IsNullOrEmpty(title)) { - if (string.IsNullOrEmpty(title)) - { - throw new InvalidMessageComponentException("Modal title cannot be less than 1 character"); - } + throw new InvalidMessageComponentException("Modal title cannot be less than 1 character"); + } - if (title.Length > 45) - { - throw new InvalidMessageComponentException("Modal title cannot be more than 45 characters"); - } + if (title.Length > 45) + { + throw new InvalidMessageComponentException("Modal title cannot be more than 45 characters"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/MessageComponents/InvalidSelectMenuComponentException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/MessageComponents/InvalidSelectMenuComponentException.cs index 233a976c1..f858ffb27 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Interactions/MessageComponents/InvalidSelectMenuComponentException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Interactions/MessageComponents/InvalidSelectMenuComponentException.cs @@ -1,152 +1,151 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception for select menu components +/// +public class InvalidSelectMenuComponentException : BaseDiscordException { - /// - /// Represents an exception for select menu components - /// - public class InvalidSelectMenuComponentException : BaseDiscordException - { - private InvalidSelectMenuComponentException(string message) : base(message) { } + private InvalidSelectMenuComponentException(string message) : base(message) { } - internal static void ThrowIfInvalidSelectMenuPlaceholder(string placeholder) - { - const int MaxLength = 150; + internal static void ThrowIfInvalidSelectMenuPlaceholder(string placeholder) + { + const int MaxLength = 150; - if (!string.IsNullOrEmpty(placeholder) && placeholder.Length > MaxLength) - { - throw new InvalidSelectMenuComponentException($"Select Menu Placeholder cannot be more than {MaxLength} characters"); - } + if (!string.IsNullOrEmpty(placeholder) && placeholder.Length > MaxLength) + { + throw new InvalidSelectMenuComponentException($"Select Menu Placeholder cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidSelectMenuMinValues(int? minValues) - { - const int MinMinValues = 0; - const int MaxMinValues = 25; + internal static void ThrowIfInvalidSelectMenuMinValues(int? minValues) + { + const int MinMinValues = 0; + const int MaxMinValues = 25; - if (!minValues.HasValue) - { - return; - } + if (!minValues.HasValue) + { + return; + } - if (minValues < MinMinValues) - { - throw new InvalidSelectMenuComponentException($"Select Menu Min Values cannot be less than {MinMinValues}"); - } + if (minValues < MinMinValues) + { + throw new InvalidSelectMenuComponentException($"Select Menu Min Values cannot be less than {MinMinValues}"); + } - if (minValues > MaxMinValues) - { - throw new InvalidSelectMenuComponentException($"Select Menu Min Values cannot be more than {MaxMinValues}"); - } + if (minValues > MaxMinValues) + { + throw new InvalidSelectMenuComponentException($"Select Menu Min Values cannot be more than {MaxMinValues}"); } + } - internal static void ThrowIfInvalidSelectMenuMaxValues(int? maxValues) - { - const int MaxMaxValues = 25; + internal static void ThrowIfInvalidSelectMenuMaxValues(int? maxValues) + { + const int MaxMaxValues = 25; - if (maxValues > MaxMaxValues) - { - throw new InvalidSelectMenuComponentException($"Select Menu Max Values cannot be more than {MaxMaxValues}"); - } + if (maxValues > MaxMaxValues) + { + throw new InvalidSelectMenuComponentException($"Select Menu Max Values cannot be more than {MaxMaxValues}"); } + } - internal static void ThrowIfInvalidSelectMenuValueRange(int? minValues, int? maxValues) + internal static void ThrowIfInvalidSelectMenuValueRange(int? minValues, int? maxValues) + { + if (!minValues.HasValue && !maxValues.HasValue) { - if (!minValues.HasValue && !maxValues.HasValue) - { - return; - } + return; + } - if (maxValues < minValues) - { - throw new InvalidSelectMenuComponentException($"Select Menu Max Values {maxValues} cannot be less min values {minValues}"); - } + if (maxValues < minValues) + { + throw new InvalidSelectMenuComponentException($"Select Menu Max Values {maxValues} cannot be less min values {minValues}"); } + } - internal static void ThrowIfInvalidSelectMenuOptionLabel(string label) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidSelectMenuOptionLabel(string label) + { + const int MaxLength = 100; - if (string.IsNullOrEmpty(label)) - { - throw new InvalidSelectMenuComponentException("Select Menu Option Label cannot be less than 1 character"); - } + if (string.IsNullOrEmpty(label)) + { + throw new InvalidSelectMenuComponentException("Select Menu Option Label cannot be less than 1 character"); + } - if (label.Length > MaxLength) - { - throw new InvalidSelectMenuComponentException($"Select Menu Option Label cannot be more than {MaxLength} characters"); - } + if (label.Length > MaxLength) + { + throw new InvalidSelectMenuComponentException($"Select Menu Option Label cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidSelectMenuOptionValue(string value) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidSelectMenuOptionValue(string value) + { + const int MaxLength = 100; - if (string.IsNullOrEmpty(value)) - { - throw new InvalidSelectMenuComponentException("Select Menu Option Value cannot be less than 1 character"); - } + if (string.IsNullOrEmpty(value)) + { + throw new InvalidSelectMenuComponentException("Select Menu Option Value cannot be less than 1 character"); + } - if (value.Length > MaxLength) - { - throw new InvalidSelectMenuComponentException($"Select Menu Option Value cannot be more than {MaxLength} characters"); - } + if (value.Length > MaxLength) + { + throw new InvalidSelectMenuComponentException($"Select Menu Option Value cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidSelectMenuOptionDescription(string description) - { - const int MaxLength = 100; + internal static void ThrowIfInvalidSelectMenuOptionDescription(string description) + { + const int MaxLength = 100; - if (!string.IsNullOrEmpty(description) && description.Length > MaxLength) - { - throw new InvalidSelectMenuComponentException($"Select Menu Option Description cannot be more than {MaxLength} characters"); - } + if (!string.IsNullOrEmpty(description) && description.Length > MaxLength) + { + throw new InvalidSelectMenuComponentException($"Select Menu Option Description cannot be more than {MaxLength} characters"); } + } - internal static void ThrowIfInvalidSelectMenuOptionCount(int count) - { - const int MaxOptions = 25; + internal static void ThrowIfInvalidSelectMenuOptionCount(int count) + { + const int MaxOptions = 25; - if (count > MaxOptions) - { - throw new InvalidSelectMenuComponentException($"Select Menu Option Count cannot be more than {MaxOptions}"); - } + if (count > MaxOptions) + { + throw new InvalidSelectMenuComponentException($"Select Menu Option Count cannot be more than {MaxOptions}"); } + } - internal static void ThrowIfInvalidComponentType(MessageComponentType type) + internal static void ThrowIfInvalidComponentType(MessageComponentType type) + { + switch (type) { - switch (type) - { - case MessageComponentType.ActionRow: - case MessageComponentType.Button: - case MessageComponentType.StringSelect: - case MessageComponentType.InputText: - throw new InvalidSelectMenuComponentException($"'{type}' is not a valid type for a SelectMenu."); - } + case MessageComponentType.ActionRow: + case MessageComponentType.Button: + case MessageComponentType.StringSelect: + case MessageComponentType.InputText: + throw new InvalidSelectMenuComponentException($"'{type}' is not a valid type for a SelectMenu."); } + } - internal static void ThrowIfTypeCantAddOptions(MessageComponentType type) + internal static void ThrowIfTypeCantAddOptions(MessageComponentType type) + { + if (type != MessageComponentType.StringSelect) { - if (type != MessageComponentType.StringSelect) - { - throw new InvalidSelectMenuComponentException($"Select Menu Type '{type}' is not allowed to add Options. Options can only be added on {nameof(MessageComponentType)}{MessageComponentType.StringSelect}"); - } + throw new InvalidSelectMenuComponentException($"Select Menu Type '{type}' is not allowed to add Options. Options can only be added on {nameof(MessageComponentType)}{MessageComponentType.StringSelect}"); } + } - internal static void ThrowIfTypeCantAddChannelTypes(MessageComponentType type) + internal static void ThrowIfTypeCantAddChannelTypes(MessageComponentType type) + { + if (type != MessageComponentType.ChannelSelect) { - if (type != MessageComponentType.ChannelSelect) - { - throw new InvalidSelectMenuComponentException($"Select Menu Type '{type}' is not allowed to add Channel Types. Channel Types can only be added on {nameof(MessageComponentType)}{MessageComponentType.ChannelSelect}"); - } + throw new InvalidSelectMenuComponentException($"Select Menu Type '{type}' is not allowed to add Channel Types. Channel Types can only be added on {nameof(MessageComponentType)}{MessageComponentType.ChannelSelect}"); } + } - internal static void ThrowIfCantAddDefaultValue(MessageComponentType type) + internal static void ThrowIfCantAddDefaultValue(MessageComponentType type) + { + if (type != MessageComponentType.ChannelSelect && type != MessageComponentType.RoleSelect && type != MessageComponentType.UserSelect) { - if (type != MessageComponentType.ChannelSelect && type != MessageComponentType.RoleSelect && type != MessageComponentType.UserSelect) - { - throw new InvalidSelectMenuComponentException($"Select Menu Default Value can only be used on {nameof(MessageComponentType)}{MessageComponentType.ChannelSelect} or {nameof(MessageComponentType)}{MessageComponentType.RoleSelect} or {nameof(MessageComponentType)}{MessageComponentType.UserSelect}"); - } + throw new InvalidSelectMenuComponentException($"Select Menu Default Value can only be used on {nameof(MessageComponentType)}{MessageComponentType.ChannelSelect} or {nameof(MessageComponentType)}{MessageComponentType.RoleSelect} or {nameof(MessageComponentType)}{MessageComponentType.UserSelect}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/InvalidSnowflakeException.cs b/Oxide.Ext.Discord/Exceptions/Entities/InvalidSnowflakeException.cs index da0bcdf33..ad367eb0b 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/InvalidSnowflakeException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/InvalidSnowflakeException.cs @@ -1,61 +1,61 @@ using System.Collections.Generic; +using System.Runtime.CompilerServices; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception thrown when an invalid Snowflake ID is used in an API call +/// +public class InvalidSnowflakeException : BaseDiscordException { /// - /// Exception thrown when an invalid Snowflake ID is used in an API call + /// Constructor /// - public class InvalidSnowflakeException : BaseDiscordException - { - /// - /// Constructor - /// - /// Exception message - private InvalidSnowflakeException(string message) : base(message) { } + /// Exception message + private InvalidSnowflakeException(string message) : base(message) { } - internal static InvalidSnowflakeException InvalidException(string paramName) => new InvalidSnowflakeException($"Invalid Snowflake ID. Parameter Name: {paramName}"); + internal static InvalidSnowflakeException InvalidException(string paramName) => new($"Invalid Snowflake ID. Parameter Name: {paramName}"); - internal static void ThrowIfInvalid(Snowflake snowflake, string paramName) + public static void ThrowIfInvalid(Snowflake snowflake, [CallerArgumentExpression("snowflake")] string paramName = null) + { + if (!snowflake.IsValid()) { - if (!snowflake.IsValid()) - { - throw InvalidException(paramName); - } + throw InvalidException(paramName); } + } - internal static void ThrowIfInvalid(Snowflake? snowflake, string paramName) + public static void ThrowIfInvalid(Snowflake? snowflake, [CallerArgumentExpression("snowflake")] string paramName = null) + { + if (snowflake.HasValue && !snowflake.Value.IsValid()) { - if (snowflake.HasValue && !snowflake.Value.IsValid()) - { - throw new InvalidSnowflakeException($"Invalid Snowflake ID. Parameter Name: {paramName}"); - } + throw new InvalidSnowflakeException($"Invalid Snowflake ID. Parameter Name: {paramName}"); } + } - internal static void ThrowIfInvalid(ICollection snowflakes, string paramName) + public static void ThrowIfInvalid(ICollection snowflakes, [CallerArgumentExpression("snowflakes")] string paramName = null) + { + int index = 0; + foreach (Snowflake snowflake in snowflakes) { - int index = 0; - foreach (Snowflake snowflake in snowflakes) + if (!snowflake.IsValid()) { - if (!snowflake.IsValid()) - { - throw new InvalidSnowflakeException($"Invalid Snowflake ID. Parameter Name: {paramName}[{index}]"); - } - index++; + throw new InvalidSnowflakeException($"Invalid Snowflake ID. Parameter Name: {paramName}[{index}]"); } + index++; } + } - internal static void ThrowIfInvalid(Snowflake? snowflake, bool requireValue, string paramName) + public static void ThrowIfInvalid(Snowflake? snowflake, bool requireValue, [CallerArgumentExpression("snowflake")] string paramName = null) + { + if (requireValue && !snowflake.HasValue) { - if (requireValue && !snowflake.HasValue) - { - throw new InvalidSnowflakeException($"Snowflake is null when snowflake is required. Parameter Name: {paramName}"); - } + throw new InvalidSnowflakeException($"Snowflake is null when snowflake is required. Parameter Name: {paramName}"); + } - if (snowflake.HasValue) - { - ThrowIfInvalid(snowflake.Value, paramName); - } + if (snowflake.HasValue) + { + ThrowIfInvalid(snowflake.Value, paramName); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidEmbedException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidEmbedException.cs index 09ab1ef76..b195d3e3b 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidEmbedException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidEmbedException.cs @@ -1,99 +1,98 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an invalid embed +/// +public class InvalidEmbedException : BaseDiscordException { /// - /// Represents an invalid embed + /// Constructor /// - public class InvalidEmbedException : BaseDiscordException + /// Exception message + private InvalidEmbedException(string message) : base(message) { - /// - /// Constructor - /// - /// Exception message - private InvalidEmbedException(string message) : base(message) - { - } + } - internal static void ThrowIfEmbedLimit(int? count) + internal static void ThrowIfEmbedLimit(int? count) + { + if (count > 10) { - if (count > 10) - { - throw new InvalidEmbedException("You cannot add more than 10 embeds in a message"); - } + throw new InvalidEmbedException("You cannot add more than 10 embeds in a message"); } + } - internal static void ThrowIfInvalidTitle(string title) + internal static void ThrowIfInvalidTitle(string title) + { + if (title.Length > 256) { - if (title.Length > 256) - { - throw new InvalidEmbedException("Title cannot be more than 256 characters"); - } + throw new InvalidEmbedException("Title cannot be more than 256 characters"); } + } - internal static void ThrowIfInvalidDescription(string description) + internal static void ThrowIfInvalidDescription(string description) + { + if (description.Length > 4096) { - if (description.Length > 4096) - { - throw new InvalidEmbedException("Description cannot be more than 4096 characters"); - } + throw new InvalidEmbedException("Description cannot be more than 4096 characters"); } + } - internal static void ThrowIfInvalidFieldCount(int count) + internal static void ThrowIfInvalidFieldCount(int count) + { + if (count > 25) { - if (count > 25) - { - throw new InvalidEmbedException("Embeds cannot have more than 25 fields"); - } + throw new InvalidEmbedException("Embeds cannot have more than 25 fields"); } + } - internal static void ThrowIfInvalidFieldName(string name) + internal static void ThrowIfInvalidFieldName(string name) + { + if (name != null && name.Length > 256) { - if (name != null && name.Length > 256) - { - throw new InvalidEmbedException("Embed Field Name cannot be more than 256 characters"); - } + throw new InvalidEmbedException("Embed Field Name cannot be more than 256 characters"); } + } - internal static void ThrowIfInvalidFieldValue(string value) + internal static void ThrowIfInvalidFieldValue(string value) + { + if (value != null && value.Length > 1024) { - if (value != null && value.Length > 1024) - { - throw new InvalidEmbedException("Embed Field Value cannot be more than 1024 characters"); - } + throw new InvalidEmbedException("Embed Field Value cannot be more than 1024 characters"); } + } - internal static void ThrowIfInvalidFooterText(string text) + internal static void ThrowIfInvalidFooterText(string text) + { + if (text == null) { - if (text == null) - { - throw new InvalidEmbedException("Embed Footer Text cannot be null"); - } + throw new InvalidEmbedException("Embed Footer Text cannot be null"); + } - if (text.Length > 2048) - { - throw new InvalidEmbedException("Embed Footer Text cannot be more than 2048 characters"); - } + if (text.Length > 2048) + { + throw new InvalidEmbedException("Embed Footer Text cannot be more than 2048 characters"); } + } - internal static void ThrowIfInvalidAuthorName(string name) + internal static void ThrowIfInvalidAuthorName(string name) + { + if (name == null) { - if (name == null) - { - throw new InvalidEmbedException("Embed Author Name cannot be null"); - } + throw new InvalidEmbedException("Embed Author Name cannot be null"); + } - if (name.Length > 256) - { - throw new InvalidEmbedException("Embed Author Name cannot be more than 256 characters"); - } + if (name.Length > 256) + { + throw new InvalidEmbedException("Embed Author Name cannot be more than 256 characters"); } + } - internal static void ThrowIfInvalidUrl(string url) + internal static void ThrowIfInvalidUrl(string url) + { + if (url == null) { - if (url == null) - { - throw new InvalidEmbedException("Url cannot be null"); - } + throw new InvalidEmbedException("Url cannot be null"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidFileNameException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidFileNameException.cs index 2b5c00669..d50a213bc 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidFileNameException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidFileNameException.cs @@ -1,31 +1,30 @@ using System.Text.RegularExpressions; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception throw when an attachment filename contains invalid characters +/// +public class InvalidFileNameException : BaseDiscordException { /// - /// Exception throw when an attachment filename contains invalid characters + /// Regex file name validation ensuring filenames are valid /// - public class InvalidFileNameException : BaseDiscordException - { - /// - /// Regex file name validation ensuring filenames are valid - /// - public static readonly Regex FilenameValidation = new Regex("^[a-zA-Z0-9_.-]*$", RegexOptions.Compiled); + public static readonly Regex FilenameValidation = new("^[a-zA-Z0-9_.-]*$", RegexOptions.Compiled); - /// - /// Constructor - /// - /// invalid file name - private InvalidFileNameException(string fileName) : base($"'{fileName}' is not a valid filename for discord. " + - "Valid filename characters are alphanumeric with underscores, dashes, or dots") - { } + /// + /// Constructor + /// + /// invalid file name + private InvalidFileNameException(string fileName) : base($"'{fileName}' is not a valid filename for discord. " + + "Valid filename characters are alphanumeric with underscores, dashes, or dots") + { } - internal static void ThrowIfInvalid(string fileName) + internal static void ThrowIfInvalid(string fileName) + { + if (!FilenameValidation.IsMatch(fileName)) { - if (!FilenameValidation.IsMatch(fileName)) - { - throw new InvalidFileNameException(fileName); - } + throw new InvalidFileNameException(fileName); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidMessageException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidMessageException.cs index aa27d4e10..34dff0e91 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidMessageException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Messages/InvalidMessageException.cs @@ -1,92 +1,92 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an invalid message +/// +public class InvalidMessageException : BaseDiscordException { /// - /// Represents an invalid message + /// Constructor /// - public class InvalidMessageException : BaseDiscordException + /// Exception message + private InvalidMessageException(string message) : base(message) { - /// - /// Constructor - /// - /// Exception message - private InvalidMessageException(string message) : base(message) - { - } + } - /// - /// Constructor - /// - /// Exception message - /// Message Create that caused the error - private InvalidMessageException(string message, BaseMessageCreate create) : base($"{message}\nBody:{JsonConvert.SerializeObject(create, Formatting.Indented)}") - { + /// + /// Constructor + /// + /// Exception message + /// Message Create that caused the error + private InvalidMessageException(string message, BaseMessageCreate create) : base($"{message}\nBody:{JsonConvert.SerializeObject(create, Formatting.Indented)}") + { - } + } - internal static void ThrowIfMissingRequiredField(BaseMessageCreate create) + internal static void ThrowIfMissingRequiredField(BaseMessageCreate create) + { + if (string.IsNullOrEmpty(create.Content) + && (create.Embeds == null || create.Embeds.Count == 0) + && (create.FileAttachments == null || create.FileAttachments.Count == 0) + && (create.StickerIds == null || create.StickerIds.Count == 0) + && (create.Components == null || create.Components.Count == 0 || create.Components[0].Components.Count == 0) + && create.Poll == null) { - if (string.IsNullOrEmpty(create.Content) - && (create.Embeds == null || create.Embeds.Count == 0) - && (create.FileAttachments == null || create.FileAttachments.Count == 0) - && (create.StickerIds == null || create.StickerIds.Count == 0) - && (create.Components == null || create.Components.Count == 0 || create.Components[0].Components.Count == 0)) - { - throw new InvalidMessageException("Discord Messages require either Content, An Embed, A Sticker, A Message Component, or a File", create); - } + throw new InvalidMessageException("Discord Messages require either Content, An Embed, A Sticker, A Message Component, A File, or a Poll", create); } + } - internal static void ThrowIfInvalidContent(string content) + internal static void ThrowIfInvalidContent(string content) + { + if (content != null && content.Length > 2000) { - if (content != null && content.Length > 2000) - { - throw new InvalidMessageException("Content cannot be more than 2000 characters"); - } + throw new InvalidMessageException("Content cannot be more than 2000 characters"); } + } - internal static void ThrowIfMaxStickers(int? count) + internal static void ThrowIfMaxStickers(int? count) + { + if (count > 3) { - if (count > 3) - { - throw new InvalidMessageException("Cannot have more than 3 stickers"); - } + throw new InvalidMessageException("Cannot have more than 3 stickers"); } + } - internal static void ThrowIfInvalidFlags(MessageFlags? flags, MessageFlags allowedFlags, string message) + internal static void ThrowIfInvalidFlags(MessageFlags? flags, MessageFlags allowedFlags, string message) + { + if (flags.HasValue && (flags & ~allowedFlags) != 0) { - if (flags.HasValue && (flags & ~allowedFlags) != 0) - { - throw new InvalidMessageException(message); - } + throw new InvalidMessageException(message); } + } - internal static void ThrowIfInvalidAttachmentDescription(string description) + internal static void ThrowIfInvalidAttachmentDescription(string description) + { + if (!string.IsNullOrEmpty(description) && description.Length > 1024) { - if (!string.IsNullOrEmpty(description) && description.Length > 1024) - { - throw new InvalidMessageException("Message attachment description cannot be more than 1024 characters"); - } + throw new InvalidMessageException("Message attachment description cannot be more than 1024 characters"); } + } - internal static void ThrowIfCantBeDeleted(DiscordMessage message) + internal static void ThrowIfCantBeDeleted(DiscordMessage message) + { + switch (message.Type) { - switch (message.Type) - { - case MessageType.RecipientAdd: - case MessageType.RecipientRemove: - case MessageType.Call: - case MessageType.ChannelNameChange: - case MessageType.ChannelIconChange: - case MessageType.GuildDiscoveryDisqualified: - case MessageType.GuildDiscoveryRequalified: - case MessageType.GuildDiscoveryGracePeriodInitialWarning: - case MessageType.GuildDiscoveryGracePeriodFinalWarning: - case MessageType.ThreadStarterMessage: - throw new InvalidMessageException($"This message cannot be deleted because it is of type {message.Type}"); - } + case MessageType.RecipientAdd: + case MessageType.RecipientRemove: + case MessageType.Call: + case MessageType.ChannelNameChange: + case MessageType.ChannelIconChange: + case MessageType.GuildDiscoveryDisqualified: + case MessageType.GuildDiscoveryRequalified: + case MessageType.GuildDiscoveryGracePeriodInitialWarning: + case MessageType.GuildDiscoveryGracePeriodFinalWarning: + case MessageType.ThreadStarterMessage: + throw new InvalidMessageException($"This message cannot be deleted because it is of type {message.Type}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Monetization/InvalidGetEntitlementException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Monetization/InvalidGetEntitlementException.cs index eb0586ca4..ab52f6848 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Monetization/InvalidGetEntitlementException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Monetization/InvalidGetEntitlementException.cs @@ -1,30 +1,29 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exceptions for invalid entitlements +/// +public class InvalidGetEntitlementException : BaseDiscordException { /// - /// Exceptions for invalid entitlements + /// Constructor /// - public class InvalidGetEntitlementException : BaseDiscordException - { - /// - /// Constructor - /// - /// Exception message - private InvalidGetEntitlementException(string message) : base(message) { } + /// Exception message + private InvalidGetEntitlementException(string message) : base(message) { } - internal static void ThrowIfInvalidLimit(int? limit) - { - const int MinLimit = 1; - const int MaxLimit = 100; + internal static void ThrowIfInvalidLimit(int? limit) + { + const int MinLimit = 1; + const int MaxLimit = 100; - if (limit < MinLimit) - { - throw new InvalidGetEntitlementException($"Limit cannot be less than {MinLimit}"); - } + if (limit < MinLimit) + { + throw new InvalidGetEntitlementException($"Limit cannot be less than {MinLimit}"); + } - if (limit > MaxLimit) - { - throw new InvalidGetEntitlementException($"Limit cannot be more than {MaxLimit}"); - } + if (limit > MaxLimit) + { + throw new InvalidGetEntitlementException($"Limit cannot be more than {MaxLimit}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Permissions/InvalidDiscordColorException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Permissions/InvalidDiscordColorException.cs index 0dc04bdb8..38973db84 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Permissions/InvalidDiscordColorException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Permissions/InvalidDiscordColorException.cs @@ -1,49 +1,48 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an invalid discord color +/// +public class InvalidDiscordColorException : BaseDiscordException { /// - /// Represents an invalid discord color + /// Constructor /// - public class InvalidDiscordColorException : BaseDiscordException + /// Exception message + private InvalidDiscordColorException(string message) : base(message) { - /// - /// Constructor - /// - /// Exception message - private InvalidDiscordColorException(string message) : base(message) - { - } + } - internal static void ThrowIfInvalidColor(uint color) + internal static void ThrowIfInvalidColor(uint color) + { + if (color > 0xFFFFFF) { - if (color > 0xFFFFFF) - { - throw new InvalidDiscordColorException($"Color '{color}' is greater than the max color of 0xFFFFFF"); - } + throw new InvalidDiscordColorException($"Color '{color}' is greater than the max color of 0xFFFFFF"); } + } - internal static void ThrowIfOutOfColorRange(string color, int value) + internal static void ThrowIfOutOfColorRange(string color, int value) + { + if (value < 0 || value > byte.MaxValue) { - if (value < 0 || value > byte.MaxValue) - { - throw new InvalidDiscordColorException($"{color} must be between 0 - 255"); - } + throw new InvalidDiscordColorException($"{color} must be between 0 - 255"); } + } - internal static void ThrowIfOutOfColorRange(string color, uint value) + internal static void ThrowIfOutOfColorRange(string color, uint value) + { + if (value > byte.MaxValue) { - if (value > byte.MaxValue) - { - throw new InvalidDiscordColorException($"{color} must be between 0 - 255"); - } + throw new InvalidDiscordColorException($"{color} must be between 0 - 255"); } + } - internal static void ThrowIfOutOfColorRange(string color, float value) + internal static void ThrowIfOutOfColorRange(string color, float value) + { + if (value < 0f || value > 1f) { - if (value < 0f || value > 1f) - { - throw new InvalidDiscordColorException($"{color} must be between 0 - 255"); - } + throw new InvalidDiscordColorException($"{color} must be between 0 - 255"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Stickers/InvalidGuildStickerException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Stickers/InvalidGuildStickerException.cs index a44b06027..e2989e046 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Stickers/InvalidGuildStickerException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Stickers/InvalidGuildStickerException.cs @@ -1,75 +1,74 @@ using System; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception in guild stickers +/// +public class InvalidGuildStickerException : BaseDiscordException { - /// - /// Represents an exception in guild stickers - /// - public class InvalidGuildStickerException : BaseDiscordException - { - private InvalidGuildStickerException(string message) : base(message) { } + private InvalidGuildStickerException(string message) : base(message) { } - internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) + internal static void ThrowIfInvalidName(string name, bool allowNullOrEmpty) + { + if (!allowNullOrEmpty && string.IsNullOrEmpty(name) || name.Length < 2) { - if (!allowNullOrEmpty && string.IsNullOrEmpty(name) || name.Length < 2) - { - throw new InvalidGuildStickerException("Name cannot be less than 2 character"); - } + throw new InvalidGuildStickerException("Name cannot be less than 2 character"); + } - if (name.Length > 30) - { - throw new InvalidGuildStickerException("Name cannot be more than 30 characters"); - } + if (name.Length > 30) + { + throw new InvalidGuildStickerException("Name cannot be more than 30 characters"); } + } - internal static void ThrowIfInvalidDescription(string description, bool allowNullOrEmpty) + internal static void ThrowIfInvalidDescription(string description, bool allowNullOrEmpty) + { + if (!allowNullOrEmpty && string.IsNullOrEmpty(description) || description.Length < 2) { - if (!allowNullOrEmpty && string.IsNullOrEmpty(description) || description.Length < 2) - { - throw new InvalidGuildStickerException("Description cannot be less than 2 character"); - } + throw new InvalidGuildStickerException("Description cannot be less than 2 character"); + } - if (description.Length > 100) - { - throw new InvalidGuildStickerException("Description cannot be more than 100 characters"); - } + if (description.Length > 100) + { + throw new InvalidGuildStickerException("Description cannot be more than 100 characters"); } + } - internal static void ThrowIfNotGuildType(StickerType type, string message) + internal static void ThrowIfNotGuildType(StickerType type, string message) + { + if (type != StickerType.Guild) { - if (type != StickerType.Guild) - { - throw new InvalidGuildStickerException(message); - } + throw new InvalidGuildStickerException(message); } + } - internal static void ThrowIfMoreThanOneImage(int count) + internal static void ThrowIfMoreThanOneImage(int count) + { + if (count != 0) { - if (count != 0) - { - throw new InvalidGuildStickerException("Can only add one sticker at a time"); - } + throw new InvalidGuildStickerException("Can only add one sticker at a time"); } + } - internal static void ThrowIfImageTooLarge(byte[] sticker) + internal static void ThrowIfImageTooLarge(byte[] sticker) + { + const int MaxStickerSizeKb = 512; + if (sticker.Length > MaxStickerSizeKb * 1024) { - const int MaxStickerSizeKb = 512; - if (sticker.Length > MaxStickerSizeKb * 1024) - { - throw new InvalidGuildStickerException($"sticker image size cannot be larger than {MaxStickerSizeKb}KB"); - } + throw new InvalidGuildStickerException($"sticker image size cannot be larger than {MaxStickerSizeKb}KB"); } + } - internal static void ThrowIfInvalidFileExtension(string fileName) + internal static void ThrowIfInvalidFileExtension(string fileName) + { + if (!fileName.EndsWith(".png", StringComparison.OrdinalIgnoreCase) + && !fileName.EndsWith(".apng", StringComparison.OrdinalIgnoreCase) + && !fileName.EndsWith(".json", StringComparison.OrdinalIgnoreCase) + && !fileName.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) { - if (!fileName.EndsWith(".png", StringComparison.OrdinalIgnoreCase) - && !fileName.EndsWith(".apng", StringComparison.OrdinalIgnoreCase) - && !fileName.EndsWith(".json", StringComparison.OrdinalIgnoreCase) - && !fileName.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidGuildStickerException("Sticker can only be of type png, apng, gif, or lottie json"); - } + throw new InvalidGuildStickerException("Sticker can only be of type png, apng, gif, or lottie json"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Users/BlockedUserException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Users/BlockedUserException.cs index efe463714..b4ad8bdd6 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Users/BlockedUserException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Users/BlockedUserException.cs @@ -1,27 +1,26 @@ using System; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception when a user has blocked receving messages from a bot +/// +public class BlockedUserException : BaseDiscordException { /// - /// Exception when a user has blocked receving messages from a bot + /// User who has blocked messages /// - public class BlockedUserException : BaseDiscordException - { - /// - /// User who has blocked messages - /// - public readonly DiscordUser User; + public readonly DiscordUser User; - /// - /// Time until we try sending a message again - /// - public readonly DateTime BlockedUntil; + /// + /// Time until we try sending a message again + /// + public readonly DateTime BlockedUntil; - internal BlockedUserException(DiscordUser user, DateTime blockedUntil) - { - User = user; - BlockedUntil = blockedUntil; - } + internal BlockedUserException(DiscordUser user, DateTime blockedUntil) + { + User = user; + BlockedUntil = blockedUntil; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Users/InvalidUserException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Users/InvalidUserException.cs index 3c1d43af6..a8fecfafc 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Users/InvalidUserException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Users/InvalidUserException.cs @@ -1,47 +1,46 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception when modifying a user with invalid data +/// +public class InvalidUserException : BaseDiscordException { /// - /// Represents an exception when modifying a user with invalid data + /// Invalid username characters /// - public class InvalidUserException : BaseDiscordException - { - /// - /// Invalid username characters - /// - public static readonly char[] InvalidUserNameCharacters = "@#:".ToCharArray(); + public static readonly char[] InvalidUserNameCharacters = "@#:".ToCharArray(); - /// - /// Constructor - /// - /// Error Message - private InvalidUserException(string message) : base(message) { } + /// + /// Constructor + /// + /// Error Message + private InvalidUserException(string message) : base(message) { } - internal static void ThrowIfInvalidUserName(string username) + internal static void ThrowIfInvalidUserName(string username) + { + if (string.IsNullOrEmpty(username)) { - if (string.IsNullOrEmpty(username)) - { - return; - } + return; + } - if (username.Length < 2 || username.Length > 32) - { - throw new InvalidUserException($"Name '{username}' cannot be less than 2 characters or more than 32 characters"); - } + if (username.Length < 2 || username.Length > 32) + { + throw new InvalidUserException($"Name '{username}' cannot be less than 2 characters or more than 32 characters"); + } - if (username.IndexOfAny(InvalidUserNameCharacters) != -1) - { - throw new InvalidUserException($"Name '{username}' Cannot contain any of the following characters [@,#,:]"); - } + if (username.IndexOfAny(InvalidUserNameCharacters) != -1) + { + throw new InvalidUserException($"Name '{username}' Cannot contain any of the following characters [@,#,:]"); + } - if (username.Contains("```")) - { - throw new InvalidUserException($"Name '{username}' Cannot contain \"```\""); - } + if (username.Contains("```")) + { + throw new InvalidUserException($"Name '{username}' Cannot contain \"```\""); + } - if (username.Contains("discord")) - { - throw new InvalidUserException($"Name '{username}' Cannot contain \"discord\""); - } + if (username.Contains("discord")) + { + throw new InvalidUserException($"Name '{username}' Cannot contain \"discord\""); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Webhooks/InvalidWebhookException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Webhooks/InvalidWebhookException.cs index fe8da33ef..81858a6bf 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Webhooks/InvalidWebhookException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Webhooks/InvalidWebhookException.cs @@ -1,43 +1,42 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents a Webhook Create Exception +/// +public class InvalidWebhookException : BaseDiscordException { /// - /// Represents a Webhook Create Exception + /// Invalid username characters /// - public class InvalidWebhookException : BaseDiscordException - { - /// - /// Invalid username characters - /// - public static readonly char[] InvalidUserNameCharacters = "@#:".ToCharArray(); + public static readonly char[] InvalidUserNameCharacters = "@#:".ToCharArray(); - /// - /// Constructor - /// - /// Error Message - private InvalidWebhookException(string message) : base(message) { } + /// + /// Constructor + /// + /// Error Message + private InvalidWebhookException(string message) : base(message) { } - internal static void ThrowIfInvalidName(string name) + internal static void ThrowIfInvalidName(string name) + { + const int MaxLength = 80; + if (string.IsNullOrEmpty(name) || name.Length > MaxLength) { - const int MaxLength = 80; - if (string.IsNullOrEmpty(name) || name.Length > MaxLength) - { - throw new InvalidWebhookException($"Name '{name}' cannot be less than 1 character or more than {MaxLength} characters"); - } + throw new InvalidWebhookException($"Name '{name}' cannot be less than 1 character or more than {MaxLength} characters"); + } - if (name.IndexOfAny(InvalidUserNameCharacters) != -1) - { - throw new InvalidWebhookException($"Name '{name}' Cannot contain any of the following characters [@,#,:]"); - } + if (name.IndexOfAny(InvalidUserNameCharacters) != -1) + { + throw new InvalidWebhookException($"Name '{name}' Cannot contain any of the following characters [@,#,:]"); + } - if (name.Contains("```")) - { - throw new InvalidWebhookException($"Name '{name}' Cannot contain \"```\""); - } + if (name.Contains("```")) + { + throw new InvalidWebhookException($"Name '{name}' Cannot contain \"```\""); + } - if (name.Contains("discord")) - { - throw new InvalidWebhookException($"Name '{name}' Cannot contain \"discord\""); - } + if (name.Contains("discord")) + { + throw new InvalidWebhookException($"Name '{name}' Cannot contain \"discord\""); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Entities/Websocket/DiscordWebSocketException.cs b/Oxide.Ext.Discord/Exceptions/Entities/Websocket/DiscordWebSocketException.cs index 1d0263aa5..d2e6288dc 100644 --- a/Oxide.Ext.Discord/Exceptions/Entities/Websocket/DiscordWebSocketException.cs +++ b/Oxide.Ext.Discord/Exceptions/Entities/Websocket/DiscordWebSocketException.cs @@ -1,10 +1,9 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents an exception that occured with the websocket +/// +public class DiscordWebSocketException : BaseDiscordException { - /// - /// Represents an exception that occured with the websocket - /// - public class DiscordWebSocketException : BaseDiscordException - { - internal DiscordWebSocketException(string message) : base(message) { } - } + internal DiscordWebSocketException(string message) : base(message) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Libraries/DiscordLocale/DiscordLocaleNotFoundException.cs b/Oxide.Ext.Discord/Exceptions/Libraries/DiscordLocale/DiscordLocaleNotFoundException.cs index d9a9c2e80..a8985f8d6 100644 --- a/Oxide.Ext.Discord/Exceptions/Libraries/DiscordLocale/DiscordLocaleNotFoundException.cs +++ b/Oxide.Ext.Discord/Exceptions/Libraries/DiscordLocale/DiscordLocaleNotFoundException.cs @@ -1,15 +1,14 @@ using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception thrown when Discord Locale is not found +/// +public class DiscordLocaleNotFoundException : BaseDiscordException { - /// - /// Exception thrown when Discord Locale is not found - /// - public class DiscordLocaleNotFoundException : BaseDiscordException - { - private DiscordLocaleNotFoundException(string message) : base(message) { } + private DiscordLocaleNotFoundException(string message) : base(message) { } - internal static DiscordLocaleNotFoundException NotFound(ServerLocale id) => new DiscordLocaleNotFoundException($"Failed to find discord locale for server locale '{id.Id}'"); - internal static void ThrowNotFound(ServerLocale id) => throw NotFound(id); - } + internal static DiscordLocaleNotFoundException NotFound(ServerLocale id) => new($"Failed to find discord locale for server locale '{id.Id}'"); + internal static void ThrowNotFound(ServerLocale id) => throw NotFound(id); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Libraries/DiscordLocale/ServerLocaleNotFoundException.cs b/Oxide.Ext.Discord/Exceptions/Libraries/DiscordLocale/ServerLocaleNotFoundException.cs index 289e542b0..26c3d7122 100644 --- a/Oxide.Ext.Discord/Exceptions/Libraries/DiscordLocale/ServerLocaleNotFoundException.cs +++ b/Oxide.Ext.Discord/Exceptions/Libraries/DiscordLocale/ServerLocaleNotFoundException.cs @@ -1,18 +1,17 @@ using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception thrown when Server Locale is not found +/// +public class ServerLocaleNotFoundException : BaseDiscordException { - /// - /// Exception thrown when Server Locale is not found - /// - public class ServerLocaleNotFoundException : BaseDiscordException - { - private ServerLocaleNotFoundException(string message) : base(message) { } + private ServerLocaleNotFoundException(string message) : base(message) { } - internal static ServerLocaleNotFoundException NotFound(DiscordLocale id) => throw new ServerLocaleNotFoundException($"Failed to find discord locale for server locale '{id.Id}'"); - internal static ServerLocaleNotFoundException NotFound(ServerLocale id) => throw new ServerLocaleNotFoundException($"Failed to find server local '{id.Id}'"); + internal static ServerLocaleNotFoundException NotFound(DiscordLocale id) => throw new ServerLocaleNotFoundException($"Failed to find discord locale for server locale '{id.Id}'"); + internal static ServerLocaleNotFoundException NotFound(ServerLocale id) => throw new ServerLocaleNotFoundException($"Failed to find server local '{id.Id}'"); - internal static void ThrowNotFound(DiscordLocale id) => throw NotFound(id); - internal static void ThrowNotFound(ServerLocale id) => throw NotFound(id); - } + internal static void ThrowNotFound(DiscordLocale id) => throw NotFound(id); + internal static void ThrowNotFound(ServerLocale id) => throw NotFound(id); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Libraries/Placeholders/InvalidPlaceholderDataException.cs b/Oxide.Ext.Discord/Exceptions/Libraries/Placeholders/InvalidPlaceholderDataException.cs index 22b7dfff8..f2f54459b 100644 --- a/Oxide.Ext.Discord/Exceptions/Libraries/Placeholders/InvalidPlaceholderDataException.cs +++ b/Oxide.Ext.Discord/Exceptions/Libraries/Placeholders/InvalidPlaceholderDataException.cs @@ -1,20 +1,19 @@ using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception thrown if is not valid +/// +public class InvalidPlaceholderDataException : BaseDiscordException { - /// - /// Exception thrown if is not valid - /// - public class InvalidPlaceholderDataException : BaseDiscordException - { - private InvalidPlaceholderDataException(string message) : base(message) { } + private InvalidPlaceholderDataException(string message) : base(message) { } - internal static void ThrowIfInvalid(PlaceholderDataKey key) + internal static void ThrowIfInvalid(PlaceholderDataKey key) + { + if (!key.IsValid) { - if (!key.IsValid) - { - throw new InvalidPlaceholderDataException("PlaceholderDataKey is not valid"); - } + throw new InvalidPlaceholderDataException("PlaceholderDataKey is not valid"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Libraries/Placeholders/InvalidPlaceholderException.cs b/Oxide.Ext.Discord/Exceptions/Libraries/Placeholders/InvalidPlaceholderException.cs index 361265f0c..44cd111d8 100644 --- a/Oxide.Ext.Discord/Exceptions/Libraries/Placeholders/InvalidPlaceholderException.cs +++ b/Oxide.Ext.Discord/Exceptions/Libraries/Placeholders/InvalidPlaceholderException.cs @@ -1,20 +1,19 @@ using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception thrown if is not valid +/// +public class InvalidPlaceholderException : BaseDiscordException { - /// - /// Exception thrown if is not valid - /// - public class InvalidPlaceholderException : BaseDiscordException - { - private InvalidPlaceholderException(string message) : base(message) { } + private InvalidPlaceholderException(string message) : base(message) { } - internal static void ThrowIfInvalid(PlaceholderKey key) + internal static void ThrowIfInvalid(PlaceholderKey key) + { + if (!key.IsValid) { - if (!key.IsValid) - { - throw new InvalidPlaceholderException("PlaceholderKey is not valid"); - } + throw new InvalidPlaceholderException("PlaceholderKey is not valid"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Libraries/Promise/PromiseCancelledException.cs b/Oxide.Ext.Discord/Exceptions/Libraries/Promise/PromiseCancelledException.cs index 505ec4dc1..f2310d5f3 100644 --- a/Oxide.Ext.Discord/Exceptions/Libraries/Promise/PromiseCancelledException.cs +++ b/Oxide.Ext.Discord/Exceptions/Libraries/Promise/PromiseCancelledException.cs @@ -1,14 +1,13 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception when a promised is cancelled +/// +public class PromiseCancelledException : BaseDiscordException { /// - /// Exception when a promised is cancelled + /// Create the exception with description /// - public class PromiseCancelledException : BaseDiscordException - { - /// - /// Create the exception with description - /// - /// Exception description - internal PromiseCancelledException(string message) : base(message) { } - } + /// Exception description + internal PromiseCancelledException(string message) : base(message) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Libraries/Promise/PromiseException.cs b/Oxide.Ext.Discord/Exceptions/Libraries/Promise/PromiseException.cs index a53f92363..c699a9e82 100644 --- a/Oxide.Ext.Discord/Exceptions/Libraries/Promise/PromiseException.cs +++ b/Oxide.Ext.Discord/Exceptions/Libraries/Promise/PromiseException.cs @@ -2,23 +2,22 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exceptions for promises +/// +public class PromiseException : BaseDiscordException { - /// - /// Exceptions for promises - /// - public class PromiseException : BaseDiscordException - { - private PromiseException(string message) : base(message) { } + private PromiseException(string message) : base(message) { } - internal static void ThrowIfNotPending(PromiseState state) - { - if (state != PromiseState.Pending) throw new PromiseException($"Attempt to reject a promise that is already in state: {state}, a promise can only be rejected when it is still in state: {PromiseState.Pending}"); - } + internal static void ThrowIfNotPending(PromiseState state) + { + if (state != PromiseState.Pending) throw new PromiseException($"Attempt to reject a promise that is already in state: {state}, a promise can only be rejected when it is still in state: {PromiseState.Pending}"); + } - internal static void ThrowIfDisposed(BasePromise promise) - { - if (promise.Disposed) throw new ObjectDisposedException($"{promise.GetType().GetRealTypeName()}"); - } + internal static void ThrowIfDisposed(BasePromise promise) + { + if (promise.Disposed) throw new ObjectDisposedException($"{promise.GetType().GetRealTypeName()}"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Libraries/Templates/DiscordTemplateException.cs b/Oxide.Ext.Discord/Exceptions/Libraries/Templates/DiscordTemplateException.cs index 432746c80..d5d373e83 100644 --- a/Oxide.Ext.Discord/Exceptions/Libraries/Templates/DiscordTemplateException.cs +++ b/Oxide.Ext.Discord/Exceptions/Libraries/Templates/DiscordTemplateException.cs @@ -1,39 +1,38 @@ using System.Text.RegularExpressions; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception for Discord Templates +/// +public class DiscordTemplateException : BaseDiscordException { - /// - /// Exception for Discord Templates - /// - public class DiscordTemplateException : BaseDiscordException - { - private static readonly Regex FileNameRegex = new Regex(@"^[\w \.]+$", RegexOptions.Compiled); - private static readonly Regex DuplicateCharacterRegex = new Regex(@"(\.)\1{1}", RegexOptions.Compiled); + private static readonly Regex FileNameRegex = new(@"^[\w \.]+$", RegexOptions.Compiled); + private static readonly Regex DuplicateCharacterRegex = new(@"(\.)\1{1}", RegexOptions.Compiled); - private DiscordTemplateException(string message) : base(message) { } + private DiscordTemplateException(string message) : base(message) { } - internal static void ThrowIfInvalidTemplateName(string name, TemplateType type) + internal static void ThrowIfInvalidTemplateName(string name, TemplateType type) + { + if (type == TemplateType.Command && string.IsNullOrEmpty(name)) { - if (type == TemplateType.Command && string.IsNullOrEmpty(name)) - { - return; - } + return; + } - if (string.IsNullOrEmpty(name)) - { - throw new DiscordTemplateException($"{name} cannot contain be null or empty"); - } + if (string.IsNullOrEmpty(name)) + { + throw new DiscordTemplateException($"{name} cannot contain be null or empty"); + } - if (!FileNameRegex.IsMatch(name)) - { - throw new DiscordTemplateException($"{name} is not a valid template name. Only Letters, Numbers, _, ., and spaces are allowed"); - } + if (!FileNameRegex.IsMatch(name)) + { + throw new DiscordTemplateException($"{name} is not a valid template name. Only Letters, Numbers, _, ., and spaces are allowed"); + } - if (DuplicateCharacterRegex.IsMatch(name)) - { - throw new DiscordTemplateException($"{name} cannot contain duplicate '.'"); - } + if (DuplicateCharacterRegex.IsMatch(name)) + { + throw new DiscordTemplateException($"{name} cannot contain duplicate '.'"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Libraries/Templates/DuplicateTemplateException.cs b/Oxide.Ext.Discord/Exceptions/Libraries/Templates/DuplicateTemplateException.cs index e933edfce..47878b8d6 100644 --- a/Oxide.Ext.Discord/Exceptions/Libraries/Templates/DuplicateTemplateException.cs +++ b/Oxide.Ext.Discord/Exceptions/Libraries/Templates/DuplicateTemplateException.cs @@ -1,10 +1,9 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Thrown when duplicate templates have been registered for the same type, plugin, and name +/// +public class DuplicateTemplateException : BaseDiscordException { - /// - /// Thrown when duplicate templates have been registered for the same type, plugin, and name - /// - public class DuplicateTemplateException : BaseDiscordException - { - internal DuplicateTemplateException(string message) : base(message) { } - } + internal DuplicateTemplateException(string message) : base(message) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Libraries/Templates/InvalidTemplateVersionException.cs b/Oxide.Ext.Discord/Exceptions/Libraries/Templates/InvalidTemplateVersionException.cs index 60382c372..ed08c7d21 100644 --- a/Oxide.Ext.Discord/Exceptions/Libraries/Templates/InvalidTemplateVersionException.cs +++ b/Oxide.Ext.Discord/Exceptions/Libraries/Templates/InvalidTemplateVersionException.cs @@ -1,10 +1,9 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Thrown when the minimum template version is higher than the current template version +/// +public class InvalidTemplateVersionException : BaseDiscordException { - /// - /// Thrown when the minimum template version is higher than the current template version - /// - public class InvalidTemplateVersionException : BaseDiscordException - { - internal InvalidTemplateVersionException(string message) : base(message) { } - } + internal InvalidTemplateVersionException(string message) : base(message) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Logging/DiscordLoggerException.cs b/Oxide.Ext.Discord/Exceptions/Logging/DiscordLoggerException.cs new file mode 100644 index 000000000..1b1e157fb --- /dev/null +++ b/Oxide.Ext.Discord/Exceptions/Logging/DiscordLoggerException.cs @@ -0,0 +1,20 @@ +using Oxide.Ext.Discord.Clients; +using Oxide.Ext.Discord.Logging; + +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exceptions for the +/// +public class DiscordLoggerException : BaseDiscordException +{ + private DiscordLoggerException(string message) : base(message) {} + + internal static void ThrowIfShutdown(DiscordLogHandler handler) + { + if (handler.IsShutdown) + { + throw new DiscordLoggerException("Cannot log into a logger that has been shutdown!"); + } + } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Pooling/InvalidPoolException.cs b/Oxide.Ext.Discord/Exceptions/Pooling/InvalidPoolException.cs index ff65fc3a5..34310b75e 100644 --- a/Oxide.Ext.Discord/Exceptions/Pooling/InvalidPoolException.cs +++ b/Oxide.Ext.Discord/Exceptions/Pooling/InvalidPoolException.cs @@ -1,33 +1,32 @@ using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// An exception when something is invalid with a pool +/// +public class InvalidPoolException : BaseDiscordException { - /// - /// An exception when something is invalid with a pool - /// - public class InvalidPoolException : BaseDiscordException - { - private InvalidPoolException(string message) : base(message) {} + private InvalidPoolException(string message) : base(message) {} - internal static void ThrowIfInvalidPoolSize(PoolSize size) + internal static void ThrowIfInvalidPoolSize(PoolSize size) + { + if (!size.IsValid) { - if (!size.IsValid) - { - throw new InvalidPoolException($"Pool Size is not a valid size. Starting: {size.StartingSize} Max: {size.MaxSize}"); - } + throw new InvalidPoolException($"Pool Size is not a valid size. Starting: {size.StartingSize} Max: {size.MaxSize}"); } + } - internal static void ThrowIfNotPowerOf2(int value, string field) + internal static void ThrowIfNotPowerOf2(int value, string field) + { + if (!IsPowerOfTwo(value)) { - if (!IsPowerOfTwo(value)) - { - throw new InvalidPoolException($"Pool Size {field}: {value} is not a valid power of 2"); - } + throw new InvalidPoolException($"Pool Size {field}: {value} is not a valid power of 2"); } + } - private static bool IsPowerOfTwo(int x) - { - return x > 0 && (x & (x - 1)) == 0; - } + private static bool IsPowerOfTwo(int x) + { + return x > 0 && (x & (x - 1)) == 0; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/Rest/RequestCancelledException.cs b/Oxide.Ext.Discord/Exceptions/Rest/RequestCancelledException.cs index 04ded3c17..ea09c67de 100644 --- a/Oxide.Ext.Discord/Exceptions/Rest/RequestCancelledException.cs +++ b/Oxide.Ext.Discord/Exceptions/Rest/RequestCancelledException.cs @@ -1,10 +1,9 @@ -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Exception returns from promise when a request is cancelled +/// +public class RequestCancelledException : BaseDiscordException { - /// - /// Exception returns from promise when a request is cancelled - /// - public class RequestCancelledException : BaseDiscordException - { - internal RequestCancelledException() : base("The request was cancelled") { } - } + internal RequestCancelledException() : base("The request was cancelled") { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Exceptions/TokenMismatchException.cs b/Oxide.Ext.Discord/Exceptions/TokenMismatchException.cs index 013c48cfd..90171cd6f 100644 --- a/Oxide.Ext.Discord/Exceptions/TokenMismatchException.cs +++ b/Oxide.Ext.Discord/Exceptions/TokenMismatchException.cs @@ -2,22 +2,21 @@ using Oxide.Ext.Discord.Connections; using Oxide.Ext.Discord.Factory; -namespace Oxide.Ext.Discord.Exceptions +namespace Oxide.Ext.Discord.Exceptions; + +/// +/// Represents a bot token mismatch +/// +public class TokenMismatchException : BaseDiscordException { - /// - /// Represents a bot token mismatch - /// - public class TokenMismatchException : BaseDiscordException - { - private TokenMismatchException(string message) : base(message) { } + private TokenMismatchException(string message) : base(message) { } - internal static void ThrowIfMismatchedToken(DiscordClient client, BotConnection expected) + internal static void ThrowIfMismatchedToken(DiscordClient client, BotConnection expected) + { + if (client.Connection.ApiToken != expected.ApiToken) { - if (client.Connection.ApiToken != expected.ApiToken) - { - BotTokenData token = BotTokenFactory.Instance.CreateFromClient(client); - throw new TokenMismatchException($"Failed to add client for plugin {client.PluginName}. Token {token.HiddenToken} does not match BotClient {expected.HiddenToken}"); - } + BotTokenData token = BotTokenFactory.Instance.CreateFromClient(client); + throw new TokenMismatchException($"Failed to add client for plugin {client.PluginName}. Token {token.HiddenToken} does not match BotClient {expected.HiddenToken}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/CastExt.cs b/Oxide.Ext.Discord/Extensions/CastExt.cs index 05d82bf2c..c4e200672 100644 --- a/Oxide.Ext.Discord/Extensions/CastExt.cs +++ b/Oxide.Ext.Discord/Extensions/CastExt.cs @@ -1,24 +1,23 @@ using System; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +internal static class CastExt { - internal static class CastExt + internal static TDestination Cast(this TSource source) { - internal static TDestination Cast(this TSource source) - { - CastImpl.Value = source; - return CastImpl.Value; - } + CastImpl.Value = source; + return CastImpl.Value; + } - private static class CastImpl - { - [ThreadStatic] - public static TSource Value; + private static class CastImpl + { + [ThreadStatic] + public static TSource Value; - static CastImpl() - { - if (typeof(TSource) != typeof(TDestination)) throw new InvalidCastException($"{typeof(TSource)} != {typeof(TDestination)}"); - } + static CastImpl() + { + if (typeof(TSource) != typeof(TDestination)) throw new InvalidCastException($"{typeof(TSource)} != {typeof(TDestination)}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/ConcurrentDictionaryExt.cs b/Oxide.Ext.Discord/Extensions/ConcurrentDictionaryExt.cs index a088d2a80..a560c66ee 100644 --- a/Oxide.Ext.Discord/Extensions/ConcurrentDictionaryExt.cs +++ b/Oxide.Ext.Discord/Extensions/ConcurrentDictionaryExt.cs @@ -3,71 +3,70 @@ using System.Collections.Generic; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// Extension for +/// +internal static class ConcurrentDictionaryExt { /// - /// Extension for + /// Remove all records from the dictionary with the given predicate filter /// - internal static class ConcurrentDictionaryExt + /// dictionary to have data removed from + /// Filter of which values to remove + /// Key type of the dictionary + /// Value type of the dictionary + internal static void RemoveAll(this ConcurrentDictionary dic, Func predicate) { - /// - /// Remove all records from the dictionary with the given predicate filter - /// - /// dictionary to have data removed from - /// Filter of which values to remove - /// Key type of the dictionary - /// Value type of the dictionary - internal static void RemoveAll(this ConcurrentDictionary dic, Func predicate) - { - if (dic == null) throw new ArgumentNullException(nameof(dic)); - - List removeKeys = DiscordPool.Internal.GetList(); - foreach (KeyValuePair key in dic) - { - if (predicate(key.Key)) - { - removeKeys.Add(key.Key); - } - } + if (dic == null) throw new ArgumentNullException(nameof(dic)); - for (int index = 0; index < removeKeys.Count; index++) + List removeKeys = DiscordPool.Internal.GetList(); + foreach (KeyValuePair key in dic) + { + if (predicate(key.Key)) { - TKey key = removeKeys[index]; - dic.TryRemove(key, out TValue _); + removeKeys.Add(key.Key); } - - DiscordPool.Internal.FreeList(removeKeys); } - - /// - /// Remove all records from the dictionary with the given predicate filter - /// - /// Dictionary to have data removed from - /// Filter of which values to remove - /// Action to call when an element is removed - /// Key type of the dictionary - /// Value type of the dictionary - internal static void RemoveAll(this ConcurrentDictionary dic, Func predicate, Action onRemove = null) + + for (int index = 0; index < removeKeys.Count; index++) { - if (dic == null) throw new ArgumentNullException(nameof(dic)); + TKey key = removeKeys[index]; + dic.TryRemove(key, out TValue _); + } - List removeKeys = DiscordPool.Internal.GetList(); - foreach (KeyValuePair key in dic) - { - if (predicate(key.Value)) - { - removeKeys.Add(key.Key); - onRemove?.Invoke(key.Value); - } - } + DiscordPool.Internal.FreeList(removeKeys); + } + + /// + /// Remove all records from the dictionary with the given predicate filter + /// + /// Dictionary to have data removed from + /// Filter of which values to remove + /// Action to call when an element is removed + /// Key type of the dictionary + /// Value type of the dictionary + internal static void RemoveAll(this ConcurrentDictionary dic, Func predicate, Action onRemove = null) + { + if (dic == null) throw new ArgumentNullException(nameof(dic)); - for (int index = 0; index < removeKeys.Count; index++) + List removeKeys = DiscordPool.Internal.GetList(); + foreach (KeyValuePair key in dic) + { + if (predicate(key.Value)) { - TKey key = removeKeys[index]; - dic.TryRemove(key, out TValue _); + removeKeys.Add(key.Key); + onRemove?.Invoke(key.Value); } + } - DiscordPool.Internal.FreeList(removeKeys); + for (int index = 0; index < removeKeys.Count; index++) + { + TKey key = removeKeys[index]; + dic.TryRemove(key, out TValue _); } + + DiscordPool.Internal.FreeList(removeKeys); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/DateTimeOffsetExt.cs b/Oxide.Ext.Discord/Extensions/DateTimeOffsetExt.cs index 1defb6375..aa08ef74e 100644 --- a/Oxide.Ext.Discord/Extensions/DateTimeOffsetExt.cs +++ b/Oxide.Ext.Discord/Extensions/DateTimeOffsetExt.cs @@ -2,32 +2,31 @@ using System.Threading; using System.Threading.Tasks; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// Extensions +/// +public static class DateTimeOffsetExt { /// - /// Extensions + /// Delay until the DateTimeOffset with 25ms - 40 padding /// - public static class DateTimeOffsetExt - { - /// - /// Delay until the DateTimeOffset with 25ms - 40 padding - /// - /// - /// - /// - public static ValueTask DelayUntil(this DateTimeOffset time, CancellationToken token = default(CancellationToken)) => time.DelayUntil(Core.Random.Range(25, 40), token); + /// + /// + /// + public static ValueTask DelayUntil(this DateTimeOffset time, CancellationToken token = default) => time.DelayUntil(Core.Random.Range(25, 40), token); - /// - /// Delay until the DateTimeOffset with additionalMs padding - /// - /// Time to wait until - /// Additional millisecond padding - /// Cancellation Token - /// - public static async ValueTask DelayUntil(this DateTimeOffset time, int additionalMs, CancellationToken token = default(CancellationToken)) - { - TimeSpan duration = time >= DateTimeOffset.UtcNow ? time - DateTimeOffset.UtcNow : TimeSpan.Zero; - await Task.Delay(duration + TimeSpan.FromMilliseconds(additionalMs), token).ConfigureAwait(false); - } + /// + /// Delay until the DateTimeOffset with additionalMs padding + /// + /// Time to wait until + /// Additional millisecond padding + /// Cancellation Token + /// + public static async ValueTask DelayUntil(this DateTimeOffset time, int additionalMs, CancellationToken token = default) + { + TimeSpan duration = time >= DateTimeOffset.UtcNow ? time - DateTimeOffset.UtcNow : TimeSpan.Zero; + await Task.Delay(duration + TimeSpan.FromMilliseconds(additionalMs), token).ConfigureAwait(false); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/DiscordUserExt.cs b/Oxide.Ext.Discord/Extensions/DiscordUserExt.cs index 3ddd21c72..f8583cbe8 100644 --- a/Oxide.Ext.Discord/Extensions/DiscordUserExt.cs +++ b/Oxide.Ext.Discord/Extensions/DiscordUserExt.cs @@ -2,63 +2,62 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// Adds extension methods to Discord User to allow sending server chat commands to the player +/// +public static class DiscordUserExt { /// - /// Adds extension methods to Discord User to allow sending server chat commands to the player + /// Send a chat message to the user if they're connected /// - public static class DiscordUserExt + /// User to send the message to on the server + /// Message to send + public static void SendChatMessage(this DiscordUser user, string message) { - /// - /// Send chat message to the user if they're connected - /// - /// User to send the message to on the server - /// Message to send - public static void SendChatMessage(this DiscordUser user, string message) + IPlayer player = user.Player; + if (player is {IsConnected: true}) { - IPlayer player = user.Player; - if (player != null && player.IsConnected) - { - player.Message(message); - } + player.Message(message); } + } - /// - /// Send chat message to the user if they're connected - /// - /// User to send the message to on the server - /// Message to send - /// Message Prefix - /// Message Args - public static void SendChatMessage(this DiscordUser user, string message, string prefix, params object[] args) + /// + /// Send a chat message to the user if they're connected + /// + /// User to send the message to on the server + /// Message to send + /// Message Prefix + /// Message Args + public static void SendChatMessage(this DiscordUser user, string message, string prefix, params object[] args) + { + IPlayer player = user.Player; + if (player is {IsConnected: true}) { - IPlayer player = user.Player; - if (player != null && player.IsConnected) - { - player.Message(message, prefix, args); - } + player.Message(message, prefix, args); } + } - /// - /// Return if the discord user has the given oxide permission. - /// If the user is not linked this will return false - /// - /// User to check for permission - /// Permission to check for - /// True if use is linked and has permission; False otherwise - public static bool HasPermission(this DiscordUser user, string permission) - { - return user.Player?.HasPermission(permission) ?? false; - } + /// + /// Return if the discord user has the given oxide permission. + /// If the user is not linked, this will return false + /// + /// User to check for permission + /// Permission to check for + /// True if use is linked and has permission; False otherwise + public static bool HasPermission(this DiscordUser user, string permission) + { + return user.Player?.HasPermission(permission) ?? false; + } - /// - /// Returns true if the player is linked - /// - /// Discord user to check if they're linked - /// True if linked; False otherwise - public static bool IsLinked(this DiscordUser user) - { - return DiscordLink.Instance.IsLinked(user.Id); - } + /// + /// Returns true if the player is linked + /// + /// Discord user to check if they're linked + /// True if linked; False otherwise + public static bool IsLinked(this DiscordUser user) + { + return DiscordLink.Instance.IsLinked(user.Id); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/HashExt.cs b/Oxide.Ext.Discord/Extensions/HashExt.cs index 2c3f13b97..35369d39d 100644 --- a/Oxide.Ext.Discord/Extensions/HashExt.cs +++ b/Oxide.Ext.Discord/Extensions/HashExt.cs @@ -3,91 +3,90 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// Hash extensions +/// +public static class HashExt { /// - /// Hash extensions + /// Remove all records from the hash with the given predicate filter /// - public static class HashExt + /// Hash to have data removed from + /// Filter of which values to remove + /// Key type of the hash + /// Value type of the hash + public static void RemoveAll(this IDictionary hash, Func, bool> predicate) { - /// - /// Remove all records from the hash with the given predicate filter - /// - /// Hash to have data removed from - /// Filter of which values to remove - /// Key type of the hash - /// Value type of the hash - public static void RemoveAll(this IDictionary hash, Func, bool> predicate) - { - if (hash == null) throw new ArgumentNullException(nameof(hash)); + if (hash == null) throw new ArgumentNullException(nameof(hash)); - List removeKeys = DiscordPool.Internal.GetList(); - foreach (KeyValuePair key in hash) + List removeKeys = DiscordPool.Internal.GetList(); + foreach (KeyValuePair key in hash) + { + if (predicate(key)) { - if (predicate(key)) - { - removeKeys.Add(key.Key); - } + removeKeys.Add(key.Key); } + } - foreach (TKey key in removeKeys) - { - hash.Remove(key); - } - - DiscordPool.Internal.FreeList(removeKeys); + foreach (TKey key in removeKeys) + { + hash.Remove(key); } + + DiscordPool.Internal.FreeList(removeKeys); + } - /// - /// Remove all records from the hash with the given predicate filter - /// - /// Hash to have data removed from - /// Filter of which values to remove - /// Action to call when an element is removed - /// Key type of the hash - /// Value type of the hash - public static void RemoveAll(this IDictionary hash, Func predicate, Action onRemove = null) - { - if (hash == null) throw new ArgumentNullException(nameof(hash)); - - List removeKeys = DiscordPool.Internal.GetList(); - foreach (KeyValuePair key in hash) - { - if (predicate(key.Value)) - { - removeKeys.Add(key.Key); - onRemove?.Invoke(key.Value); - } - } + /// + /// Remove all records from the hash with the given predicate filter + /// + /// Hash to have data removed from + /// Filter of which values to remove + /// Action to call when an element is removed + /// Key type of the hash + /// Value type of the hash + public static void RemoveAll(this IDictionary hash, Func predicate, Action onRemove = null) + { + if (hash == null) throw new ArgumentNullException(nameof(hash)); - foreach (TKey key in removeKeys) + List removeKeys = DiscordPool.Internal.GetList(); + foreach (KeyValuePair key in hash) + { + if (predicate(key.Value)) { - hash.Remove(key); + removeKeys.Add(key.Key); + onRemove?.Invoke(key.Value); } - - DiscordPool.Internal.FreeList(removeKeys); } - /// - /// Creates a clone of a hash with it's current key value pairs - /// - /// Hash to be copied - /// - /// - /// Copied Hash - internal static Hash Clone(this Hash hash) + foreach (TKey key in removeKeys) { - Hash copy = new Hash(); - CopyTo(hash, copy); - return copy; + hash.Remove(key); } + + DiscordPool.Internal.FreeList(removeKeys); + } + + /// + /// Creates a clone of a hash with its current key value pairs + /// + /// Hash to be copied + /// + /// + /// Copied Hash + internal static Hash Clone(this Hash hash) + { + Hash copy = new(); + CopyTo(hash, copy); + return copy; + } - internal static void CopyTo(this IDictionary hash, Hash target) + internal static void CopyTo(this IDictionary hash, Hash target) + { + foreach (KeyValuePair value in hash) { - foreach (KeyValuePair value in hash) - { - target[value.Key] = value.Value; - } + target[value.Key] = value.Value; } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/HttpResponseHeadersExt.cs b/Oxide.Ext.Discord/Extensions/HttpResponseHeadersExt.cs index 1f2d71917..ed0798619 100644 --- a/Oxide.Ext.Discord/Extensions/HttpResponseHeadersExt.cs +++ b/Oxide.Ext.Discord/Extensions/HttpResponseHeadersExt.cs @@ -3,64 +3,63 @@ using System.Net.Http.Headers; using Oxide.Ext.Discord.Rest; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +internal static class HttpResponseHeadersExt { - internal static class HttpResponseHeadersExt + internal static string Get(this HttpResponseHeaders headers, string key) { - internal static string Get(this HttpResponseHeaders headers, string key) - { - return headers.TryGetValues(key, out IEnumerable values) ? values.FirstOrDefault() : null; - } + return headers.TryGetValues(key, out IEnumerable values) ? values.FirstOrDefault() : null; + } - internal static bool GetBool(this HttpResponseHeaders headers, string key) + internal static bool GetBool(this HttpResponseHeaders headers, string key) + { + string value = headers.Get(key); + if (string.IsNullOrEmpty(value) || !bool.TryParse(value, out bool result)) { - string value = headers.Get(key); - if (string.IsNullOrEmpty(value) || !bool.TryParse(value, out bool result)) - { - return default(bool); - } - - return result; + return default; } + + return result; + } - internal static int GetInt(this HttpResponseHeaders headers, string key) + internal static int GetInt(this HttpResponseHeaders headers, string key) + { + string value = headers.Get(key); + if (string.IsNullOrEmpty(value) || !int.TryParse(value, out int result)) { - string value = headers.Get(key); - if (string.IsNullOrEmpty(value) || !int.TryParse(value, out int result)) - { - return default(int); - } - - return result; + return default; } - internal static bool TryGetInt(this HttpResponseHeaders headers, string key, out int value) - { - string headerValue = headers.Get(key); - if (string.IsNullOrEmpty(headerValue) || !int.TryParse(headerValue, out value)) - { - value = 0; - return false; - } + return result; + } - return true; - } - - internal static double GetDouble(this HttpResponseHeaders headers, string key) + internal static bool TryGetInt(this HttpResponseHeaders headers, string key, out int value) + { + string headerValue = headers.Get(key); + if (string.IsNullOrEmpty(headerValue) || !int.TryParse(headerValue, out value)) { - string value = headers.Get(key); - if (string.IsNullOrEmpty(value) || !double.TryParse(value, out double result)) - { - return default(double); - } - - return result; + value = 0; + return false; } + + return true; + } - internal static BucketId GetBucketId(this HttpResponseHeaders headers, string key) + internal static double GetDouble(this HttpResponseHeaders headers, string key) + { + string value = headers.Get(key); + if (string.IsNullOrEmpty(value) || !double.TryParse(value, out double result)) { - string value = headers.Get(key); - return !string.IsNullOrEmpty(value) ? new BucketId(value) : default(BucketId); + return default; } + + return result; + } + + internal static BucketId GetBucketId(this HttpResponseHeaders headers, string key) + { + string value = headers.Get(key); + return !string.IsNullOrEmpty(value) ? new BucketId(value) : default; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/IEnumerableExt.cs b/Oxide.Ext.Discord/Extensions/IEnumerableExt.cs index 9eb184a90..8657b2ad8 100644 --- a/Oxide.Ext.Discord/Extensions/IEnumerableExt.cs +++ b/Oxide.Ext.Discord/Extensions/IEnumerableExt.cs @@ -3,82 +3,81 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// Represents Extension to IEnumerable +/// +// ReSharper disable once InconsistentNaming +public static class IEnumerableExt { /// - /// Represents Extension to IEnumerable + /// Converts an IEnumerable{TSource} to a pooled List /// - // ReSharper disable once InconsistentNaming - public static class IEnumerableExt + /// IEnumerable to convert + /// The to pool from + /// Type of the list + /// Pooled List{TSource} + /// Thrown if the source is null + public static List ToPooledList(this IEnumerable source, DiscordPluginPool pluginPool) { - /// - /// Converts an IEnumerable{TSource} to a pooled List - /// - /// IEnumerable to convert - /// The to pool from - /// Type of the list - /// Pooled List{TSource} - /// Thrown if source is null - public static List ToPooledList(this IEnumerable source, DiscordPluginPool pluginPool) - { - if (source == null) throw new ArgumentNullException(nameof(source)); + if (source == null) throw new ArgumentNullException(nameof(source)); - List list = pluginPool.GetList(); - list.AddRange(source); - return list; - } + List list = pluginPool.GetList(); + list.AddRange(source); + return list; + } - /// - /// Converts an IEnumerable{TSource} to a Hash{TKey, TElement} - /// - /// IEnumerable to convert - /// Selector for the key - /// Selector for the value - /// Type of the source - /// Key type for the hash - /// Value type for the hash - /// Pooled Hash{TKey, TElement} - /// Thrown if source is null - public static Hash ToHash(this IEnumerable source, Func keySelector, Func elementSelector) - { - if (source == null) throw new ArgumentNullException(nameof(source)); - if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); - if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector)); - - Hash hash = new Hash(); - foreach (TSource element in source) - { - hash.Add(keySelector(element), elementSelector(element)); - } + /// + /// Converts an IEnumerable{TSource} to a Hash{TKey, TElement} + /// + /// IEnumerable to convert + /// Selector for the key + /// Selector for the value + /// Type of the source + /// Key type for the hash + /// Value type for the hash + /// Pooled Hash{TKey, TElement} + /// Thrown if the source is null + public static Hash ToHash(this IEnumerable source, Func keySelector, Func elementSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); + if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector)); - return hash; + Hash hash = new(); + foreach (TSource element in source) + { + hash.Add(keySelector(element), elementSelector(element)); } + + return hash; + } - /// - /// Converts an IEnumerable{TSource} to a pooled Hash{TKey, TElement} - /// - /// IEnumerable to convert - /// The to pool from - /// Selector for the key - /// Selector for the value - /// Type of the source - /// Key type for the hash - /// Value type for the hash - /// Pooled Hash{TKey, TElement} - /// Thrown if source is null - public static Hash ToPooledHash(this IEnumerable source, DiscordPluginPool pluginPool, Func keySelector, Func elementSelector) - { - if (source == null) throw new ArgumentNullException(nameof(source)); - if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); - if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector)); + /// + /// Converts an IEnumerable{TSource} to a pooled Hash{TKey, TElement} + /// + /// IEnumerable to convert + /// The to pool from + /// Selector for the key + /// Selector for the value + /// Type of the source + /// Key type for the hash + /// Value type for the hash + /// Pooled Hash{TKey, TElement} + /// Thrown if the source is null + public static Hash ToPooledHash(this IEnumerable source, DiscordPluginPool pluginPool, Func keySelector, Func elementSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); + if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector)); - Hash hash = pluginPool.GetHash(); - foreach (TSource element in source) - { - hash.Add(keySelector(element), elementSelector(element)); - } - - return hash; + Hash hash = pluginPool.GetHash(); + foreach (TSource element in source) + { + hash.Add(keySelector(element), elementSelector(element)); } + + return hash; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/MathExt.cs b/Oxide.Ext.Discord/Extensions/MathExt.cs index ce2656282..e3cb635bc 100644 --- a/Oxide.Ext.Discord/Extensions/MathExt.cs +++ b/Oxide.Ext.Discord/Extensions/MathExt.cs @@ -1,49 +1,48 @@ using System; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// Extensions for math operations +/// +public static class MathExt { /// - /// Extensions for math operations + /// Returns the value of {T} clamped between min and max value /// - public static class MathExt + /// Value to be clamped + /// Min value + /// Max Value + /// Type to be clamped + /// Value of {T} clamped between min and max + public static T Clamp(this T val, T min, T max) where T : IComparable { - /// - /// Returns the value of {T} clamped between min and max value - /// - /// Value to be clamped - /// Min value - /// Max Value - /// Type to be clamped - /// Value of {T} clamped between min and max - public static T Clamp(this T val, T min, T max) where T : IComparable - { - if (val.CompareTo(min) < 0) return min; - if (val.CompareTo(max) > 0) return max; - return val; - } + if (val.CompareTo(min) < 0) return min; + if (val.CompareTo(max) > 0) return max; + return val; + } - /// - /// Returns the min value between left and right - /// - /// Left argument - /// Right argument - /// Type of IComparable{T} - /// Left if less than or equal to right else right - public static T Min(T left, T right) where T : IComparable - { - return left.CompareTo(right) > 0 ? right : left; - } + /// + /// Returns the min value between left and right + /// + /// Left argument + /// Right argument + /// Type of IComparable{T} + /// Left if less than or equal to right else right + public static T Min(T left, T right) where T : IComparable + { + return left.CompareTo(right) > 0 ? right : left; + } - /// - /// Returns the Max value between left and right - /// - /// Left argument - /// Right argument - /// Type of IComparable{T} - /// Left if greater than or equal to right else right - public static T Max(T left, T right) where T : IComparable - { - return left.CompareTo(right) < 0 ? right : left; - } + /// + /// Returns the Max value between left and right + /// + /// Left argument + /// Right argument + /// Type of IComparable{T} + /// Left if greater than or equal to right else right + public static T Max(T left, T right) where T : IComparable + { + return left.CompareTo(right) < 0 ? right : left; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/MemberInfoExt.cs b/Oxide.Ext.Discord/Extensions/MemberInfoExt.cs index e53d35adf..5104cfc44 100644 --- a/Oxide.Ext.Discord/Extensions/MemberInfoExt.cs +++ b/Oxide.Ext.Discord/Extensions/MemberInfoExt.cs @@ -1,28 +1,27 @@ using System; using System.Reflection; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +internal static class MemberInfoExt { - internal static class MemberInfoExt + internal static void SetMemberValue(this MemberInfo info, object instance, object value) { - internal static void SetMemberValue(this MemberInfo info, object instance, object value) + switch (info.MemberType) { - switch (info.MemberType) - { - case MemberTypes.Field: - ((FieldInfo)info).SetValue(instance, value); + case MemberTypes.Field: + ((FieldInfo)info).SetValue(instance, value); + break; + case MemberTypes.Property: + PropertyInfo property = ((PropertyInfo)info); + if (property.CanWrite) + { + ((PropertyInfo)info).SetValue(instance, value); break; - case MemberTypes.Property: - PropertyInfo property = ((PropertyInfo)info); - if (property.CanWrite) - { - ((PropertyInfo)info).SetValue(instance, value); - break; - } - throw new Exception($"{property.DeclaringType?.Name}.{property.Name} does not support writing"); - default: - throw new Exception("Invalid Member Type. This method only supports MemberTypes.Field or MemberTypes.Property"); - } + } + throw new Exception($"{property.DeclaringType?.Name}.{property.Name} does not support writing"); + default: + throw new Exception("Invalid Member Type. This method only supports MemberTypes.Field or MemberTypes.Property"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/MethodInfoExt.cs b/Oxide.Ext.Discord/Extensions/MethodInfoExt.cs index 8704e67da..9f3db1093 100644 --- a/Oxide.Ext.Discord/Extensions/MethodInfoExt.cs +++ b/Oxide.Ext.Discord/Extensions/MethodInfoExt.cs @@ -1,106 +1,104 @@ using System; using System.Reflection; -using System.Text; -using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Logging; +using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +internal static class MethodInfoExt { - internal static class MethodInfoExt + public static Action CreateDelegate(this MethodInfo methodInfo, object target) { - public static Action CreateDelegate(this MethodInfo methodInfo, object target) + try { - try - { - return (Action)Delegate.CreateDelegate(typeof(Action), target, methodInfo); - } - catch (Exception ex) - { - HandleException(ex, methodInfo, target); - return null; - } + return (Action)Delegate.CreateDelegate(typeof(Action), target, methodInfo); } + catch (Exception ex) + { + HandleException(ex, methodInfo, target); + return null; + } + } - public static Action CreateDelegate(this MethodInfo methodInfo, object target) + public static Action CreateDelegate(this MethodInfo methodInfo, object target) + { + try { - try - { - return (Action)Delegate.CreateDelegate(typeof(Action), target, methodInfo); - } - catch (Exception ex) - { - HandleException(ex, methodInfo, target); - return null; - } + return (Action)Delegate.CreateDelegate(typeof(Action), target, methodInfo); + } + catch (Exception ex) + { + HandleException(ex, methodInfo, target); + return null; } + } - public static Action CreateDelegate(this MethodInfo methodInfo, object target) + public static Action CreateDelegate(this MethodInfo methodInfo, object target) + { + try { - try - { - return (Action)Delegate.CreateDelegate(typeof(Action), target, methodInfo); - } - catch (Exception ex) - { - HandleException(ex, methodInfo, target, typeof(T1), typeof(T2)); - return null; - } + return (Action)Delegate.CreateDelegate(typeof(Action), target, methodInfo); } - - private static void HandleException(Exception ex, MethodInfo methodInfo, object target, params Type[] types) + catch (Exception ex) { - string expected = BuildExpected(methodInfo, types); - string actual = BuildActual(methodInfo); - DiscordExtension.GlobalLogger.Exception("Failed to create delegate for Plugin: {0} Method: {1} Expected: {2} Actual: {3}", target.GetType().GetRealTypeName(), methodInfo.Name, expected, actual, ex); + HandleException(ex, methodInfo, target, typeof(T1), typeof(T2)); + return null; } + } + + private static void HandleException(Exception ex, MethodInfo methodInfo, object target, params Type[] types) + { + string expected = BuildExpected(methodInfo, types); + string actual = BuildActual(methodInfo); + DiscordExtension.GlobalLogger.Exception("Failed to create delegate for Plugin: {0} Method: {1} Expected: {2} Actual: {3}", target.GetType().GetRealTypeName(), methodInfo.Name, expected, actual, ex); + } - private static string BuildExpected(MethodInfo methodInfo, params Type[] types) + private static string BuildExpected(MethodInfo methodInfo, params Type[] types) + { + ValueStringBuilder sb = new(); + sb.Append("void "); + sb.Append(methodInfo.Name); + sb.Append('('); + for (int index = 0; index < types.Length; index++) { - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); - sb.Append("void "); - sb.Append(methodInfo.Name); - sb.Append('('); - for (int index = 0; index < types.Length; index++) + Type type = types[index]; + if (index != 0) { - Type type = types[index]; - if (index != 0) - { - sb.Append(", "); - } - - sb.Append(type.Name); - sb.Append(" t"); - sb.Append(index); + sb.Append(", "); } - sb.Append(')'); - return DiscordPool.Internal.ToStringAndFree(sb); - } + + sb.Append(type.Name); + sb.Append(" t"); + sb.Append(index); + } + sb.Append(')'); + return sb.ToString(); + } - private static string BuildActual(MethodInfo info) - { - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); - sb.Append(info.ReturnType.Name); - sb.Append(' '); - sb.Append(info.Name); - sb.Append('('); + private static string BuildActual(MethodInfo info) + { + ValueStringBuilder sb = new(); + sb.Append(info.ReturnType.Name); + sb.Append(' '); + sb.Append(info.Name); + sb.Append('('); - ParameterInfo[] parameters = info.GetParameters(); - for (int index = 0; index < parameters.Length; index++) + ParameterInfo[] parameters = info.GetParameters(); + for (int index = 0; index < parameters.Length; index++) + { + ParameterInfo parameter = parameters[index]; + if (index != 0) { - ParameterInfo parameter = parameters[index]; - if (index != 0) - { - sb.Append(", "); - } - - sb.Append(parameter.ParameterType.Name); - sb.Append(' '); - sb.Append(parameter.Name); + sb.Append(", "); } - sb.Append(')'); - - return DiscordPool.Internal.ToStringAndFree(sb); + sb.Append(parameter.ParameterType.Name); + sb.Append(' '); + sb.Append(parameter.Name); } + + sb.Append(')'); + + return sb.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/PlayerExt.cs b/Oxide.Ext.Discord/Extensions/PlayerExt.cs index 0d1a5b3bd..64febe598 100644 --- a/Oxide.Ext.Discord/Extensions/PlayerExt.cs +++ b/Oxide.Ext.Discord/Extensions/PlayerExt.cs @@ -9,172 +9,171 @@ using Oxide.Ext.Discord.Plugins; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// IPlayer Extensions for sending Discord Message to an IPlayer +/// +public static class PlayerExt { /// - /// IPlayer Extensions for sending Discord Message to an IPlayer + /// Send a Discord Message to an IPlayer if they're registered /// - public static class PlayerExt + /// Player to send the discord message to + /// Client to use for sending the message + /// Message to send + public static IPromise SendDiscordMessage(this IPlayer player, DiscordClient client, string message) { - /// - /// Send a Discord Message to an IPlayer if they're registered - /// - /// Player to send the discord message to - /// Client to use for sending the message - /// Message to send - public static IPromise SendDiscordMessage(this IPlayer player, DiscordClient client, string message) + MessageCreate create = new() { - MessageCreate create = new MessageCreate - { - Content = message - }; + Content = message + }; - return player.SendDiscordMessage(client, create); - } + return player.SendDiscordMessage(client, create); + } - /// - /// Send a Discord Message to an IPlayer if they're registered - /// - /// Player to send the discord message to - /// Client to use for sending the message - /// Embed to send - public static IPromise SendDiscordMessage(this IPlayer player, DiscordClient client, DiscordEmbed embed) + /// + /// Send a Discord Message to an IPlayer if they're registered + /// + /// Player to send the discord message to + /// Client to use for sending the message + /// Embed to send + public static IPromise SendDiscordMessage(this IPlayer player, DiscordClient client, DiscordEmbed embed) + { + MessageCreate create = new() { - MessageCreate create = new MessageCreate - { - Embeds = new List {embed} - }; + Embeds = [embed] + }; - return player.SendDiscordMessage(client, create); - } + return player.SendDiscordMessage(client, create); + } - /// - /// Send a Discord Message to an IPlayer if they're registered - /// - /// Player to send the discord message to - /// Client to use for sending the message - /// Embeds to send - public static IPromise SendDiscordMessage(this IPlayer player, DiscordClient client, List embeds) + /// + /// Send a Discord Message to an IPlayer if they're registered + /// + /// Player to send the discord message to + /// Client to use for sending the message + /// Embeds to send + public static IPromise SendDiscordMessage(this IPlayer player, DiscordClient client, List embeds) + { + MessageCreate create = new() { - MessageCreate create = new MessageCreate - { - Embeds = embeds - }; + Embeds = embeds + }; - return player.SendDiscordMessage(client, create); - } + return player.SendDiscordMessage(client, create); + } - /// - /// Send a Discord Message to an IPlayer if they're registered - /// - /// Player to send the discord message to - /// Client to use for sending the message - /// Message to send - public static IPromise SendDiscordMessage(this IPlayer player, DiscordClient client, MessageCreate message) - { - return SendMessage(client, player.GetDiscordUserId(), message); - } + /// + /// Send a Discord Message to an IPlayer if they're registered + /// + /// Player to send the discord message to + /// Client to use for sending the message + /// Message to send + public static IPromise SendDiscordMessage(this IPlayer player, DiscordClient client, MessageCreate message) + { + return SendMessage(client, player.GetDiscordUserId(), message); + } - /// - /// Send a message in a DM to the linked user using a global message template - /// - /// Player to send the message to - /// Client to use - /// Template Name - /// Message to use (optional) - /// Placeholders to apply (optional) - public static IPromise SendDiscordGlobalTemplateMessage(this IPlayer player, DiscordClient client, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) - { - MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetPlayerTemplate(client.Plugin, templateName, player).ToMessage(placeholders, message); - return SendMessage(client, player.GetDiscordUserId(), template); - } + /// + /// Send a message in a DM to the linked user using a global message template + /// + /// Player to send the message to + /// Client to use + /// Template Name + /// Message to use (optional) + /// Placeholders to apply (optional) + public static IPromise SendDiscordGlobalTemplateMessage(this IPlayer player, DiscordClient client, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) + { + MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetPlayerTemplate(client.Plugin, templateName, player).ToMessage(placeholders, message); + return SendMessage(client, player.GetDiscordUserId(), template); + } - /// - /// Send a message in a DM to the linked user using a localized message template - /// - /// Player to send the message to - /// Client to use - /// Template Name - /// Message to use (optional) - /// Placeholders to apply (optional) - public static IPromise SendDiscordTemplateMessage(this IPlayer player, DiscordClient client, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) - { - MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetPlayerTemplate(client.Plugin, templateName, player).ToMessage(placeholders, message); - return SendMessage(client, player.GetDiscordUserId(), template); - } + /// + /// Send a message in a DM to the linked user using a localized message template + /// + /// Player to send the message to + /// Client to use + /// Template Name + /// Message to use (optional) + /// Placeholders to apply (optional) + public static IPromise SendDiscordTemplateMessage(this IPlayer player, DiscordClient client, TemplateKey templateName, MessageCreate message = null, PlaceholderData placeholders = null) + { + MessageCreate template = DiscordExtension.DiscordMessageTemplates.GetPlayerTemplate(client.Plugin, templateName, player).ToMessage(placeholders, message); + return SendMessage(client, player.GetDiscordUserId(), template); + } - private static IPromise SendMessage(DiscordClient client, Snowflake? id, MessageCreate message) + private static IPromise SendMessage(DiscordClient client, Snowflake? id, MessageCreate message) + { + if (!client.IsConnected()) { - if (!client.IsConnected()) - { - return Promise.Rejected(DiscordClientException.NotConnected()); - } + return Promise.Rejected(DiscordClientException.NotConnected()); + } - if (!id.HasValue) - { - return Promise.Rejected(InvalidSnowflakeException.InvalidException(nameof(id))); - } + if (!id.HasValue) + { + return Promise.Rejected(InvalidSnowflakeException.InvalidException(nameof(id))); + } - DiscordChannel channel = client.Bot.DirectMessagesByUserId[id.Value]; - if (channel != null) - { - return channel.CreateMessage(client, message); - } - - DiscordUser user = EntityCache.Instance.GetOrCreate(id.Value); - return user.SendDirectMessage(client, message); + DiscordChannel channel = client.Bot.DirectMessagesByUserId[id.Value]; + if (channel != null) + { + return channel.CreateMessage(client, message); } - /// - /// Returns true if the player is linked - /// - /// Player to check if they're linked - /// True if linked; False otherwise - public static bool IsLinked(this IPlayer player) => player != null && DiscordLink.Instance.IsLinked(player.Id); + DiscordUser user = EntityCache.Instance.GetOrCreate(id.Value); + return user.SendDirectMessage(client, message); + } - /// - /// Returns the Discord ID of the IPlayer if linked - /// - /// Player to get Discord ID for - /// Discord ID if linked; null otherwise - public static Snowflake GetDiscordUserId(this IPlayer player) => player != null ? DiscordLink.Instance.GetDiscordId(player) : default(Snowflake); + /// + /// Returns true if the player is linked + /// + /// Player to check if they're linked + /// True if linked; False otherwise + public static bool IsLinked(this IPlayer player) => player != null && DiscordLink.Instance.IsLinked(player.Id); - /// - /// Returns a minimal Discord User for the given player - /// - /// Player to get Discord User for - /// Discord User if linked; null otherwise - public static DiscordUser GetDiscordUser(this IPlayer player) => player != null ? DiscordLink.Instance.GetDiscordUser(player) : null; + /// + /// Returns the Discord ID of the IPlayer if linked + /// + /// Player to get Discord ID for + /// Discord ID if linked; null otherwise + public static Snowflake GetDiscordUserId(this IPlayer player) => player != null ? DiscordLink.Instance.GetDiscordId(player) : default; - /// - /// Returns a minimal Guild Member for the given player - /// - /// Player to get Discord User for - /// Guild the member is in - /// GuildMember if linked and in guild; null otherwise - public static GuildMember GetGuildMember(this IPlayer player, DiscordGuild guild) => player != null ? DiscordLink.Instance.GetLinkedMember(player, guild) : null; + /// + /// Returns a minimal Discord User for the given player + /// + /// Player to get Discord User for + /// Discord User if linked; null otherwise + public static DiscordUser GetDiscordUser(this IPlayer player) => player != null ? DiscordLink.Instance.GetDiscordUser(player) : null; - /// - /// Returns the PlayerId for a given - /// - /// - /// - public static PlayerId PlayerId(this IPlayer player) => player != null ? new PlayerId(player.Id) : default(PlayerId); + /// + /// Returns a minimal Guild Member for the given player + /// + /// Player to get Discord User for + /// Guild the member is in + /// GuildMember if linked and in guild; null otherwise + public static GuildMember GetGuildMember(this IPlayer player, DiscordGuild guild) => player != null ? DiscordLink.Instance.GetLinkedMember(player, guild) : null; + + /// + /// Returns the PlayerId for a given + /// + /// + /// + public static PlayerId PlayerId(this IPlayer player) => player != null ? new PlayerId(player.Id) : default; - /// - /// Returns if the IPlayer is a - /// - /// - /// - public static bool IsDummyPlayer(this IPlayer player) => player is DiscordDummyPlayer; + /// + /// Returns if the IPlayer is a + /// + /// + /// + public static bool IsDummyPlayer(this IPlayer player) => player is DiscordDummyPlayer; - /// - /// Allows plugins to create dummy IPlayers - /// - /// ID of the player - /// Name of the player - /// IP of the player - /// - public static IPlayer CreateDummyPlayer(string id, string name, string ip) => new DiscordDummyPlayer(id, name, ip); - } + /// + /// Allows plugins to create dummy IPlayers + /// + /// ID of the player + /// Name of the player + /// IP of the player + /// + public static IPlayer CreateDummyPlayer(string id, string name, string ip) => new DiscordDummyPlayer(id, name, ip); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/PluginExt.cs b/Oxide.Ext.Discord/Extensions/PluginExt.cs index 64a0e0fb1..b1281d152 100644 --- a/Oxide.Ext.Discord/Extensions/PluginExt.cs +++ b/Oxide.Ext.Discord/Extensions/PluginExt.cs @@ -5,86 +5,85 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// Extension methods for plugins +/// +internal static class PluginExt { - /// - /// Extension methods for plugins - /// - internal static class PluginExt - { - private static readonly Hash FullNameCache = new Hash(); - private static readonly BidirectionalDictionary PluginIds = new BidirectionalDictionary(); + private static readonly Hash FullNameCache = new(); + private static readonly BidirectionalDictionary PluginIds = new(); - internal static PluginId Id(this Plugin plugin) + internal static PluginId Id(this Plugin plugin) + { + if (PluginIds.TryGetValue(plugin, out PluginId id)) { - if (PluginIds.TryGetValue(plugin, out PluginId id)) - { - return id; - } - - id = new PluginId(plugin); - PluginIds[plugin] = id; return id; } - // ReSharper disable once SuspiciousTypeConversion.Global - internal static PluginId Id(this IPluginBase plugin) => ((Plugin)plugin).Id(); + id = new PluginId(plugin); + PluginIds[plugin] = id; + return id; + } - internal static string PluginName(this Plugin plugin) => plugin?.Name ?? throw new ArgumentNullException(nameof(plugin)); - internal static string PluginName(this PluginId pluginId) - { - if (pluginId.IsValid && PluginIds.TryGetValue(pluginId, out Plugin plugin)) - { - return plugin.Name; - } - - return $"Invalid Plugin ID: {pluginId.Id}"; - } + // ReSharper disable once SuspiciousTypeConversion.Global + internal static PluginId Id(this IPluginBase plugin) => ((Plugin)plugin).Id(); - internal static string FullName(this Plugin plugin) + internal static string PluginName(this Plugin plugin) => plugin?.Name ?? throw new ArgumentNullException(nameof(plugin)); + internal static string PluginName(this PluginId pluginId) + { + if (pluginId.IsValid && PluginIds.TryGetValue(pluginId, out Plugin plugin)) { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - PluginId pluginId = plugin.Id(); - string name = FullNameCache[pluginId]; - if (name == null) - { - name = CreatePluginFullName(plugin); - FullNameCache[pluginId] = name; - } - - return name; + return plugin.Name; } - - internal static string FullName(this PluginId pluginId) - { - if (pluginId.IsValid && PluginIds.TryGetValue(pluginId, out Plugin plugin)) - { - return plugin.FullName(); - } - return $"Invalid Plugin ID: {pluginId.Id}"; - } + return $"Invalid Plugin ID: {pluginId.Id}"; + } - internal static string GetFullName(PluginId pluginId) + internal static string FullName(this Plugin plugin) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + PluginId pluginId = plugin.Id(); + string name = FullNameCache[pluginId]; + if (name == null) { - if (pluginId.IsValid && PluginIds.TryGetValue(pluginId, out Plugin plugin)) - { - return plugin.FullName(); - } - - return $"Invalid Plugin ID: {pluginId.Id}"; + name = CreatePluginFullName(plugin); + FullNameCache[pluginId] = name; } - internal static void OnPluginLoaded(Plugin plugin) + return name; + } + + internal static string FullName(this PluginId pluginId) + { + if (pluginId.IsValid && PluginIds.TryGetValue(pluginId, out Plugin plugin)) { - FullNameCache[plugin.Id()] = CreatePluginFullName(plugin); + return plugin.FullName(); } + + return $"Invalid Plugin ID: {pluginId.Id}"; + } - internal static void OnPluginUnloaded(Plugin plugin) + internal static string GetFullName(PluginId pluginId) + { + if (pluginId.IsValid && PluginIds.TryGetValue(pluginId, out Plugin plugin)) { - FullNameCache.Remove(plugin.Id()); + return plugin.FullName(); } - private static string CreatePluginFullName(Plugin plugin) => $"{plugin.Name} by {plugin.Author} v{plugin.Version}"; + return $"Invalid Plugin ID: {pluginId.Id}"; } + + internal static void OnPluginLoaded(Plugin plugin) + { + FullNameCache[plugin.Id()] = CreatePluginFullName(plugin); + } + + internal static void OnPluginUnloaded(Plugin plugin) + { + FullNameCache.Remove(plugin.Id()); + } + + private static string CreatePluginFullName(Plugin plugin) => $"{plugin.Name} by {plugin.Author} v{plugin.Version}"; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/SpanExt.cs b/Oxide.Ext.Discord/Extensions/SpanExt.cs index b080c0e80..1c5c8481d 100644 --- a/Oxide.Ext.Discord/Extensions/SpanExt.cs +++ b/Oxide.Ext.Discord/Extensions/SpanExt.cs @@ -1,40 +1,39 @@ using System; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// Extension Methods +/// +public static class SpanExt { /// - /// Extension Methods + /// Parses the next string from the input splitting on the token /// - public static class SpanExt + /// Input string + /// Token to split on + /// Remaining text of the span + /// The parsed string + /// True if successfully parsed; false otherwise + public static bool TryParseNextString(this ReadOnlySpan input, ReadOnlySpan token, out ReadOnlySpan remaining, out ReadOnlySpan parsed) { - /// - /// Parses the next string from the input splitting on the token - /// - /// Input string - /// Token to split on - /// Remaining text of the span - /// The parsed string - /// True if successfully parsed; false otherwise - public static bool TryParseNextString(this ReadOnlySpan input, ReadOnlySpan token, out ReadOnlySpan remaining, out ReadOnlySpan parsed) + if (input.Length == 0) { - if (input.Length == 0) - { - remaining = ReadOnlySpan.Empty; - parsed = ReadOnlySpan.Empty; - return false; - } - - int end = input.IndexOf(token); - if (end == -1) - { - remaining = ReadOnlySpan.Empty; - parsed = input; - return true; - } + remaining = ReadOnlySpan.Empty; + parsed = ReadOnlySpan.Empty; + return false; + } - remaining = input.Slice(end + token.Length); - parsed = input.Slice(0, end); + int end = input.IndexOf(token); + if (end == -1) + { + remaining = ReadOnlySpan.Empty; + parsed = input; return true; } + + remaining = input.Slice(end + token.Length); + parsed = input.Slice(0, end); + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/StreamExt.cs b/Oxide.Ext.Discord/Extensions/StreamExt.cs index 3b0ae7378..746ebfa5b 100644 --- a/Oxide.Ext.Discord/Extensions/StreamExt.cs +++ b/Oxide.Ext.Discord/Extensions/StreamExt.cs @@ -1,30 +1,29 @@ using System.Buffers; using System.IO; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// Stream Extension Methods +/// +public static class StreamExt { /// - /// Stream Extension Methods + /// Copies one stream to another using a pooled byte[] buffer /// - public static class StreamExt + /// Stream to copy from + /// Stream to copy to + public static void CopyToPooled(this Stream from, Stream to) { - /// - /// Copies one stream to another using a pooled byte[] buffer - /// - /// Stream to copy from - /// Stream to copy to - public static void CopyToPooled(this Stream from, Stream to) - { - from.Position = 0; - byte[] buffer = ArrayPool.Shared.Rent(1024); - - int bytesRead; - while ((bytesRead = from.Read(buffer, 0, buffer.Length)) != 0) - { - to.Write(buffer, 0, bytesRead); - } + from.Position = 0; + byte[] buffer = ArrayPool.Shared.Rent(1024); - ArrayPool.Shared.Return(buffer); + int bytesRead; + while ((bytesRead = from.Read(buffer, 0, buffer.Length)) != 0) + { + to.Write(buffer, 0, bytesRead); } + + ArrayPool.Shared.Return(buffer); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/StringBuilderExt.cs b/Oxide.Ext.Discord/Extensions/StringBuilderExt.cs index b659b2c58..2706fd9a8 100644 --- a/Oxide.Ext.Discord/Extensions/StringBuilderExt.cs +++ b/Oxide.Ext.Discord/Extensions/StringBuilderExt.cs @@ -1,65 +1,64 @@ using System; using System.Runtime.CompilerServices; using System.Text; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// StringBuilder extension methods +/// +public static class StringBuilderExt { /// - /// StringBuilder extension methods + /// Replaces the text at the index and length with the span value /// - public static class StringBuilderExt + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Replace(this StringBuilder builder, ReadOnlySpan value, int index, int length) { - /// - /// Replaces the text at the index and length with the span value - /// - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Replace(this StringBuilder builder, ReadOnlySpan value, int index, int length) - { - builder.Remove(index, length); - builder.Insert(index, value); - } + builder.Remove(index, length); + builder.Insert(index, value); + } - /// - /// Trim empty space to the left and right of the StringBuilder - /// - /// StringBuilder to trim - /// The passed in StringBuilder - public static StringBuilder Trim(this StringBuilder sb) - { - if (sb == null || sb.Length == 0) return sb; + /// + /// Trim empty space to the left and right of the StringBuilder + /// + /// StringBuilder to trim + /// The passed in StringBuilder + public static StringBuilder Trim(this StringBuilder sb) + { + if (sb == null || sb.Length == 0) return sb; - //Process Left Side - if (char.IsWhiteSpace(sb[0])) + //Process Left Side + if (char.IsWhiteSpace(sb[0])) + { + int index = 1; + while (index < sb.Length && char.IsWhiteSpace(sb[index])) { - int index = 1; - while (index < sb.Length && char.IsWhiteSpace(sb[index])) - { - index++; - } - - sb.Remove(0, index + 1); - if (sb.Length == 0) - { - return sb; - } + index++; } - //Process Right Side - if (char.IsWhiteSpace(sb[sb.Length - 1])) + sb.Remove(0, index + 1); + if (sb.Length == 0) { - int index = sb.Length - 2; - while (index >= 0 && char.IsWhiteSpace(sb[index])) - { - index--; - } - - sb.Length = index + 1; + return sb; } + } - return sb; + //Process Right Side + if (char.IsWhiteSpace(sb[sb.Length - 1])) + { + int index = sb.Length - 2; + while (index >= 0 && char.IsWhiteSpace(sb[index])) + { + index--; + } + + sb.Length = index + 1; } + + return sb; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/StringExt.cs b/Oxide.Ext.Discord/Extensions/StringExt.cs index b00ae9d14..c8cec549b 100644 --- a/Oxide.Ext.Discord/Extensions/StringExt.cs +++ b/Oxide.Ext.Discord/Extensions/StringExt.cs @@ -3,67 +3,51 @@ using System.Text; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// String Extension methods +/// +internal static class StringExt { - /// - /// String Extension methods - /// - internal static class StringExt + public static bool ParseBool(this string input, out bool value) { - public static bool ParseBool(this string input, out bool value) + if (bool.TryParse(input, out value)) { - if (bool.TryParse(input, out value)) - { - return true; - } - - if (char.IsNumber(input[0])) - { - value = input[0] != '0'; - return true; - } + return true; + } - return false; + if (char.IsNumber(input[0])) + { + value = input[0] != '0'; + return true; } + + return false; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static string TrimIfLargerThan(this string str, int maxCharacters) => str.Length <= maxCharacters ? str : str.Substring(0, maxCharacters); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string TrimIfLargerThan(this string str, int maxCharacters) => str.Length <= maxCharacters ? str : str.Substring(0, maxCharacters); - /// - /// Parses the specified command into uMod command format - /// Sourced from CommandHandler.cs of uMod (https://gitlab.com/umod/core/core/-/blob/develop/src/Command/CommandHandler.cs) - /// - /// - /// - /// - public static void ParseCommand(this string argStr, out string command, out string[] args) - { - List argList = DiscordPool.Internal.GetList(); - StringBuilder stringBuilder = DiscordPool.Internal.GetStringBuilder(); - bool inLongArg = false; + /// + /// Parses the specified command into uMod command format + /// Sourced from CommandHandler.cs of uMod (https://gitlab.com/umod/core/core/-/blob/develop/src/Command/CommandHandler.cs) + /// + /// + /// + /// + public static void ParseCommand(this string argStr, out string command, out string[] args) + { + List argList = DiscordPool.Internal.GetList(); + StringBuilder stringBuilder = DiscordPool.Internal.GetStringBuilder(); + bool inLongArg = false; - for (int index = 0; index < argStr.Length; index++) + for (int index = 0; index < argStr.Length; index++) + { + char c = argStr[index]; + if (c == '"') { - char c = argStr[index]; - if (c == '"') - { - if (inLongArg) - { - string arg = stringBuilder.Trim().ToString(); - if (!string.IsNullOrEmpty(arg)) - { - argList.Add(arg); - } - - stringBuilder.Clear(); - inLongArg = false; - } - else - { - inLongArg = true; - } - } - else if (char.IsWhiteSpace(c) && !inLongArg) + if (inLongArg) { string arg = stringBuilder.Trim().ToString(); if (!string.IsNullOrEmpty(arg)) @@ -72,34 +56,49 @@ public static void ParseCommand(this string argStr, out string command, out stri } stringBuilder.Clear(); + inLongArg = false; } else { - stringBuilder.Append(c); + inLongArg = true; } } - - if (stringBuilder.Length > 0) + else if (char.IsWhiteSpace(c) && !inLongArg) { string arg = stringBuilder.Trim().ToString(); if (!string.IsNullOrEmpty(arg)) { argList.Add(arg); } + + stringBuilder.Clear(); + } + else + { + stringBuilder.Append(c); } + } - if (argList.Count == 0) + if (stringBuilder.Length > 0) + { + string arg = stringBuilder.Trim().ToString(); + if (!string.IsNullOrEmpty(arg)) { - command = null; - args = null; - return; + argList.Add(arg); } + } - command = argList[0].ToLower(); - argList.RemoveAt(0); - args = argList.ToArray(); - DiscordPool.Internal.FreeStringBuilder(stringBuilder); - DiscordPool.Internal.FreeList(argList); + if (argList.Count == 0) + { + command = null; + args = null; + return; } + + command = argList[0].ToLower(); + argList.RemoveAt(0); + args = argList.ToArray(); + DiscordPool.Internal.FreeStringBuilder(stringBuilder); + DiscordPool.Internal.FreeList(argList); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/ThreadEx.cs b/Oxide.Ext.Discord/Extensions/ThreadEx.cs index 20e463ff2..24fc8fd94 100644 --- a/Oxide.Ext.Discord/Extensions/ThreadEx.cs +++ b/Oxide.Ext.Discord/Extensions/ThreadEx.cs @@ -1,23 +1,22 @@ using System.Threading; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +internal static class ThreadEx { - internal static class ThreadEx - { - /// - /// Main thread - /// - private static readonly int MainThreadId = Thread.CurrentThread.ManagedThreadId; + /// + /// Main thread + /// + private static readonly int MainThreadId = Thread.CurrentThread.ManagedThreadId; - /// - /// Determine if current thread is main thread - /// - internal static bool IsMain => MainThreadId == Thread.CurrentThread.ManagedThreadId; + /// + /// Determine if current thread is the main thread + /// + internal static bool IsMain => MainThreadId == Thread.CurrentThread.ManagedThreadId; - internal static void Initialize() - { - DiscordExtension.GlobalLogger.Verbose("Main Thread ID: {0}", MainThreadId); - } + internal static void Initialize() + { + DiscordExtension.GlobalLogger.Verbose("Main Thread ID: {0}", MainThreadId); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Extensions/TypeExt.cs b/Oxide.Ext.Discord/Extensions/TypeExt.cs index c710e86ec..c7167a86b 100644 --- a/Oxide.Ext.Discord/Extensions/TypeExt.cs +++ b/Oxide.Ext.Discord/Extensions/TypeExt.cs @@ -1,68 +1,66 @@ using System; using System.Reflection; -using System.Text; -using Oxide.Ext.Discord.Libraries; +using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Extensions +namespace Oxide.Ext.Discord.Extensions; + +/// +/// Extensions for +/// +internal static class TypeExt { /// - /// Extensions for + /// Returns if the type is /// - internal static class TypeExt - { - /// - /// Returns if the type is - /// - /// Type to check - /// True if type is ; false otherwise - public static bool IsNullable(this Type objectType) => objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Nullable<>); + /// Type to check + /// True if type is ; false otherwise + public static bool IsNullable(this Type objectType) => objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Nullable<>); - /// - /// Returns if the type is - /// - /// Type to check - /// True if type is ; false otherwise - public static Type GetNullableType(this Type objectType) => Nullable.GetUnderlyingType(objectType); + /// + /// Returns if the type is + /// + /// Type to check + /// True if type is ; false otherwise + public static Type GetNullableType(this Type objectType) => Nullable.GetUnderlyingType(objectType); - /// - /// Returns if a type is a value type - /// - /// - /// - public static bool IsValueType(this Type source) => source.IsValueType; + /// + /// Returns if a type is a value type + /// + /// + /// + public static bool IsValueType(this Type source) => source.IsValueType; - /// - /// Returns the default value for - /// - /// Type to get default value for - /// default value for - public static object GetDefault(this Type type) => type.IsValueType ? Activator.CreateInstance(type) : null; + /// + /// Returns the default value for + /// + /// Type to get default value for + /// default value for + public static object GetDefault(this Type type) => type.IsValueType ? Activator.CreateInstance(type) : null; - internal static T GetAttribute(this Type type, bool inherit) where T : Attribute => type.GetCustomAttribute(typeof(T), inherit) as T; - internal static bool HasAttribute(this Type type, bool inherit) where T : Attribute => GetAttribute(type, inherit) != null; + internal static T GetAttribute(this Type type, bool inherit) where T : Attribute => type.GetCustomAttribute(typeof(T), inherit) as T; + internal static bool HasAttribute(this Type type, bool inherit) where T : Attribute => GetAttribute(type, inherit) != null; - public static string GetRealTypeName(this Type t) + public static string GetRealTypeName(this Type t) + { + if (!t.IsGenericType) { - if (!t.IsGenericType) - { - return t.Name; - } + return t.Name; + } - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); - sb.Append(t.Name.AsSpan().Slice(0, t.Name.IndexOf('`'))); - sb.Append('<'); - Type[] args = t.GetGenericArguments(); - for (int index = 0; index < args.Length; index++) + ValueStringBuilder sb = new(); + sb.Append(t.Name.AsSpan().Slice(0, t.Name.IndexOf('`'))); + sb.Append('<'); + Type[] args = t.GetGenericArguments(); + for (int index = 0; index < args.Length; index++) + { + Type arg = args[index]; + if (index != 0) { - Type arg = args[index]; - if (index != 0) - { - sb.Append(','); - } - sb.Append(GetRealTypeName(arg)); + sb.Append(','); } - sb.Append('>'); - return DiscordPool.Internal.ToStringAndFree(sb); + sb.Append(GetRealTypeName(arg)); } + sb.Append('>'); + return sb.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Factory/BotClientFactory.cs b/Oxide.Ext.Discord/Factory/BotClientFactory.cs index 4bc8a207e..cda03cf05 100644 --- a/Oxide.Ext.Discord/Factory/BotClientFactory.cs +++ b/Oxide.Ext.Discord/Factory/BotClientFactory.cs @@ -1,93 +1,94 @@ using System; using System.Collections.Generic; using Oxide.Ext.Discord.Clients; +using Oxide.Ext.Discord.Connections; using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Factory +namespace Oxide.Ext.Discord.Factory; + +internal sealed class BotClientFactory : Singleton { - internal sealed class BotClientFactory : Singleton - { - /// - /// List of active bots by bot API key - /// - private readonly Hash _activeBots = new Hash(); - private readonly Hash _applicationBots = new Hash(); - - public IEnumerable Clients => _activeBots.Values; + /// + /// List of active bots by bot API key + /// + private readonly Hash _activeBots = new(); + private readonly Hash _applicationBots = new(); - private BotClientFactory() {} + public IEnumerable Clients => _activeBots.Values; - /// - /// Gets or creates a new bot client for the given discord client - /// - /// Client to use for creating / loading the bot client - /// Bot client that is created or already exists - public BotClient InitializeBotClient(DiscordClient client) + private BotClientFactory() {} + + /// + /// Gets or creates a new bot client for the given discord client + /// + /// Client to use for creating / loading the bot client + /// Connection for the bot + /// Bot client that is created or already exists + public BotClient InitializeBotClient(DiscordClient client, BotConnection connection) + { + try { - try + BotClient bot = _activeBots[connection.ApiToken]; + if (bot == null) { - BotClient bot = _activeBots[client.Connection.ApiToken]; - if (bot == null) - { - DiscordExtension.GlobalLogger.Debug($"{nameof(BotClientFactory)}.{nameof(InitializeBotClient)} Creating new BotClient"); - bot = new BotClient(client.Connection); - _activeBots[client.Connection.ApiToken] = bot; - _applicationBots[bot.Connection.ApplicationId] = bot; - } - - DiscordExtension.GlobalLogger.Debug($"{nameof(BotClientFactory)}.{nameof(InitializeBotClient)} Adding {{0}} client to bot {{1}}", client.PluginName, bot.BotUser?.FullUserName); - return bot; - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"{nameof(BotClientFactory)}.{nameof(InitializeBotClient)} An error occured adding {{0}} client", client.PluginName, ex); - return null; + DiscordExtension.GlobalLogger.Debug($"{nameof(BotClientFactory)}.{nameof(InitializeBotClient)} Creating new BotClient"); + bot = new BotClient(connection); + _activeBots[connection.ApiToken] = bot; + _applicationBots[connection.ApplicationId] = bot; } + + DiscordExtension.GlobalLogger.Debug($"{nameof(BotClientFactory)}.{nameof(InitializeBotClient)} Adding {{0}} client to bot {{1}}", client.PluginName, bot.BotUser?.FullUserName); + return bot; } - - internal BotClient GetByApplicationId(Snowflake appId) + catch (Exception ex) { - return _applicationBots[appId]; + DiscordExtension.GlobalLogger.Exception($"{nameof(BotClientFactory)}.{nameof(InitializeBotClient)} An error occured adding {{0}} client", client.PluginName, ex); + return null; } + } - public void RemoveBot(BotClient bot) - { - _activeBots.Remove(bot.Connection.ApiToken); - } + internal BotClient GetByApplicationId(Snowflake appId) + { + return _applicationBots[appId]; + } - public void ResetAllWebSockets() + public void RemoveBot(BotClient bot) + { + _activeBots.Remove(bot.Connection.ApiToken); + } + + public void ResetAllWebSockets() + { + foreach (BotClient client in _activeBots.Values) { - foreach (BotClient client in _activeBots.Values) - { - client.ResetWebSocket(); - } + client.ResetWebSocket(); } + } - public void ReconnectAllWebSockets() + public void ReconnectAllWebSockets() + { + foreach (BotClient client in _activeBots.Values) { - foreach (BotClient client in _activeBots.Values) - { - client.WebSocket.Disconnect(true, true, true); - } + client.WebSocket.Disconnect(true, true, true); } + } - public void ResetAllRestApis() + public void ResetAllRestApis() + { + foreach (BotClient client in _activeBots.Values) { - foreach (BotClient client in _activeBots.Values) - { - client.ResetRestApi(); - } + client.ResetRestApi(); } + } - public void UpdateLogLevel() + public void UpdateLogLevel() + { + foreach (BotClient client in _activeBots.Values) { - foreach (BotClient client in _activeBots.Values) - { - client.UpdateLogLevel(DiscordLoggerFactory.Instance.GetLogLevel()); - } + client.UpdateLogLevel(DiscordLoggerFactory.Instance.GetLogLevel()); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Factory/BotTokenFactory.cs b/Oxide.Ext.Discord/Factory/BotTokenFactory.cs index 722b210ed..b5c9aa1a1 100644 --- a/Oxide.Ext.Discord/Factory/BotTokenFactory.cs +++ b/Oxide.Ext.Discord/Factory/BotTokenFactory.cs @@ -4,96 +4,94 @@ using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Connections; using Oxide.Ext.Discord.Entities; -using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Factory +namespace Oxide.Ext.Discord.Factory; + +internal class BotTokenFactory : Singleton { - internal class BotTokenFactory : Singleton - { - private readonly Regex _tokenValidator = new Regex(@"^[\w-]+\.[\w-]+\.[\w-]+$", RegexOptions.Compiled); - private readonly char[] _splitArgs = {'.'}; + private readonly Regex _tokenValidator = new(@"^[\w-]+\.[\w-]+\.[\w-]+$", RegexOptions.Compiled); + private readonly char[] _splitArgs = ['.']; - private readonly Hash _tokens = new Hash(); + private readonly Hash _tokens = new(); - private BotTokenFactory() { } + private BotTokenFactory() { } - internal BotTokenData CreateFromClient(DiscordClient client) - { - string token = client.Connection.ApiToken; + internal BotTokenData CreateFromClient(DiscordClient client) + { + string token = client.Connection.ApiToken; - BotTokenData botToken = _tokens[token]; - if (botToken == null) - { - botToken = ParseToken(token, client.PluginName); - _tokens[token] = botToken; - } + BotTokenData botToken = _tokens[token]; + if (botToken == null) + { + botToken = ParseToken(token, client.PluginName); + _tokens[token] = botToken; + } - if (!_tokenValidator.IsMatch(token)) - { - DiscordExtension.GlobalLogger.Warning("API Token does not appear to be a valid discord bot token: {0} for plugin {1}. " + - "Please confirm you are using the correct bot token. " + - "If the token is correct and this message is showing please let the Discord Extension Developers know.", botToken.HiddenToken, client.PluginName); - } - - return botToken; + if (!_tokenValidator.IsMatch(token)) + { + DiscordExtension.GlobalLogger.Warning("API Token does not appear to be a valid discord bot token: {0} for plugin {1}. " + + "Please confirm you are using the correct bot token. " + + "If the token is correct and this message is showing please let the Discord Extension Developers know.", botToken.HiddenToken, client.PluginName); } + + return botToken; + } - private static string GenerateHiddenToken(string token) - { - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); + private static string GenerateHiddenToken(string token) + { + ValueStringBuilder sb = new(); - int last = token.LastIndexOf('.') + 1; - sb.Append(token, 0, last); - sb.Append('#', token.Length - last); + int last = token.LastIndexOf('.') + 1; + sb.Append(token.AsSpan().Slice(0, last)); + sb.Append('#', token.Length - last); - return DiscordPool.Internal.ToStringAndFree(sb); - } + return sb.ToString(); + } - private BotTokenData ParseToken(string token, string pluginName) + private BotTokenData ParseToken(string token, string pluginName) + { + string hiddenToken = GenerateHiddenToken(token); + string[] args = token.Split(_splitArgs); + if (args.Length != 3) { - string hiddenToken = GenerateHiddenToken(token); - string[] args = token.Split(_splitArgs); - if (args.Length != 3) - { - DiscordExtension.GlobalLogger.Error("Failed to parse token {0} for plugin {1}", hiddenToken, pluginName); - return new BotTokenData(hiddenToken, default(Snowflake)); - } - - if (!TryParseApplicationId(args[0], out Snowflake appId)) - { - DiscordExtension.GlobalLogger.Error("Failed to parse application ID from bot token. Bot token is invalid. Token: {0}", hiddenToken); - } - - return new BotTokenData(hiddenToken, appId); + DiscordExtension.GlobalLogger.Error("Failed to parse token {0} for plugin {1}", hiddenToken, pluginName); + return new BotTokenData(hiddenToken, default); } - private bool TryParseApplicationId(string base64AppId, out Snowflake id) + if (!TryParseApplicationId(args[0], out Snowflake appId)) { - try - { - string appId = Encoding.UTF8.GetString(ConvertFromBase64(base64AppId)); - id = new Snowflake(appId); - return true; - } - catch(Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An error occured parsing Token Application ID: {0}", base64AppId, ex); - id = default(Snowflake); - return false; - } + DiscordExtension.GlobalLogger.Error("Failed to parse application ID from bot token. Bot token is invalid. Token: {0}", hiddenToken); } - private byte[] ConvertFromBase64(string base64) + return new BotTokenData(hiddenToken, appId); + } + + private bool TryParseApplicationId(string base64AppId, out Snowflake id) + { + try { - if (base64.Length % 4 != 0) - { - base64 += new string('=', (4 - base64.Length % 4)); - } + string appId = Encoding.UTF8.GetString(ConvertFromBase64(base64AppId)); + id = new Snowflake(appId); + return true; + } + catch(Exception ex) + { + DiscordExtension.GlobalLogger.Exception("An error occured parsing Token Application ID: {0}", base64AppId, ex); + id = default; + return false; + } + } - return Convert.FromBase64String(base64); + private byte[] ConvertFromBase64(string base64) + { + if (base64.Length % 4 != 0) + { + base64 += new string('=', (4 - base64.Length % 4)); } + + return Convert.FromBase64String(base64); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Factory/BucketIdFactory.cs b/Oxide.Ext.Discord/Factory/BucketIdFactory.cs index 3af614e40..0d934c2f4 100644 --- a/Oxide.Ext.Discord/Factory/BucketIdFactory.cs +++ b/Oxide.Ext.Discord/Factory/BucketIdFactory.cs @@ -1,80 +1,75 @@ using System; -using System.Text; using Oxide.Core.Libraries; using Oxide.Ext.Discord.Cache; -using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Rest; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Factory +namespace Oxide.Ext.Discord.Factory; + +internal static class BucketIdFactory { - internal static class BucketIdFactory - { - private const char SplitChar = '/'; - private const char QueryStringChar = '?'; - private const string IdReplacement = "id"; - private const string ReactionsRoute = "reactions"; + private const string SplitChar = "/"; + private const char QueryStringChar = '?'; + private const string IdReplacement = "id"; + private const string ReactionsRoute = "reactions"; - /// - /// Returns the Rate Limit Bucket for the given route - /// https://discord.com/developers/docs/topics/rate-limits#rate-limits - /// - /// Request method for the request - /// API Route - /// Bucket ID for route - internal static BucketId GenerateId(RequestMethod method, string route) + /// + /// Returns the Rate Limit Bucket for the given route + /// https://discord.com/developers/docs/topics/rate-limits#rate-limits + /// + /// Request method for the request + /// API Route + /// Bucket ID for route + internal static BucketId GenerateId(RequestMethod method, string route) + { + int routeLength = route.LastIndexOf(QueryStringChar); + if (routeLength == -1) { - int routeLength = route.LastIndexOf(QueryStringChar); - if (routeLength == -1) - { - routeLength = route.Length; - } + routeLength = route.Length; + } - StringTokenizer tokenizer = StringTokenizer.Create(route, SplitChar, routeLength); - tokenizer.MoveNext(); - ReadOnlySpan previous = tokenizer.Current.Span; + StringTokenizer tokenizer = new(route, SplitChar, routeLength); + tokenizer.MoveNext(); + ReadOnlySpan previous = tokenizer.Current; - StringBuilder bucket = DiscordPool.Internal.GetStringBuilder(); - bucket.Append(EnumCache.Instance.ToString(method)); - bucket.Append(':'); - bucket.Append(previous); + ValueStringBuilder bucket = new(); + bucket.Append(EnumCache.Instance.ToString(method)); + bucket.Append(':'); + bucket.Append(previous); - ReadOnlySpan reactions = ReactionsRoute.AsSpan(); + ReadOnlySpan reactions = ReactionsRoute.AsSpan(); - while (tokenizer.MoveNext()) - { - bucket.Append('/'); + while (tokenizer.MoveNext()) + { + bucket.Append('/'); - ReadOnlySpan current = GetCurrent(tokenizer.Index, previous, tokenizer.Current.Span); + ReadOnlySpan current = GetCurrent(tokenizer.Index, previous, tokenizer.Current); - bucket.Append(current); - if (current.Equals(reactions, StringComparison.OrdinalIgnoreCase)) - { - break; - } - - previous = current; + bucket.Append(current); + if (current.Equals(reactions, StringComparison.OrdinalIgnoreCase)) + { + break; } - - tokenizer.Dispose(); - - return new BucketId(DiscordPool.Internal.ToStringAndFree(bucket)); + + previous = current; } + + return new BucketId(bucket.ToString()); + } - private static ReadOnlySpan GetCurrent(int index, ReadOnlySpan previous, ReadOnlySpan token) - { - //If previous is not a major ID we don't want to include the ID in the bucket ID so use "id" string instead - return char.IsNumber(token[0]) && !IsMajorId(index, previous) ? IdReplacement.AsSpan() : token; - } + private static ReadOnlySpan GetCurrent(int index, ReadOnlySpan previous, ReadOnlySpan token) + { + //If previous is not a major ID we don't want to include the ID in the bucket ID so use "id" string instead + return char.IsNumber(token[0]) && !IsMajorId(index, previous) ? IdReplacement.AsSpan() : token; + } - private static bool IsMajorId(int index, ReadOnlySpan previous) - { - //We should only use Major ID if the previous segment name is the first segment and the ID is the second. - return index == 1 && - (previous.Equals("guilds".AsSpan(), StringComparison.OrdinalIgnoreCase) - || previous.Equals("channels".AsSpan(), StringComparison.OrdinalIgnoreCase) - || previous.Equals("webhooks".AsSpan(), StringComparison.OrdinalIgnoreCase) - ); - } + private static bool IsMajorId(int index, ReadOnlySpan previous) + { + //We should only use Major ID if the previous segment name is the first segment and the ID is the second. + return index == 1 && + (previous.Equals("guilds".AsSpan(), StringComparison.OrdinalIgnoreCase) + || previous.Equals("channels".AsSpan(), StringComparison.OrdinalIgnoreCase) + || previous.Equals("webhooks".AsSpan(), StringComparison.OrdinalIgnoreCase) + ); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Factory/DiscordClientFactory.cs b/Oxide.Ext.Discord/Factory/DiscordClientFactory.cs index 72a54b0f5..bed18948a 100644 --- a/Oxide.Ext.Discord/Factory/DiscordClientFactory.cs +++ b/Oxide.Ext.Discord/Factory/DiscordClientFactory.cs @@ -12,130 +12,128 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Factory +namespace Oxide.Ext.Discord.Factory; + +/// +/// Factory for creating +/// +public sealed class DiscordClientFactory : Singleton { + private readonly Hash _clients = new(); + + private DiscordClientFactory() { } + + #region Client Handling /// - /// Factory for creating + /// Creates the client for the given plugin. If one already exists, the existing one is returned /// - public sealed class DiscordClientFactory : Singleton + /// Plugin the client is for + /// DiscordClient for plugin + /// Thrown is plugin is null + public DiscordClient CreateClient(Plugin plugin) { - private readonly Hash _clients = new Hash(); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + OnPluginUnloaded(plugin); - private DiscordClientFactory() { } - - #region Client Handling - /// - /// Creates the client for the given plugin. If one already exist the existing one is returned - /// - /// Plugin the client is for - /// DiscordClient for plugin - /// Thrown is plugin is null - public DiscordClient CreateClient(Plugin plugin) + // ReSharper disable once SuspiciousTypeConversion.Global + if (plugin is not IDiscordPlugin discordPlugin) { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - OnPluginUnloaded(plugin); - - // ReSharper disable once SuspiciousTypeConversion.Global - if (!(plugin is IDiscordPlugin discordPlugin)) - { - return null; - } - - DiscordClient client = _clients[plugin.Id()]; - if (client == null) - { - DiscordExtension.GlobalLogger.Debug($"{nameof(DiscordClient)}.{nameof(CreateClient)} Creating DiscordClient for plugin {{0}}", plugin.FullName()); - client = new DiscordClient(plugin); - _clients[plugin.Id()] = client; - } - - discordPlugin.Client = client; - DiscordHook.CallPluginHook(client.Plugin, DiscordExtHooks.OnDiscordClientCreated); - return client; + return null; } - /// - /// Gets the client for the given plugin - /// - /// Plugin to get client for - /// Discord client for the plugin - public DiscordClient GetClient(Plugin plugin) + DiscordClient client = _clients[plugin.Id()]; + if (client == null) { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - return GetClient(plugin.Id()); + DiscordExtension.GlobalLogger.Debug($"{nameof(DiscordClient)}.{nameof(CreateClient)} Creating DiscordClient for plugin {{0}}", plugin.FullName()); + client = new DiscordClient(plugin); + _clients[plugin.Id()] = client; } + + discordPlugin.Client = client; + DiscordHook.CallPluginHook(client.Plugin, DiscordExtHooks.OnDiscordClientCreated); + return client; + } + + /// + /// Gets the client for the given plugin + /// + /// Plugin to get the client for + /// Discord client for the plugin + public DiscordClient GetClient(Plugin plugin) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + return GetClient(plugin.Id()); + } - /// - /// Gets the client for the given plugin - /// - /// Plugin to get client for - /// Discord client for the plugin - internal DiscordClient GetClient(PluginId pluginId) - { - return _clients[pluginId]; - } + /// + /// Gets the client for the given plugin + /// + /// Plugin to get the client for + /// Discord client for the plugin + private DiscordClient GetClient(PluginId pluginId) + { + return _clients[pluginId]; + } - /// - /// Gets the client for the given plugin name - /// - /// Plugin Name to get client for - /// Discord client for the plugin name - public DiscordClient GetClient(string pluginName) - { - if (pluginName == null) throw new ArgumentNullException(nameof(pluginName)); - return GetClient(new PluginId(pluginName)); - } - #endregion + /// + /// Gets the client for the given plugin name + /// + /// Plugin Name to get the client for + /// Discord client for the plugin name + public DiscordClient GetClient(string pluginName) + { + if (pluginName == null) throw new ArgumentNullException(nameof(pluginName)); + return GetClient(new PluginId(pluginName)); + } + #endregion - #region Plugin Handling - internal void OnPluginLoaded(Plugin plugin) + #region Plugin Handling + internal void OnPluginLoaded(Plugin plugin) + { + if (!plugin.IsCorePlugin) { - if (!plugin.IsCorePlugin) - { - CreateClient(plugin); - DiscordPluginCache.Instance.OnPluginLoaded(plugin); - } + CreateClient(plugin); + DiscordPluginCache.Instance.OnPluginLoaded(plugin); } + } - internal void OnPluginUnloaded(Plugin plugin) + internal void OnPluginUnloaded(Plugin plugin) + { + if (plugin.IsCorePlugin || DiscordExtension.IsShuttingDown) { - if (plugin.IsCorePlugin || DiscordExtension.IsShuttingDown) - { - return; - } - - DiscordClient client = _clients[plugin.Id()]; - if (client != null) - { - client.CloseClient(); - BaseDiscordLibrary.ProcessPluginUnloaded(plugin); - } - - PluginExt.OnPluginUnloaded(plugin); - DiscordPluginCache.Instance.OnPluginUnloaded(plugin); - DiscordLoggerFactory.Instance.OnPluginUnloaded(plugin); + return; } - internal void RemoveClient(DiscordClient client) + DiscordClient client = _clients[plugin.Id()]; + if (client != null) { - _clients.Remove(client.PluginId); + client.CloseClient(); + BaseDiscordLibrary.ProcessPluginUnloaded(plugin); } - internal void OnShutdown() + PluginExt.OnPluginUnloaded(plugin); + DiscordPluginCache.Instance.OnPluginUnloaded(plugin); + } + + internal void RemoveClient(DiscordClient client) + { + _clients.Remove(client.PluginId); + } + + internal void OnShutdown() + { + foreach (DiscordClient client in _clients.Values.ToList()) { - foreach (DiscordClient client in _clients.Values.ToList()) - { - client.CloseClient(); - } + client.CloseClient(); } - #endregion + } + #endregion - internal void UpdateLogLevel() + internal void UpdateLogLevel() + { + foreach (DiscordClient client in _clients.Values) { - foreach (DiscordClient client in _clients.Values) - { - client.UpdateLogLevel(); - } + client.UpdateLogLevel(); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Factory/SnowflakeIdFactory.cs b/Oxide.Ext.Discord/Factory/SnowflakeIdFactory.cs index 07424bdcf..167c2d25f 100644 --- a/Oxide.Ext.Discord/Factory/SnowflakeIdFactory.cs +++ b/Oxide.Ext.Discord/Factory/SnowflakeIdFactory.cs @@ -2,38 +2,37 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Factory +namespace Oxide.Ext.Discord.Factory; + +/// +/// Generates a unique snowflake ID +/// +public sealed class SnowflakeIdFactory : Singleton { + private DateTimeOffset _currentTime; + private ulong _increment; + private readonly TimeSpan _diffCompare = TimeSpan.FromMilliseconds(1); + private readonly object _sync = new(); + + private SnowflakeIdFactory() { } + /// - /// Generates a unique snowflake ID + /// Returns the generated snowflake ID /// - public sealed class SnowflakeIdFactory : Singleton + /// + public Snowflake Generate() { - private DateTimeOffset _currentTime; - private ulong _increment; - private readonly TimeSpan _diffCompare = TimeSpan.FromMilliseconds(1); - private readonly object _sync = new object(); - - private SnowflakeIdFactory() { } - - /// - /// Returns the generated snowflake ID - /// - /// - public Snowflake Generate() + lock (_sync) { - lock (_sync) + if (DateTimeOffset.UtcNow - _currentTime >= _diffCompare) { - if (DateTimeOffset.UtcNow - _currentTime >= _diffCompare) - { - _currentTime = DateTimeOffset.UtcNow; - _increment = 0; - } - - Snowflake id = new Snowflake(_currentTime, _increment); - _increment++; - return id; + _currentTime = DateTimeOffset.UtcNow; + _increment = 0; } + + Snowflake id = new(_currentTime, _increment); + _increment++; + return id; } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Factory/WebhookClientFactory.cs b/Oxide.Ext.Discord/Factory/WebhookClientFactory.cs new file mode 100644 index 000000000..5e03b9ac8 --- /dev/null +++ b/Oxide.Ext.Discord/Factory/WebhookClientFactory.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using Oxide.Ext.Discord.Clients; +using Oxide.Ext.Discord.Connections; +using Oxide.Ext.Discord.Logging; +using Oxide.Ext.Discord.Types; +using Oxide.Plugins; + +namespace Oxide.Ext.Discord.Factory; + +internal sealed class WebhookClientFactory : Singleton +{ + /// + /// List of active bots by bot API key + /// + private readonly Hash _activeWebhooks = new(); + + public IEnumerable Clients => _activeWebhooks.Values; + + private WebhookClientFactory() {} + + /// + /// Gets or creates a new bot client for the given discord client + /// + /// Client to use for creating / loading the bot client + /// Connection for the webhook + /// Bot client that is created or already exists + public WebhookClient InitializeWebhookClient(DiscordClient client, WebhookConnection connection) + { + try + { + WebhookClient bot = _activeWebhooks[connection.WebhookToken]; + if (bot == null) + { + DiscordExtension.GlobalLogger.Debug($"{nameof(WebhookClientFactory)}.{nameof(InitializeWebhookClient)} Creating new ${nameof(WebhookClient)}"); + bot = new WebhookClient(connection); + _activeWebhooks[connection.WebhookToken] = bot; + } + + DiscordExtension.GlobalLogger.Debug($"{nameof(WebhookClientFactory)}.{nameof(InitializeWebhookClient)} Adding {{0}} client to webhook {{1}}", client.PluginName, connection.WebhookId); + return bot; + } + catch (Exception ex) + { + DiscordExtension.GlobalLogger.Exception($"{nameof(WebhookClientFactory)}.{nameof(InitializeWebhookClient)} An error occured adding {{0}} client", client.PluginName, ex); + return null; + } + } + + public void RemoveWebhook(WebhookClient client) + { + _activeWebhooks.Remove(client.Connection.WebhookToken); + } + + public void UpdateLogLevel() + { + foreach (WebhookClient client in _activeWebhooks.Values) + { + client.UpdateLogLevel(DiscordLoggerFactory.Instance.GetLogLevel()); + } + } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Helpers/DiscordAppRoutes.cs b/Oxide.Ext.Discord/Helpers/DiscordAppRoutes.cs index 51f73f40b..7c4bfe3d7 100644 --- a/Oxide.Ext.Discord/Helpers/DiscordAppRoutes.cs +++ b/Oxide.Ext.Discord/Helpers/DiscordAppRoutes.cs @@ -1,242 +1,173 @@ using System; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Helpers +namespace Oxide.Ext.Discord.Helpers; + +/// +/// Discord App Routes for navigating the client within the discord app using links +/// Sourced from: https://gist.github.com/ghostrider-05/8f1a0bfc27c7c4509b4ea4e8ce718af0 +/// +public static class DiscordAppRoutes { + private const string BaseUrl = "discord://-"; + /// - /// Discord App Routes for navigating the client within the discord app using links - /// Sourced from: https://gist.github.com/ghostrider-05/8f1a0bfc27c7c4509b4ea4e8ce718af0 + /// User App Route /// - public static class DiscordAppRoutes - { - private const string BaseUrl = "discord://-"; + public static string User(IDiscordKey userId) => $"{BaseUrl}/users/{userId.ToString()}"; + /// + /// Message Requests App Route + /// + public const string MessageRequests = BaseUrl + "/message-requests"; + + /// + /// General App Routes + /// + public static class General + { /// - /// User App Route + /// Apps App Route /// - public static string User(IDiscordKey userId) => $"{BaseUrl}/users/{userId.ToString()}"; - + public const string Apps = BaseUrl + "/apps"; + /// - /// Message Requests App Route + /// Guild Discovery App Route /// - public const string MessageRequests = BaseUrl + "/message-requests"; - + public const string GuildDiscovery = BaseUrl + "/guild-discovery"; + /// - /// General App Routes + /// Create Guild App Route /// - public static class General - { - /// - /// Apps App Route - /// - public const string Apps = BaseUrl + "/apps"; - - /// - /// Guild Discovery App Route - /// - public const string GuildDiscovery = BaseUrl + "/guild-discovery"; - - /// - /// Create Guild App Route - /// - public const string CreateGuild = BaseUrl + "/guilds/create"; + public const string CreateGuild = BaseUrl + "/guilds/create"; - /// - /// Gift App Route - /// - public static string Gift(string code) => $"{BaseUrl}/gifts/{code}"; + /// + /// Gift App Route + /// + public static string Gift(string code) => $"{BaseUrl}/gifts/{code}"; - /// - /// Server Invite App Route - /// - public static string ServerInvite(string code) => $"{BaseUrl}/invite/{code}"; + /// + /// Server Invite App Route + /// + public static string ServerInvite(string code) => $"{BaseUrl}/invite/{code}"; - /// - /// App Settings Page Routes - /// - /// - public static string Settings(SettingsPage page) + /// + /// App Settings Page Routes + /// + /// + public static string Settings(SettingsPage page) + { + string path = page switch { - string path; - switch (page) - { - case SettingsPage.Account: - path = "account"; - break; - case SettingsPage.ProfileCustomization: - path = "profile-customization"; - break; - case SettingsPage.PrivacyAndSafety: - path = "privacy-and-safety"; - break; - case SettingsPage.AuthorizedApps: - path = "authorized-apps"; - break; - case SettingsPage.Connections: - path = "connections"; - break; - case SettingsPage.Premium: - path = "premium"; - break; - case SettingsPage.PremiumGuildSubscriptions: - path = "premium-guild-subscription"; - break; - case SettingsPage.Subscriptions: - path = "subscriptions"; - break; - case SettingsPage.Inventory: - path = "inventory"; - break; - case SettingsPage.Billing: - path = "billing"; - break; - case SettingsPage.Appearance: - path = "appearance"; - break; - case SettingsPage.Accessibility: - path = "accessibility"; - break; - case SettingsPage.Voice: - path = "voice"; - break; - case SettingsPage.Text: - path = "text"; - break; - case SettingsPage.Notifications: - path = "notifications"; - break; - case SettingsPage.Keybinds: - path = "keybinds"; - break; - case SettingsPage.Locale: - path = "locale"; - break; - case SettingsPage.Windows: - path = "windows"; - break; - case SettingsPage.Linux: - path = "linux"; - break; - case SettingsPage.StreamerMode: - path = "streamer-mode"; - break; - case SettingsPage.Advanced: - path = "advanced"; - break; - case SettingsPage.ActivityStatus: - path = "activity-status"; - break; - case SettingsPage.Overlay: - path = "overlay"; - break; - case SettingsPage.HypesquadOnline: - path = "hypesquad-online"; - break; - case SettingsPage.Changelogs: - path = "changelogs"; - break; - case SettingsPage.Experiments: - path = "experiments"; - break; - case SettingsPage.DeveloperOptions: - path = "developer-options"; - break; - case SettingsPage.HotspotOptions: - path = "hotspot-options"; - break; - case SettingsPage.DismissibleContentOptions: - path = "dismissible-content-options"; - break; - case SettingsPage.FamilyCenter: - path = "family-center"; - break; - case SettingsPage.Sessions: - path = "sessions"; - break; - case SettingsPage.FriendRequests: - path = "friend-requests"; - break; - case SettingsPage.RegisteredGames: - path = "registered-games"; - break; - default: - throw new ArgumentOutOfRangeException(nameof(page), page, null); - } + SettingsPage.Account => "account", + SettingsPage.ProfileCustomization => "profile-customization", + SettingsPage.PrivacyAndSafety => "privacy-and-safety", + SettingsPage.AuthorizedApps => "authorized-apps", + SettingsPage.Connections => "connections", + SettingsPage.Premium => "premium", + SettingsPage.PremiumGuildSubscriptions => "premium-guild-subscription", + SettingsPage.Subscriptions => "subscriptions", + SettingsPage.Inventory => "inventory", + SettingsPage.Billing => "billing", + SettingsPage.Appearance => "appearance", + SettingsPage.Accessibility => "accessibility", + SettingsPage.Voice => "voice", + SettingsPage.Text => "text", + SettingsPage.Notifications => "notifications", + SettingsPage.Keybinds => "keybinds", + SettingsPage.Locale => "locale", + SettingsPage.Windows => "windows", + SettingsPage.Linux => "linux", + SettingsPage.StreamerMode => "streamer-mode", + SettingsPage.Advanced => "advanced", + SettingsPage.ActivityStatus => "activity-status", + SettingsPage.Overlay => "overlay", + SettingsPage.HypesquadOnline => "hypesquad-online", + SettingsPage.Changelogs => "changelogs", + SettingsPage.Experiments => "experiments", + SettingsPage.DeveloperOptions => "developer-options", + SettingsPage.HotspotOptions => "hotspot-options", + SettingsPage.DismissibleContentOptions => "dismissible-content-options", + SettingsPage.FamilyCenter => "family-center", + SettingsPage.Sessions => "sessions", + SettingsPage.FriendRequests => "friend-requests", + SettingsPage.RegisteredGames => "registered-games", + _ => throw new ArgumentOutOfRangeException(nameof(page), page, null) + }; - return $"{BaseUrl}/{path}"; - } + return $"{BaseUrl}/{path}"; } + } + /// + /// DM App routes + /// + public static class DMs + { /// - /// DM App routes + /// DM Channel App Route /// - public static class DMs - { - /// - /// DM Channel App Route - /// - public static string Channel(IDiscordKey channelId) => $"{BaseUrl}/channels/@me/{channelId.ToString()}"; + public static string Channel(IDiscordKey channelId) => $"{BaseUrl}/channels/@me/{channelId.ToString()}"; - /// - /// DM Message App Route - /// - public static string Message(IDiscordKey channelId, IDiscordKey messageId) => $"{BaseUrl}/channels/@me/{channelId.ToString()}/{messageId.ToString()}"; - } + /// + /// DM Message App Route + /// + public static string Message(IDiscordKey channelId, IDiscordKey messageId) => $"{BaseUrl}/channels/@me/{channelId.ToString()}/{messageId.ToString()}"; + } + /// + /// Guild App Routes + /// + public static class Guilds + { /// - /// Guild App Routes + /// Favorite Channels App Route /// - public static class Guilds - { - /// - /// Favorite Channels App Route - /// - public const string Favorites = BaseUrl + "/channels/@favorites"; + public const string Favorites = BaseUrl + "/channels/@favorites"; - /// - /// Favorites Channel App Route - /// - public static string FavoritesChannel(IDiscordKey channelId) => $"{BaseUrl}/channels/@favorites/{channelId.ToString()}"; + /// + /// Favorites Channel App Route + /// + public static string FavoritesChannel(IDiscordKey channelId) => $"{BaseUrl}/channels/@favorites/{channelId.ToString()}"; - /// - /// Guild App Route - /// - public static string Guild(IDiscordKey guildId) => $"{BaseUrl}/channels/{guildId.ToString()}"; + /// + /// Guild App Route + /// + public static string Guild(IDiscordKey guildId) => $"{BaseUrl}/channels/{guildId.ToString()}"; - /// - /// Guild Channel App Route - /// - public static string Channel(IDiscordKey guildId, IDiscordKey channelId) => $"{BaseUrl}/channels/{guildId.ToString()}/{channelId.ToString()}"; + /// + /// Guild Channel App Route + /// + public static string Channel(IDiscordKey guildId, IDiscordKey channelId) => $"{BaseUrl}/channels/{guildId.ToString()}/{channelId.ToString()}"; - /// - /// Browse Guild Channels App Route - /// - public static string BrowseChannel(IDiscordKey guildId) => $"{BaseUrl}/channels/{guildId.ToString()}/channel-browser"; + /// + /// Browse Guild Channels App Route + /// + public static string BrowseChannel(IDiscordKey guildId) => $"{BaseUrl}/channels/{guildId.ToString()}/channel-browser"; - /// - /// Server Guide App Route - /// - public static string ServerGuide(IDiscordKey guildId) => $"{BaseUrl}/channels/{guildId.ToString()}/@home"; + /// + /// Server Guide App Route + /// + public static string ServerGuide(IDiscordKey guildId) => $"{BaseUrl}/channels/{guildId.ToString()}/@home"; - /// - /// Event App Route - /// - public static string Event(IDiscordKey guildId, IDiscordKey eventId) => $"{BaseUrl}/events/{guildId.ToString()}/{eventId}"; + /// + /// Event App Route + /// + public static string Event(IDiscordKey guildId, IDiscordKey eventId) => $"{BaseUrl}/events/{guildId.ToString()}/{eventId}"; - /// - /// Message App Route - /// - public static string Message(IDiscordKey guildId, IDiscordKey channelId, IDiscordKey messageId) => $"{BaseUrl}/channels/{guildId.ToString()}/{channelId.ToString()}/{messageId.ToString()}"; + /// + /// Message App Route + /// + public static string Message(IDiscordKey guildId, IDiscordKey channelId, IDiscordKey messageId) => $"{BaseUrl}/channels/{guildId.ToString()}/{channelId.ToString()}/{messageId.ToString()}"; - /// - /// Membership Screening App Route - /// - public static string MembershipScreening(IDiscordKey guildId) => $"{BaseUrl}/member-verification/{guildId.ToString()}"; + /// + /// Membership Screening App Route + /// + public static string MembershipScreening(IDiscordKey guildId) => $"{BaseUrl}/member-verification/{guildId.ToString()}"; - /// - /// Role Subscriptions App Route - /// - public static string RoleSubscriptions(IDiscordKey guildId) => $"{BaseUrl}/guild-role-subscriptions/{guildId.ToString()}"; - } + /// + /// Role Subscriptions App Route + /// + public static string RoleSubscriptions(IDiscordKey guildId) => $"{BaseUrl}/guild-role-subscriptions/{guildId.ToString()}"; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Helpers/DiscordCdn.cs b/Oxide.Ext.Discord/Helpers/DiscordCdn.cs index 90a783093..03d050641 100644 --- a/Oxide.Ext.Discord/Helpers/DiscordCdn.cs +++ b/Oxide.Ext.Discord/Helpers/DiscordCdn.cs @@ -2,522 +2,398 @@ using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Helpers +namespace Oxide.Ext.Discord.Helpers; + +/// +/// Represents Discord CDN Endpoints +/// +public static class DiscordCdn { /// - /// Represents Discord CDN Endpoints + /// Base CDN Url /// - public static class DiscordCdn - { - /// - /// Base CDN Url - /// - public const string CdnUrl = "https://cdn.discordapp.com"; + public const string CdnUrl = "https://cdn.discordapp.com"; - /// - /// Returns the Url to the custom emoji - /// - /// ID of the emoji - /// The format the emoji is in - /// Url of the emoji - /// Thrown if format is Jpg or WebP - public static string GetCustomEmojiUrl(Snowflake emojiId, DiscordImageFormat format) + /// + /// Returns the Url to the custom emoji + /// + /// ID of the emoji + /// The format the emoji is in + /// Url of the emoji + /// Thrown if the format is Jpg or WebP + public static string GetCustomEmojiUrl(Snowflake emojiId, DiscordImageFormat format) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - case DiscordImageFormat.Gif: - return $"{CdnUrl}/emojis/{emojiId.ToString()}.{GetExtension(format)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Custom Emoji. Valid types are (Auto, Png, Jpeg, WebP, Gif)", nameof(format)); - } - } + DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP or DiscordImageFormat.Gif => $"{CdnUrl}/emojis/{emojiId.ToString()}.{GetExtension(format)}", + _ => throw new ArgumentException("ImageFormat is not valid for Custom Emoji. Valid types are (Auto, Png, Jpeg, WebP, Gif)", nameof(format)) + }; + } - /// - /// Returns the Url to the Guild Icon - /// - /// Guild ID for the icon - /// Guild Icon from guild - /// Format the icon is in - /// Url of the guild icon - public static string GetGuildIconUrl(Snowflake guildId, string guildIcon, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the Url to the Guild Icon + /// + /// Guild ID for the icon + /// Guild Icon from guild + /// Format the icon is in + /// Url of the guild icon + public static string GetGuildIconUrl(Snowflake guildId, string guildIcon, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - case DiscordImageFormat.Gif: - return $"{CdnUrl}/icons/{guildId.ToString()}/{guildIcon}.{GetExtension(format, guildIcon)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Guild Icon. Valid types are (Auto, Png, Jpeg, WebP, Gif)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP or DiscordImageFormat.Gif => $"{CdnUrl}/icons/{guildId.ToString()}/{guildIcon}.{GetExtension(format, guildIcon)}", + _ => throw new ArgumentException("ImageFormat is not valid for Guild Icon. Valid types are (Auto, Png, Jpeg, WebP, Gif)", nameof(format)) + }; + } - /// - /// Returns the Url of the Guild Splash - /// - /// Guild ID for the icon - /// Guild Splash from guild - /// Format the icon is in - /// Url of the guild splash - /// Thrown if format is Gif - public static string GetGuildSplashUrl(Snowflake guildId, string guildSplash, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the Url of the Guild Splash + /// + /// Guild ID for the icon + /// Guild Splash from guild + /// Format the icon is in + /// Url of the guild splash + /// Thrown if the format is GIF + public static string GetGuildSplashUrl(Snowflake guildId, string guildSplash, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - return $"{CdnUrl}/splashes/{guildId.ToString()}/{guildSplash}.{GetExtension(format)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Guild Splash. Valid types are (Png, Jpeg, WebP)", nameof(format)); - } - } + DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP => $"{CdnUrl}/splashes/{guildId.ToString()}/{guildSplash}.{GetExtension(format)}", + _ => throw new ArgumentException("ImageFormat is not valid for Guild Splash. Valid types are (Png, Jpeg, WebP)", nameof(format)) + }; + } - /// - /// Return the Url of the Guild Discovery Splash - /// - /// Guild ID for the icon - /// Guild Discovery Splash from guild - /// Format the icon is in - /// Url of the guild discovery splash - /// Thrown if format is Gif - public static string GetGuildDiscoverySplashUrl(Snowflake guildId, string guildDiscoverySplash, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Return the Url of the Guild Discovery Splash + /// + /// Guild ID for the icon + /// Guild Discovery Splash from guild + /// Format the icon is in + /// Url of the guild discovery splash + /// Thrown if the format is GIF + public static string GetGuildDiscoverySplashUrl(Snowflake guildId, string guildDiscoverySplash, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - return $"{CdnUrl}/discovery-splashes/{guildId.ToString()}/{guildDiscoverySplash}.{GetExtension(format, guildDiscoverySplash)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Guild Discovery Splash. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP => $"{CdnUrl}/discovery-splashes/{guildId.ToString()}/{guildDiscoverySplash}.{GetExtension(format, guildDiscoverySplash)}", + _ => throw new ArgumentException("ImageFormat is not valid for Guild Discovery Splash. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)) + }; + } - /// - /// Returns the Url of the Guild Banner - /// - /// Guild ID for the icon - /// Guild Banner from guild - /// Format the icon is in - /// Url of the guild banner - /// Thrown if format is Gif - public static string GetGuildBannerUrl(Snowflake guildId, string guildBanner, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the Url of the Guild Banner + /// + /// Guild ID for the icon + /// Guild Banner from guild + /// Format the icon is in + /// Url of the guild banner + /// Thrown if the format is GIF + public static string GetGuildBannerUrl(Snowflake guildId, string guildBanner, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - case DiscordImageFormat.Gif: - return $"{CdnUrl}/banners/{guildId.ToString()}/{guildBanner}.{GetExtension(format, guildBanner)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Guild Banner. Valid types are (Auto, Png, Jpeg, WebP, GIF)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP or DiscordImageFormat.Gif => $"{CdnUrl}/banners/{guildId.ToString()}/{guildBanner}.{GetExtension(format, guildBanner)}", + _ => throw new ArgumentException("ImageFormat is not valid for Guild Banner. Valid types are (Auto, Png, Jpeg, WebP, GIF)", nameof(format)) + }; + } - /// - /// Returns the Url of the User Banner - /// - /// User ID for the Banner - /// User Banner from user - /// Format the icon is in - /// Url of the User banner - /// Thrown if format is Gif - public static string GetUserBanner(Snowflake userId, string userBanner, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the Url of the User Banner + /// + /// User ID for the Banner + /// User Banner from user + /// Format the icon is in + /// Url of the User banner + /// Thrown if the format is GIF + public static string GetUserBanner(Snowflake userId, string userBanner, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - case DiscordImageFormat.Gif: - return $"{CdnUrl}/banners/{userId.ToString()}/{userBanner}.{GetExtension(format, userBanner)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for User Banner. Valid types are (Auto, Png, Jpeg, WebP, GIF)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP or DiscordImageFormat.Gif => $"{CdnUrl}/banners/{userId.ToString()}/{userBanner}.{GetExtension(format, userBanner)}", + _ => throw new ArgumentException("ImageFormat is not valid for User Banner. Valid types are (Auto, Png, Jpeg, WebP, GIF)", nameof(format)) + }; + } - /// - /// Returns the Url of the users default avatar - /// - /// Discord User Discriminator - /// Url of the default avatar url - public static string GetUserDefaultAvatarUrl(string userDiscriminator) - { - uint discriminator = uint.Parse(userDiscriminator) % 5; - return $"{CdnUrl}/embed/avatars/{discriminator.ToString()}.png"; - } + /// + /// Returns the Url of the users default avatar + /// + /// Discord User Discriminator + /// Url of the default avatar url + public static string GetUserDefaultAvatarUrl(string userDiscriminator) + { + uint discriminator = uint.Parse(userDiscriminator) % 5; + return $"{CdnUrl}/embed/avatars/{discriminator.ToString()}.png"; + } - /// - /// Returns the Url of the users avatar - /// - /// Discord User ID - /// User avatar from user - /// Format the avatar is in - /// Url of the users avatar - public static string GetUserAvatarUrl(Snowflake userId, string userAvatar, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the Url of the users avatar + /// + /// Discord User ID + /// User avatar from user + /// Format the avatar is in + /// Url of the user's avatar + public static string GetUserAvatarUrl(Snowflake userId, string userAvatar, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - case DiscordImageFormat.Gif: - return $"{CdnUrl}/avatars/{userId.ToString()}/{userAvatar}.{GetExtension(format, userAvatar)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for User Avatar. Valid types are (Auto, Png, Jpeg, WebP, Gif)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP or DiscordImageFormat.Gif => $"{CdnUrl}/avatars/{userId.ToString()}/{userAvatar}.{GetExtension(format, userAvatar)}", + _ => throw new ArgumentException("ImageFormat is not valid for User Avatar. Valid types are (Auto, Png, Jpeg, WebP, Gif)", nameof(format)) + }; + } - /// - /// Returns the Url of the Guild Member avatar - /// - /// Guild ID of the Guild Member - /// Discord User ID - /// Guild Member avatar - /// Format the avatar is in - /// Url of the Guild Member avatar - public static string GetGuildMemberAvatar(Snowflake guildId, Snowflake userId, string memberAvatar, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the Url of the Guild Member avatar + /// + /// Guild ID of the Guild Member + /// Discord User ID + /// Guild Member avatar + /// Format the avatar is in + /// Url of the Guild Member avatar + public static string GetGuildMemberAvatar(Snowflake guildId, Snowflake userId, string memberAvatar, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - case DiscordImageFormat.Gif: - return $"{CdnUrl}/guilds/{guildId.ToString()}/users/{userId.ToString()}/avatars/{memberAvatar}.{GetExtension(format, memberAvatar)}"; + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP or DiscordImageFormat.Gif => $"{CdnUrl}/guilds/{guildId.ToString()}/users/{userId.ToString()}/avatars/{memberAvatar}.{GetExtension(format, memberAvatar)}", + _ => throw new ArgumentException("ImageFormat is not valid for Guild Member Avatar. Valid types are (Auto, Png, Jpeg, WebP, Gif)", nameof(format)) + }; + } - default: - throw new ArgumentException("ImageFormat is not valid for Guild Member Avatar. Valid types are (Auto, Png, Jpeg, WebP, Gif)", nameof(format)); - } - } - - /// - /// Returns the Url of the User Avatar Decoration - /// - /// Discord User ID - /// Guild Member avatar - /// Format the avatar is in - /// Url of the Guild Member avatar - public static string GetUserAvatarDecoration(Snowflake userId, string decorationHash, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the Url of the User Avatar Decoration + /// + /// Avatar Decoration Data + /// Format the avatar is in + /// Url of the Guild Member avatar + public static string GetUserAvatarDecoration(AvatarDecorationData data, DiscordImageFormat format = DiscordImageFormat.Auto) + { + if (data == null) throw new ArgumentNullException(nameof(data)); + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Png: - return $"{CdnUrl}/avatar-decorations/{userId}/{decorationHash}.{GetExtension(format, decorationHash)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for User Avatar Decoration. Valid types are (Auto, Png)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Png => $"{CdnUrl}/avatar-decoration-presets/{data.Asset}.{GetExtension(format, data.Asset)}", + _ => throw new ArgumentException("ImageFormat is not valid for User Avatar Decoration. Valid types are (Auto, Png)", nameof(format)) + }; + } - /// - /// Returns the url to the application icon - /// - /// Application ID - /// Icon field from application - /// Format the icon is in - /// Url of the application icon - /// Throw if format is Gif - public static string GetApplicationIconUrl(Snowflake applicationId, string icon, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the url to the application icon + /// + /// Application ID + /// Icon field from application + /// Format the icon is in + /// Url of the application icon + /// Throw if the format is GIF + public static string GetApplicationIconUrl(Snowflake applicationId, string icon, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - return $"{CdnUrl}/app-icons/{applicationId.ToString()}/{icon}.{GetExtension(format, icon)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Application Icon. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP => $"{CdnUrl}/app-icons/{applicationId.ToString()}/{icon}.{GetExtension(format, icon)}", + _ => throw new ArgumentException("ImageFormat is not valid for Application Icon. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)) + }; + } - /// - /// Returns the url to the application cover - /// - /// Application ID - /// Icon field from application - /// Format the icon is in - /// Url of the application icon - /// Throw if format is Gif - public static string GetApplicationCoverUrl(Snowflake applicationId, string coverImage, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the url to the application cover + /// + /// Application ID + /// Icon field from application + /// Format the icon is in + /// Url of the application icon + /// Throw if the format is GIF + public static string GetApplicationCoverUrl(Snowflake applicationId, string coverImage, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - return $"{CdnUrl}/app-icons/{applicationId.ToString()}/{coverImage}.{GetExtension(format, coverImage)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Application Cover. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP => $"{CdnUrl}/app-icons/{applicationId.ToString()}/{coverImage}.{GetExtension(format, coverImage)}", + _ => throw new ArgumentException("ImageFormat is not valid for Application Cover. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)) + }; + } - /// - /// Returns the applications asset icon url - /// - /// Application ID of the icon - /// Asset ID for the application - /// Format the icon is in - /// Url of the application asset icon - /// Throw if format is Gif - public static string GetApplicationAssetUrl(Snowflake applicationId, string assetId, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the applications asset icon url + /// + /// Application ID of the icon + /// Asset ID for the application + /// Format the icon is in + /// Url of the application asset icon + /// Throw if the format is GIF + public static string GetApplicationAssetUrl(Snowflake applicationId, string assetId, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - return $"{CdnUrl}/app-assets/{applicationId.ToString()}/{assetId}.{GetExtension(format, assetId)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Application Asset. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP => $"{CdnUrl}/app-assets/{applicationId.ToString()}/{assetId}.{GetExtension(format, assetId)}", + _ => throw new ArgumentException("ImageFormat is not valid for Application Asset. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)) + }; + } - /// - /// Returns the Url of the Achievement Icon - /// - /// Application ID of the icon - /// Achievement ID - /// Achievement Icon Hash - /// Url of the achievement icon - /// Throw if format is Gif - public static string GetAchievementIconUrl(Snowflake applicationId, Snowflake achievementId, string iconHash) - { - return $"{CdnUrl}/app-assets/{applicationId.ToString()}/achievements/{achievementId.ToString()}/icons/{iconHash}.png"; - } + /// + /// Returns the Url of the Achievement Icon + /// + /// Application ID of the icon + /// Achievement ID + /// Achievement Icon Hash + /// Url of the achievement icon + /// Throw if the format is GIF + public static string GetAchievementIconUrl(Snowflake applicationId, Snowflake achievementId, string iconHash) + { + return $"{CdnUrl}/app-assets/{applicationId.ToString()}/achievements/{achievementId.ToString()}/icons/{iconHash}.png"; + } - /// - /// Returns the Store Page Asset Url - /// - /// Application ID of the icon - /// Asset ID - /// Format the icon is in - /// Url of the achievement icon - /// Throw if format is Gif - public static string GetStorePageAssetUrl(Snowflake applicationId, ulong assetId, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the Store Page Asset Url + /// + /// Application ID of the icon + /// Asset ID + /// Format the icon is in + /// Url of the achievement icon + /// Throw if the format is GIF + public static string GetStorePageAssetUrl(Snowflake applicationId, ulong assetId, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - return $"{CdnUrl}/app-assets/{applicationId.ToString()}/store/{StringCache.Instance.ToString(assetId)}.{GetExtension(format)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Store Page Asset Url. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP => $"{CdnUrl}/app-assets/{applicationId.ToString()}/store/{StringCache.Instance.ToString(assetId)}.{GetExtension(format)}", + _ => throw new ArgumentException("ImageFormat is not valid for Store Page Asset Url. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)) + }; + } - /// - /// Returns the Url of the Team Icon - /// - /// Team ID of the Icon - /// Icon field from Team - /// Format the icon is in - /// Url of the achievement icon - /// Throw if format is Gif - public static string GetTeamIconUrl(Snowflake teamId, string teamIcon, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the Url of the Team Icon + /// + /// Team ID of the Icon + /// Icon field from Team + /// Format the icon is in + /// Url of the achievement icon + /// Throw if the format is GIF + public static string GetTeamIconUrl(Snowflake teamId, string teamIcon, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - return $"{CdnUrl}/team-icons/{teamId.ToString()}/{teamIcon}.{GetExtension(format, teamIcon)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Team Icon. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP => $"{CdnUrl}/team-icons/{teamId.ToString()}/{teamIcon}.{GetExtension(format, teamIcon)}", + _ => throw new ArgumentException("ImageFormat is not valid for Team Icon. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)) + }; + } - /// - /// Returns the banner for a given sticker pack - /// - /// Application ID for the stickers - /// Banner Asset ID for the stickers - /// Image Formatting for the banner - /// Url to the sticker pack banner - /// Thrown if image type is not PNG,JPEG, or WebP - public static string GetStickerPackBanner(Snowflake applicationId, Snowflake bannerAssetId, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the banner for a given sticker pack + /// + /// Application ID for the stickers + /// Banner Asset ID for the stickers + /// Image Formatting for the banner + /// Url to the sticker pack banner + /// Thrown if the image type is not PNG, JPEG, or WebP + public static string GetStickerPackBanner(Snowflake applicationId, Snowflake bannerAssetId, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - return $"{CdnUrl}/app-assets/{applicationId.ToString()}/store/{bannerAssetId.ToString()}.{GetExtension(format)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Sticker Pack Banner. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP => $"{CdnUrl}/app-assets/{applicationId.ToString()}/store/{bannerAssetId.ToString()}.{GetExtension(format)}", + _ => throw new ArgumentException("ImageFormat is not valid for Sticker Pack Banner. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)) + }; + } - /// - /// Returns the sticker url with the given ID - /// - /// Sticker to get the url for - /// Return url for the sticker - public static string GetSticker(DiscordSticker sticker) + /// + /// Returns the sticker url with the given ID + /// + /// Sticker to get the url for + /// Return url for the sticker + public static string GetSticker(DiscordSticker sticker) + { + if (sticker == null) throw new ArgumentNullException(nameof(sticker)); + return sticker.FormatType switch { - if (sticker == null) throw new ArgumentNullException(nameof(sticker)); - switch (sticker.FormatType) - { - case StickerFormatType.Png: - case StickerFormatType.Apng: - return $"{CdnUrl}/stickers/{sticker.Id.ToString()}.{GetExtension(DiscordImageFormat.Png)}"; - case StickerFormatType.Lottie: - return $"{CdnUrl}/stickers/{sticker.Id.ToString()}.{GetExtension(DiscordImageFormat.Lottie)}"; - case StickerFormatType.Gif: - return $"{CdnUrl}/stickers/{sticker.Id.ToString()}.{GetExtension(DiscordImageFormat.Gif)}"; - default: - throw new ArgumentException("Sticker does not container a valid format type", nameof(sticker.FormatType)); - } - } + StickerFormatType.Png or StickerFormatType.Apng => $"{CdnUrl}/stickers/{sticker.Id.ToString()}.{GetExtension(DiscordImageFormat.Png)}", + StickerFormatType.Lottie => $"{CdnUrl}/stickers/{sticker.Id.ToString()}.{GetExtension(DiscordImageFormat.Lottie)}", + StickerFormatType.Gif => $"{CdnUrl}/stickers/{sticker.Id.ToString()}.{GetExtension(DiscordImageFormat.Gif)}", + _ => throw new ArgumentException("Sticker does not container a valid format type", nameof(sticker.FormatType)) + }; + } - /// - /// Returns the sticker url with the given ID - /// - /// ID of the role - /// Format for the icon to be returned in - /// Return url for the role icon - /// Thrown if image type is not PNG or Lottie - public static string GetRoleIcon(Snowflake roleId, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the sticker url with the given ID + /// + /// ID of the role + /// Format for the icon to be returned in + /// Return url for the role icon + /// Thrown if the image type is not PNG or Lottie + public static string GetRoleIcon(Snowflake roleId, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - return $"{CdnUrl}/role-icons/{roleId.ToString()}.{GetExtension(format)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Role Icon. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP => $"{CdnUrl}/role-icons/{roleId.ToString()}.{GetExtension(format)}", + _ => throw new ArgumentException("ImageFormat is not valid for Role Icon. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)) + }; + } - /// - /// Returns the guild schedule event cover icon with the given ID - /// - /// Scheduled Event ID - /// Format for the icon to be returned in - /// Return url for the guild schedule event cover icon - /// Thrown if image type is not PNG or Lottie - public static string GetGuildScheduledEventCover(Snowflake scheduledEventId, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the guild schedule event cover icon with the given ID + /// + /// Scheduled Event ID + /// Format for the icon to be returned in + /// Return url for the guild schedule event cover icon + /// Thrown if the image type is not PNG or Lottie + public static string GetGuildScheduledEventCover(Snowflake scheduledEventId, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - return $"{CdnUrl}/guild-events/{scheduledEventId.ToString()}/scheduled_event_cover_image.{GetExtension(format)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Guild Scheduled Event Cover. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP => $"{CdnUrl}/guild-events/{scheduledEventId.ToString()}/scheduled_event_cover_image.{GetExtension(format)}", + _ => throw new ArgumentException("ImageFormat is not valid for Guild Scheduled Event Cover. Valid types are (Auto, Png, Jpeg, WebP)", nameof(format)) + }; + } - /// - /// Returns the guild member banner for the given guild / user ID - /// - /// Guild ID of the user - /// User ID of the user - /// Format for the icon to be returned in - /// Return url for the guild member banner - /// Thrown if image type is not PNG or Lottie - public static string GetGuildMemberBanner(Snowflake guildId, Snowflake userId, DiscordImageFormat format = DiscordImageFormat.Auto) + /// + /// Returns the guild member banner for the given guild / user ID + /// + /// Guild ID of the user + /// User ID of the user + /// Format for the icon to be returned in + /// Return url for the guild member banner + /// Thrown if the image type is not PNG or Lottie + public static string GetGuildMemberBanner(Snowflake guildId, Snowflake userId, DiscordImageFormat format = DiscordImageFormat.Auto) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Auto: - case DiscordImageFormat.Jpg: - case DiscordImageFormat.Png: - case DiscordImageFormat.WebP: - case DiscordImageFormat.Gif: - return $"{CdnUrl}/guilds/{guildId.ToString()}/users/{userId.ToString()}/banners/member_banner.{GetExtension(format)}"; - - default: - throw new ArgumentException("ImageFormat is not valid for Guild Member Banner. Valid types are (Auto, Png, Jpeg, WebP, Gif)", nameof(format)); - } - } + DiscordImageFormat.Auto or DiscordImageFormat.Jpg or DiscordImageFormat.Png or DiscordImageFormat.WebP or DiscordImageFormat.Gif => $"{CdnUrl}/guilds/{guildId.ToString()}/users/{userId.ToString()}/banners/member_banner.{GetExtension(format)}", + _ => throw new ArgumentException("ImageFormat is not valid for Guild Member Banner. Valid types are (Auto, Png, Jpeg, WebP, Gif)", nameof(format)) + }; + } - /// - /// Returns the icon for a given channel - /// - /// Channel ID for the Icon - /// Icon hash for the channel - /// - public static string GetChannelIcon(Snowflake channelId, string icon) - { - return $"{CdnUrl}/channel-icons/{channelId.ToString()}/{icon}.png"; - } + /// + /// Returns the icon for a given channel + /// + /// Channel ID for the Icon + /// Icon hash for the channel + /// + public static string GetChannelIcon(Snowflake channelId, string icon) + { + return $"{CdnUrl}/channel-icons/{channelId.ToString()}/{icon}.png"; + } - /// - /// Returns the extension to use for the image - /// - /// Image format that is requested - /// Image data from the field - /// Image extension for the image format and image data - /// Thrown if Image Format is out of range - public static string GetExtension(DiscordImageFormat format, string image) + /// + /// Returns the extension to use for the image + /// + /// Image format that is requested + /// Image data from the field + /// Image extension for the image format and image data + /// Thrown if Image Format is out of range + public static string GetExtension(DiscordImageFormat format, string image) + { + if (format == DiscordImageFormat.Auto) { - if (format == DiscordImageFormat.Auto) - { - format = image.StartsWith("a_") ? DiscordImageFormat.Gif : DiscordImageFormat.Png; - } - - return GetExtension(format); + format = image.StartsWith("a_") ? DiscordImageFormat.Gif : DiscordImageFormat.Png; } - private static string GetExtension(DiscordImageFormat format) + return GetExtension(format); + } + + private static string GetExtension(DiscordImageFormat format) + { + return format switch { - switch (format) - { - case DiscordImageFormat.Jpg: - return "jpeg"; - case DiscordImageFormat.Auto: - case DiscordImageFormat.Png: - return "png"; - case DiscordImageFormat.WebP: - return "webp"; - case DiscordImageFormat.Gif: - return "gif"; - case DiscordImageFormat.Lottie: - return "json"; - default: - throw new ArgumentOutOfRangeException(nameof(format), format.ToString(), "Format is not a valid ImageFormat"); - } - } + DiscordImageFormat.Jpg => "jpeg", + DiscordImageFormat.Auto or DiscordImageFormat.Png => "png", + DiscordImageFormat.WebP => "webp", + DiscordImageFormat.Gif => "gif", + DiscordImageFormat.Lottie => "json", + _ => throw new ArgumentOutOfRangeException(nameof(format), format.ToString(), "Format is not a valid ImageFormat") + }; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Helpers/DiscordFormatting.cs b/Oxide.Ext.Discord/Helpers/DiscordFormatting.cs index 94d0eb9bb..9ab607804 100644 --- a/Oxide.Ext.Discord/Helpers/DiscordFormatting.cs +++ b/Oxide.Ext.Discord/Helpers/DiscordFormatting.cs @@ -3,297 +3,289 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Helpers +namespace Oxide.Ext.Discord.Helpers; + +/// +/// Represents Message text formatting options +/// +public static class DiscordFormatting { /// - /// Represents Message text formatting options + /// Mention the user with the given user ID /// - public static class DiscordFormatting - { - /// - /// Mention the user with the given user ID - /// - /// User ID to mention - /// Mention user formatted string - public static string MentionUser(Snowflake userId) => $"<@{userId.ToString()}>"; + /// User ID to mention + /// Mention user formatted string + public static string MentionUser(Snowflake userId) => $"<@{userId.ToString()}>"; - /// - /// Mention the the channel with the given ID - /// - /// Channel ID to mention - /// Mention channel formatted string - public static string MentionChannel(Snowflake channelId) => $"<#{channelId.ToString()}>"; + /// + /// Mention the channel with the given ID + /// + /// Channel ID to mention + /// Mention channel formatted string + public static string MentionChannel(Snowflake channelId) => $"<#{channelId.ToString()}>"; - /// - /// Mention the the role with the given ID - /// - /// Role ID to mention - /// Mention role formatted string - public static string MentionRole(Snowflake roleId) => $"<@&{roleId.ToString()}>"; + /// + /// Mention the role with the given ID + /// + /// Role ID to mention + /// Mention role formatted string + public static string MentionRole(Snowflake roleId) => $"<@&{roleId.ToString()}>"; - /// - /// Mention the the Application command - /// - /// Application Command ID - /// Name of the command - /// Sub Command Name (Optional) - /// Sub Command Group (Optional) - /// Mentions the application command - public static string MentionApplicationCommand(Snowflake commandId, string name, string subCommand = null, string group = null) + /// + /// Mention the Application command + /// + /// Application Command ID + /// Name of the command + /// Sub Command Name (Optional) + /// Sub Command Group (Optional) + /// Mentions the application command + public static string MentionApplicationCommand(Snowflake commandId, string name, string subCommand = null, string group = null) + { + InvalidSnowflakeException.ThrowIfInvalid(commandId); + if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); + if (!string.IsNullOrEmpty(subCommand)) { - InvalidSnowflakeException.ThrowIfInvalid(commandId, nameof(commandId)); - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - if (!string.IsNullOrEmpty(subCommand)) + if (!string.IsNullOrEmpty(group)) { - if (!string.IsNullOrEmpty(group)) - { - return $""; - } - - return $""; + return $""; } - return $""; + + return $""; } + return $""; + } - /// - /// Mention the application command using a custom command string - /// - /// Application Command ID - /// Custom Command String - /// - public static string MentionApplicationCommandCustom(Snowflake commandId, string command) - { - return $""; - } + /// + /// Mention the application command using a custom command string + /// + /// Application Command ID + /// Custom Command String + /// + public static string MentionApplicationCommandCustom(Snowflake commandId, string command) + { + return $""; + } - /// - /// Return the emoji string for a message - /// - /// Emoji to create as a string - /// Emoji message string - public static string EmojiMessageString(DiscordEmoji emoji) + /// + /// Return the emoji string for a message + /// + /// Emoji to create as a string + /// Emoji message string + public static string EmojiMessageString(DiscordEmoji emoji) + { + if (!emoji.EmojiId.HasValue) { - if (!emoji.EmojiId.HasValue) - { - return emoji.Name; - } - - return CustomEmojiMessageString(emoji.Id, emoji.Name, emoji.Animated ?? false); + return emoji.Name; } - /// - /// Returns formatting string for custom emoji to be used in a message - /// - /// Name of the custom emoji - /// ID of the custom emoji - /// If the emoji is animated - /// Custom emoji formatted string - public static string CustomEmojiMessageString(Snowflake id, string name, bool animated) => $"<{CustomEmojiDataString(id, name, animated)}>"; + return CustomEmojiMessageString(emoji.Id, emoji.Name, emoji.Animated ?? false); + } + + /// + /// Returns formatting string for custom emoji to be used in a message + /// + /// Name of the custom emoji + /// ID of the custom emoji + /// If the emoji is animated + /// Custom emoji formatted string + public static string CustomEmojiMessageString(Snowflake id, string name, bool animated) => $"<{CustomEmojiDataString(id, name, animated)}>"; - /// - /// Returns formatting string for custom emoji to be used in a url - /// - /// Name of the custom emoji - /// ID of the custom emoji - /// If the emoji is animated - /// Custom emoji formatted string - public static string CustomEmojiDataString(Snowflake id, string name, bool animated) => $"{(animated ? "a" : "")}:{name}:{id.ToString()}"; + /// + /// Returns formatting string for custom emoji to be used in a url + /// + /// Name of the custom emoji + /// ID of the custom emoji + /// If the emoji is animated + /// Custom emoji formatted string + public static string CustomEmojiDataString(Snowflake id, string name, bool animated) => $"{(animated ? "a" : "")}:{name}:{id.ToString()}"; - /// - /// Displays a timestamp - /// - /// Time to display - /// Style of the timestamp - /// - public static string UnixTimestamp(DateTimeOffset time, TimestampStyles style = TimestampStyles.ShortDateTime) => UnixTimestamp(time.ToUnixTimeSeconds(), style); + /// + /// Displays a timestamp + /// + /// Time to display + /// Style of the timestamp + /// + public static string UnixTimestamp(DateTimeOffset time, TimestampStyles style = TimestampStyles.ShortDateTime) => UnixTimestamp(time.ToUnixTimeSeconds(), style); - /// - /// Displays a timestamp - /// - /// UNIX Timestamp - /// Display style for the timestamp - /// - public static string UnixTimestamp(long timestamp, TimestampStyles style = TimestampStyles.ShortDateTime) - { - return $""; - } + /// + /// Displays a timestamp + /// + /// UNIX Timestamp + /// Display style for the timestamp + /// + public static string UnixTimestamp(long timestamp, TimestampStyles style = TimestampStyles.ShortDateTime) + { + return $""; + } - private static char GetTimestampFlag(TimestampStyles style) + private static char GetTimestampFlag(TimestampStyles style) + { + return style switch { - switch (style) - { - case TimestampStyles.ShortTime: - return 't'; - case TimestampStyles.LongTime: - return 'T'; - case TimestampStyles.ShortDate: - return 'd'; - case TimestampStyles.LongDate: - return 'D'; - case TimestampStyles.ShortDateTime: - return 'f'; - case TimestampStyles.LongDateTime: - return 'F'; - case TimestampStyles.RelativeTime: - return 'R'; - } + TimestampStyles.ShortTime => 't', + TimestampStyles.LongTime => 'T', + TimestampStyles.ShortDate => 'd', + TimestampStyles.LongDate => 'D', + TimestampStyles.ShortDateTime => 'f', + TimestampStyles.LongDateTime => 'F', + TimestampStyles.RelativeTime => 'R', + _ => 'f' + }; - return 'f'; - } + } - /// - /// Guild Navigation Format - /// - /// Type to navigate to - /// string with navigation to the navigation type - public static string GuildNavigation(GuildNavigationType type) - { - return $".Instance.ToLower(type)}>"; - } + /// + /// Guild Navigation Format + /// + /// Type to navigate to + /// string with navigation to the navigation type + public static string GuildNavigation(GuildNavigationType type) + { + return $".Instance.ToLower(type)}>"; + } - /// - /// Will display the message in italics - /// - /// Message to make italics - /// Italics formatted message - public static string Italics(string message) => $"*{message}*"; + /// + /// Will display the message in italics + /// + /// Message to make italics + /// Italics formatted message + public static string Italics(string message) => $"*{message}*"; - /// - /// Will display the message in bold - /// - /// Message to make bold - /// Bold formatted message - public static string Bold(string message) => $"**{message}**"; + /// + /// Will display the message in bold + /// + /// Message to make bold + /// Bold formatted message + public static string Bold(string message) => $"**{message}**"; - /// - /// Will display the message in italics and bold - /// - /// Message to make italics and bold - /// Bold and Italics formatted message - public static string ItalicsBold(string message) => $"***{message}***"; + /// + /// Will display the message in italics and bold + /// + /// Message to make italics and bold + /// Bold and Italics formatted message + public static string ItalicsBold(string message) => $"***{message}***"; - /// - /// Will display the message in underline - /// - /// Message to make underline - /// Underline formatted message - public static string Underline(string message) => $"__{message}__"; + /// + /// Will display the message in underline + /// + /// Message to make underline + /// Underline formatted message + public static string Underline(string message) => $"__{message}__"; - /// - /// Will display the message in underline and italics - /// - /// Message to make underline and italics - /// Underline and Italics formatted message - public static string UnderlineItalics(string message) => $"__*{message}*__"; + /// + /// Will display the message in underline and italics + /// + /// Message to make underline and italics + /// Underline and Italics formatted message + public static string UnderlineItalics(string message) => $"__*{message}*__"; - /// - /// Will display the message in underline and bold - /// - /// Message to make underline and bold - /// Underline and bold formatted message - public static string UnderlineBold(string message) => $"__**{message}**__"; + /// + /// Will display the message in underline and bold + /// + /// Message to make underline and bold + /// Underline and bold formatted message + public static string UnderlineBold(string message) => $"__**{message}**__"; - /// - /// Will display the message in underline and bold and italics - /// - /// Message to make underline and bold and italics - /// Underline and Bold and Italics formatted message - public static string UnderlineBoldItalics(string message) => $"__***{message}***__"; + /// + /// Will display the message in underline and bold and italics + /// + /// Message to make underline and bold and italics + /// Underline and Bold and Italics formatted message + public static string UnderlineBoldItalics(string message) => $"__***{message}***__"; - /// - /// Will display the message with a strikethrough - /// - /// Message to make strikethrough - /// Strikethrough formatted message - public static string Strikethrough(string message) => $"~~{message}~~"; + /// + /// Will display the message with a strikethrough + /// + /// Message to make strikethrough + /// Strikethrough formatted message + public static string Strikethrough(string message) => $"~~{message}~~"; - /// - /// Will display the message as a one line code block - /// - /// Message to make code block - /// Code block formatted message - public static string CodeBlockOneLine(string message) => $"`{message}`"; + /// + /// Will display the message as a one-line code block + /// + /// Message to make code block + /// Code block formatted message + public static string CodeBlockOneLine(string message) => $"`{message}`"; - /// - /// Will display the message as a multiline code block - /// - /// Message to make multiline code block - /// Code block formatted message - public static string CodeBlockMultiLine(string message) => $"```\n{message}\n```"; + /// + /// Will display the message as a multiline code block + /// + /// Message to make multiline code block + /// Code block formatted message + public static string CodeBlockMultiLine(string message) => $"```\n{message}\n```"; - /// - /// Will display a multiline code bloc with the specified language - /// - /// Message to make code block with language - /// Language to display the code block as - /// Language code block formatted message - public static string CodeBlockLanguage(string message, string language) => $"```{language}\n{message}\n```"; + /// + /// Will display a multiline code bloc with the specified language + /// + /// Message to make code block with language + /// Language to display the code block as + /// Language code block formatted message + public static string CodeBlockLanguage(string message, string language) => $"```{language}\n{message}\n```"; - /// - /// Will display the message in single line block quote - /// - /// Message to make block quote - /// Block Quote formatted message - public static string BlockQuoteSingleLine(string message) => $"> {message}"; + /// + /// Will display the message in single line block quote + /// + /// Message to make block quote + /// Block Quote formatted message + public static string BlockQuoteSingleLine(string message) => $"> {message}"; - /// - /// Will display the message in multiline block quote - /// - /// Message to make block quote - /// Multiline block quote formatted message - public static string BlockQuoteMultiLine(string message) => $">>> {message}"; + /// + /// Will display the message in multiline block quote + /// + /// Message to make block quote + /// Multiline block quote formatted message + public static string BlockQuoteMultiLine(string message) => $">>> {message}"; - /// - /// Will display the text as a spoiler - /// - /// Message to make Spoiler - /// Spoiler message - public static string Spoiler(string message) => $"||{message}||"; + /// + /// Will display the text as a spoiler + /// + /// Message to make Spoiler + /// Spoiler message + public static string Spoiler(string message) => $"||{message}||"; - /// - /// Creates a Big Header - /// - /// text for the header - /// - public static string Header1(string header) => $"# {header}"; + /// + /// Creates a Big Header + /// + /// text for the header + /// + public static string Header1(string header) => $"# {header}"; - /// - /// Creates a Medium Header - /// - /// text for the header - /// - public static string Header2(string header) => $"## {header}"; + /// + /// Creates a Medium Header + /// + /// text for the header + /// + public static string Header2(string header) => $"## {header}"; - /// - /// Creates a Small Header - /// - /// text for the header - /// - public static string Header3(string header) => $"### {header}"; + /// + /// Creates a Small Header + /// + /// text for the header + /// + public static string Header3(string header) => $"### {header}"; - /// - /// Creates a clickable link displayed as the mask text - /// - /// Text to display the link as - /// Url for the link - /// - public static string MaskLink(string mask, string url) => $"[{mask}]({url})"; + /// + /// Creates a clickable link displayed as the mask text + /// + /// Text to display the link as + /// Url for the link + /// + public static string MaskLink(string mask, string url) => $"[{mask}]({url})"; - /// - /// Creates a list item for the given message - /// - /// Text for the list - /// If the list should be indented a level - /// - public static string List(string message, bool indent) => $"{(indent ? " " : string.Empty)}- {message}"; + /// + /// Creates a list item for the given message + /// + /// Text for the list + /// If the list should be indented a level + /// + public static string List(string message, bool indent) => $"{(indent ? " " : string.Empty)}- {message}"; - /// - /// Creates a list item for the given message - /// - /// Text for the list - /// Number to display - /// If the list should be indented a level - /// - public static string NumberedList(string message, int number, bool indent) => $"{(indent ? " " : string.Empty)}{StringCache.Instance.ToString(number)} {message}"; - } + /// + /// Creates a list item for the given message + /// + /// Text for the list + /// Number to display + /// If the list should be indented a level + /// + public static string NumberedList(string message, int number, bool indent) => $"{(indent ? " " : string.Empty)}{StringCache.Instance.ToString(number)} {message}"; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Helpers/ServerFormatting.cs b/Oxide.Ext.Discord/Helpers/ServerFormatting.cs index 89770ba42..b036e1945 100644 --- a/Oxide.Ext.Discord/Helpers/ServerFormatting.cs +++ b/Oxide.Ext.Discord/Helpers/ServerFormatting.cs @@ -1,49 +1,48 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Helpers +namespace Oxide.Ext.Discord.Helpers; + +/// +/// Server Text Formatting +/// +public static class ServerFormatting { /// - /// Server Text Formatting + /// Color Text with the given color /// - public static class ServerFormatting - { - /// - /// Color Text with the given color - /// - /// Text to color - /// Color of the text - /// - public static string Color(this string text, DiscordColor color) => $"[{color.ToHex()}]{text}[/#]"; + /// Text to color + /// Color of the text + /// + public static string Color(this string text, DiscordColor color) => $"[{color.ToHex()}]{text}[/#]"; - /// - /// Color the placeholder text with a given color - /// - /// PlaceholderKey to color - /// Color of the text - /// - public static string Color(this PlaceholderKey key, DiscordColor color) => $"[{color.ToHex()}]{key.ToString()}[/#]"; + /// + /// Color the placeholder text with a given color + /// + /// PlaceholderKey to color + /// Color of the text + /// + public static string Color(this PlaceholderKey key, DiscordColor color) => $"[{color.ToHex()}]{key.ToString()}[/#]"; - /// - /// Bold the Text - /// - /// - /// Bold text formatting - public static string Bold(this string text) => $"[b]{text}[/b]"; + /// + /// Bold the Text + /// + /// + /// Bold text formatting + public static string Bold(this string text) => $"[b]{text}[/b]"; - /// - /// Italics the Text - /// - /// - /// Italic text formatting - public static string Italic(this string text) => $"[i]{text}[/i]"; + /// + /// Italics the Text + /// + /// + /// Italic text formatting + public static string Italic(this string text) => $"[i]{text}[/i]"; - /// - /// Font size formatted text - /// - /// - /// Font size for the text - /// Font size text formatting - public static string Size(this string text, int size) => $"[+{size}]{text}[/+]"; - } + /// + /// Font size formatted text + /// + /// + /// Font size for the text + /// Font size text formatting + public static string Size(this string text, int size) => $"[+{size}]{text}[/+]"; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Helpers/SettingsPage.cs b/Oxide.Ext.Discord/Helpers/SettingsPage.cs index 113401e18..c1c803970 100644 --- a/Oxide.Ext.Discord/Helpers/SettingsPage.cs +++ b/Oxide.Ext.Discord/Helpers/SettingsPage.cs @@ -1,173 +1,172 @@ -namespace Oxide.Ext.Discord.Helpers +namespace Oxide.Ext.Discord.Helpers; + +/// +/// App Settings Pages +/// +public enum SettingsPage { /// - /// App Settings Pages - /// - public enum SettingsPage - { - /// - /// Account Page - /// - Account, - - /// - /// Profile Customization Page - /// - ProfileCustomization, - - /// - /// Privacy and Safety Page - /// - PrivacyAndSafety, - - /// - /// Family Center Page - /// - FamilyCenter, - - /// - /// Authorized Apps Page - /// - AuthorizedApps, - - /// - /// Connections Page - /// - Connections, - - /// - /// Sessions Page - /// - Sessions, - - /// - /// Friend Requests Page - /// - FriendRequests, - - /// - /// Premium Page - /// - Premium, - - /// - /// Premium Guild Subscriptions Page - /// - PremiumGuildSubscriptions, - - /// - /// Subscriptions Page - /// - Subscriptions, - - /// - /// Inventory Page - /// - Inventory, - - /// - /// Billing Page - /// - Billing, - - /// - /// Appearance Page - /// - Appearance, - - /// - /// Accessibility Page - /// - Accessibility, - - /// - /// Voice Page - /// - Voice, - - /// - /// Text Page - /// - Text, - - /// - /// Notifications Page - /// - Notifications, - - /// - /// Keybinds Page - /// - Keybinds, - - /// - /// Locale Page - /// - Locale, - - /// - /// Windows Page - /// - Windows, - - /// - /// Linux Page - /// - Linux, - - /// - /// Streamer Mode Page - /// - StreamerMode, - - /// - /// Advanced Page - /// - Advanced, - - /// - /// Activity Status Page - /// - ActivityStatus, - - /// - /// Registered Games Page - /// - RegisteredGames, - - /// - /// Overlay - /// - Overlay, - - /// - /// Hype Squad Online Page - /// - HypesquadOnline, - - /// - /// Changelogs page - /// - Changelogs, - - /// - /// Experiments Page - /// - Experiments, - - /// - /// Developer Options Page - /// - DeveloperOptions, - - /// - /// Hotspot Options Page - /// - HotspotOptions, - - /// - /// Dismissible Content Options Page - /// - DismissibleContentOptions - } + /// Account Page + /// + Account, + + /// + /// Profile Customization Page + /// + ProfileCustomization, + + /// + /// Privacy and Safety Page + /// + PrivacyAndSafety, + + /// + /// Family Center Page + /// + FamilyCenter, + + /// + /// Authorized Apps Page + /// + AuthorizedApps, + + /// + /// Connections Page + /// + Connections, + + /// + /// Sessions Page + /// + Sessions, + + /// + /// Friend Requests Page + /// + FriendRequests, + + /// + /// Premium Page + /// + Premium, + + /// + /// Premium Guild Subscriptions Page + /// + PremiumGuildSubscriptions, + + /// + /// Subscriptions Page + /// + Subscriptions, + + /// + /// Inventory Page + /// + Inventory, + + /// + /// Billing Page + /// + Billing, + + /// + /// Appearance Page + /// + Appearance, + + /// + /// Accessibility Page + /// + Accessibility, + + /// + /// Voice Page + /// + Voice, + + /// + /// Text Page + /// + Text, + + /// + /// Notifications Page + /// + Notifications, + + /// + /// Keybinds Page + /// + Keybinds, + + /// + /// Locale Page + /// + Locale, + + /// + /// Windows Page + /// + Windows, + + /// + /// Linux Page + /// + Linux, + + /// + /// Streamer Mode Page + /// + StreamerMode, + + /// + /// Advanced Page + /// + Advanced, + + /// + /// Activity Status Page + /// + ActivityStatus, + + /// + /// Registered Games Page + /// + RegisteredGames, + + /// + /// Overlay + /// + Overlay, + + /// + /// Hype Squad Online Page + /// + HypesquadOnline, + + /// + /// Changelogs page + /// + Changelogs, + + /// + /// Experiments Page + /// + Experiments, + + /// + /// Developer Options Page + /// + DeveloperOptions, + + /// + /// Hotspot Options Page + /// + HotspotOptions, + + /// + /// Dismissible Content Options Page + /// + DismissibleContentOptions } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Helpers/TimestampStyles.cs b/Oxide.Ext.Discord/Helpers/TimestampStyles.cs index 023f34d66..a79e5ead6 100644 --- a/Oxide.Ext.Discord/Helpers/TimestampStyles.cs +++ b/Oxide.Ext.Discord/Helpers/TimestampStyles.cs @@ -1,50 +1,49 @@ -namespace Oxide.Ext.Discord.Helpers +namespace Oxide.Ext.Discord.Helpers; + +/// +/// Available flags for timestamp formatting +/// +public enum TimestampStyles : byte { /// - /// Available flags for timestamp formatting + /// Displays the short time for the timestamp + /// Ex: 16:20 /// - public enum TimestampStyles : byte - { - /// - /// Displays the short time for the timestamp - /// Ex: 16:20 - /// - ShortTime, + ShortTime, - /// - /// Displays the long time for the timestamp - /// Ex: 16:20:30 - /// - LongTime, + /// + /// Displays the long time for the timestamp + /// Ex: 16:20:30 + /// + LongTime, - /// - /// Displays the short date for the timestamp - /// Ex: 20/04/2021 - /// - ShortDate, + /// + /// Displays the short date for the timestamp + /// Ex: 20/04/2021 + /// + ShortDate, - /// - /// Displays the long date for the timestamp - /// Ex: 20 April 2021 - /// - LongDate, + /// + /// Displays the long date for the timestamp + /// Ex: 20 April 2021 + /// + LongDate, - /// - /// Displays the short date/time for the timestamp - /// Ex: 20 April 2021 16:20 - /// - ShortDateTime, + /// + /// Displays the short date/time for the timestamp + /// Ex: 20 April 2021 16:20 + /// + ShortDateTime, - /// - /// Displays the long date/time for the timestamp - /// Ex: Tuesday, 20 April 2021 16:20 - /// - LongDateTime, + /// + /// Displays the long date/time for the timestamp + /// Ex: Tuesday, 20 April 2021 16:20 + /// + LongDateTime, - /// - /// Displays the relative time since the timestamp - /// Ex: 2 months ago - /// - RelativeTime - } + /// + /// Displays the relative time since the timestamp + /// Ex: 2 months ago + /// + RelativeTime } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Entities/Messages/IDiscordMessageTemplate.cs b/Oxide.Ext.Discord/Interfaces/Entities/Messages/IDiscordMessageTemplate.cs index 24ba680f6..3bcc8c61c 100644 --- a/Oxide.Ext.Discord/Interfaces/Entities/Messages/IDiscordMessageTemplate.cs +++ b/Oxide.Ext.Discord/Interfaces/Entities/Messages/IDiscordMessageTemplate.cs @@ -2,32 +2,31 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Interfaces for Messages +/// +public interface IDiscordMessageTemplate { /// - /// Interfaces for Messages + /// Content of the message /// - public interface IDiscordMessageTemplate - { - /// - /// Content of the message - /// - string Content { get; set; } + string Content { get; set; } - /// - /// Allowed mentions for a message - /// Allows for more granular control over mentions without various hacks to the message content. - /// - AllowedMentions AllowedMentions { get; set; } + /// + /// Allowed mentions for a message + /// Allows for more granular control over mentions without various hacks to the message content. + /// + AllowedMentions AllowedMentions { get; set; } - /// - /// Embeds for the message - /// - List Embeds { get; set; } + /// + /// Embeds for the message + /// + List Embeds { get; set; } - /// - /// Components for the message - /// - List Components { get; set; } - } + /// + /// Components for the message + /// + List Components { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/IDiscordCacheable.cs b/Oxide.Ext.Discord/Interfaces/IDiscordCacheable.cs index 6158cae68..b91824bf0 100644 --- a/Oxide.Ext.Discord/Interfaces/IDiscordCacheable.cs +++ b/Oxide.Ext.Discord/Interfaces/IDiscordCacheable.cs @@ -1,22 +1,21 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents entities that are cacheable by the DiscordExtension +/// +/// +public interface IDiscordCacheable { /// - /// Represents entities that are cacheable by the DiscordExtension + /// ID of the entity /// - /// - public interface IDiscordCacheable - { - /// - /// Id of the entity - /// - Snowflake Id { get; set; } + Snowflake Id { get; set; } - /// - /// Method to update the entity - /// - /// Update data to apply - void Update(T update); - } + /// + /// Method to update the entity + /// + /// Update data to apply + void Update(T update); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/IDiscordKey.cs b/Oxide.Ext.Discord/Interfaces/IDiscordKey.cs index b351d913b..573967366 100644 --- a/Oxide.Ext.Discord/Interfaces/IDiscordKey.cs +++ b/Oxide.Ext.Discord/Interfaces/IDiscordKey.cs @@ -1,14 +1,13 @@ -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents a Key in Discord +/// +public interface IDiscordKey { /// - /// Represents a Key in Discord + /// Converts the key to a string /// - public interface IDiscordKey - { - /// - /// Converts the key to a string - /// - /// - string ToString(); - } + /// + string ToString(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/IDiscordQueryString.cs b/Oxide.Ext.Discord/Interfaces/IDiscordQueryString.cs index 4f3bbdc78..b06a40989 100644 --- a/Oxide.Ext.Discord/Interfaces/IDiscordQueryString.cs +++ b/Oxide.Ext.Discord/Interfaces/IDiscordQueryString.cs @@ -1,14 +1,13 @@ -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Interface for Discord Query Strings +/// +public interface IDiscordQueryString { /// - /// Interface for Discord Query Strings + /// Returns the request as a query string /// - public interface IDiscordQueryString - { - /// - /// Returns the request as a query string - /// - /// - string ToQueryString(); - } + /// + string ToQueryString(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/IDiscordValidation.cs b/Oxide.Ext.Discord/Interfaces/IDiscordValidation.cs index 733013795..fa3891cfa 100644 --- a/Oxide.Ext.Discord/Interfaces/IDiscordValidation.cs +++ b/Oxide.Ext.Discord/Interfaces/IDiscordValidation.cs @@ -1,13 +1,12 @@ using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +internal interface IDiscordValidation { - internal interface IDiscordValidation - { - /// - /// Validates data being passed to the discord API. - /// Throws an exception with base type of if the validation fails - /// - void Validate(); - } + /// + /// Validates data being passed to the discord API. + /// Throws an exception with a base type of if the validation fails + /// + void Validate(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/IFileAttachments.cs b/Oxide.Ext.Discord/Interfaces/IFileAttachments.cs index 9177a1f6a..46daec2f0 100644 --- a/Oxide.Ext.Discord/Interfaces/IFileAttachments.cs +++ b/Oxide.Ext.Discord/Interfaces/IFileAttachments.cs @@ -1,16 +1,15 @@ using System.Collections.Generic; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents and interface for entities that can upload files +/// +public interface IFileAttachments { /// - /// Represents and interface for entities that can upload files + /// File attachments for an entity /// - public interface IFileAttachments - { - /// - /// File attachments for an entity - /// - List FileAttachments { get; } - } + List FileAttachments { get; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/ISnowflakeEntity.cs b/Oxide.Ext.Discord/Interfaces/ISnowflakeEntity.cs index 4b5d8bc73..b0693f1a9 100644 --- a/Oxide.Ext.Discord/Interfaces/ISnowflakeEntity.cs +++ b/Oxide.Ext.Discord/Interfaces/ISnowflakeEntity.cs @@ -1,16 +1,15 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Interface used to get the entity ID from an entity +/// +public interface ISnowflakeEntity { /// - /// Interface used to get the entity ID from an entity + /// Returns the unique ID for this entity /// - public interface ISnowflakeEntity - { - /// - /// Returns the unique ID for this entity - /// - /// - Snowflake Id { get; } - } + /// + Snowflake Id { get; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Logging/IDebugLoggable.cs b/Oxide.Ext.Discord/Interfaces/Logging/IDebugLoggable.cs index 744bc6b22..5bd0ed16f 100644 --- a/Oxide.Ext.Discord/Interfaces/Logging/IDebugLoggable.cs +++ b/Oxide.Ext.Discord/Interfaces/Logging/IDebugLoggable.cs @@ -1,16 +1,15 @@ using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents an object that supports debug logging +/// +public interface IDebugLoggable { /// - /// Represents an object that supports debug logging + /// Logs a debug message for the object /// - public interface IDebugLoggable - { - /// - /// Logs a debug message for the object - /// - /// Current debug logger - void LogDebug(DebugLogger logger); - } + /// Current debug logger + void LogDebug(DebugLogger logger); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Logging/IDiscordLoggingConfig.cs b/Oxide.Ext.Discord/Interfaces/Logging/IDiscordLoggingConfig.cs index 186bcf96b..a62334e36 100644 --- a/Oxide.Ext.Discord/Interfaces/Logging/IDiscordLoggingConfig.cs +++ b/Oxide.Ext.Discord/Interfaces/Logging/IDiscordLoggingConfig.cs @@ -1,25 +1,24 @@ using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Interface for Discord Logging Configuration +/// +public interface IDiscordLoggingConfig { /// - /// Interface for Discord Logging Configuration + /// Log Level for the Console /// - public interface IDiscordLoggingConfig - { - /// - /// Log Level for the Console - /// - DiscordLogLevel ConsoleLogLevel { get; } + DiscordLogLevel ConsoleLogLevel { get; } - /// - /// Log Level for file Logging - /// - DiscordLogLevel FileLogLevel { get; } + /// + /// Log Level for file Logging + /// + DiscordLogLevel FileLogLevel { get; } - /// - /// File Logging DateTime format - /// - string FileDateTimeFormat { get; } - } + /// + /// File Logging DateTime format + /// + string FileDateTimeFormat { get; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Logging/ILogger.cs b/Oxide.Ext.Discord/Interfaces/Logging/ILogger.cs index b873e5839..91ddc3fe5 100644 --- a/Oxide.Ext.Discord/Interfaces/Logging/ILogger.cs +++ b/Oxide.Ext.Discord/Interfaces/Logging/ILogger.cs @@ -1,57 +1,56 @@ using System; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents an interface for a logger +/// +public interface ILogger { /// - /// Represents an interface for a logger + /// Current Log level of the logger /// - public interface ILogger - { - /// - /// Current Log level of the logger - /// - DiscordLogLevel LogLevel { get; } + DiscordLogLevel LogLevel { get; } - /// - /// Updates the log level for the current logger - /// - /// Level to update the logger to - void UpdateLogLevel(DiscordLogLevel level); + /// + /// Updates the log level for the current logger + /// + /// Level to update the logger to + void UpdateLogLevel(DiscordLogLevel level); - /// - /// Returns true if the logger is logging for the passed log level - /// - /// Log Level to check - /// True if the logger is logging for the given log level - bool IsLogging(DiscordLogLevel level); + /// + /// Returns true if the logger is logging for the passed log level + /// + /// Log Level to check + /// True if the logger is logging for the given log level + bool IsLogging(DiscordLogLevel level); - /// - /// Returns if the logger is logging for server console - /// - /// - /// - bool IsConsoleLogging(DiscordLogLevel level); + /// + /// Returns if the logger is logging for server console + /// + /// + /// + bool IsConsoleLogging(DiscordLogLevel level); - /// - /// Returns if the logger is logging for file logger - /// - /// - /// - bool IsFileLogging(DiscordLogLevel level); + /// + /// Returns if the logger is logging for file logger + /// + /// + /// + bool IsFileLogging(DiscordLogLevel level); - /// - /// Log the message with the specified level - /// - /// Log Level for the message - /// Message format to log - /// Message args - /// Exception for the log - void Log(DiscordLogLevel level, string log, object[] args, Exception exception = null); + /// + /// Log the message with the specified level + /// + /// Log Level for the message + /// Message format to log + /// Message args + /// Exception for the log + void Log(DiscordLogLevel level, string log, object[] args, Exception exception = null); - /// - /// Shuts down the logger - /// - void Shutdown(); - } + /// + /// Shuts down the logger + /// + void Shutdown(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Logging/IOutputLogger.cs b/Oxide.Ext.Discord/Interfaces/Logging/IOutputLogger.cs index 27d87636f..a5b226779 100644 --- a/Oxide.Ext.Discord/Interfaces/Logging/IOutputLogger.cs +++ b/Oxide.Ext.Discord/Interfaces/Logging/IOutputLogger.cs @@ -1,25 +1,24 @@ using System; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents a specific logger output +/// +public interface IOutputLogger { /// - /// Represents a specific logger output + /// Adds a message to the logger /// - public interface IOutputLogger - { - /// - /// Adds a message to the logger - /// - /// - /// - /// - /// - void AddMessage(DiscordLogLevel level, string log, object[] args, Exception ex); + /// + /// + /// + /// + void AddMessage(DiscordLogLevel level, string log, object[] args, Exception ex); - /// - /// Shuts down the logger output - /// - void OnShutdown(); - } + /// + /// Shuts down the logger output + /// + void OnShutdown(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Plugins/IDiscordPlugin.cs b/Oxide.Ext.Discord/Interfaces/Plugins/IDiscordPlugin.cs index db706f54e..e989ea1fe 100644 --- a/Oxide.Ext.Discord/Interfaces/Plugins/IDiscordPlugin.cs +++ b/Oxide.Ext.Discord/Interfaces/Plugins/IDiscordPlugin.cs @@ -1,15 +1,14 @@ using Oxide.Ext.Discord.Clients; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents a plugin that uses the Discord Extension +/// +public interface IDiscordPlugin : IPluginBase { /// - /// Represents a plugin that uses the Discord Extension + /// Gets / Sets the DiscordClient on a plugin /// - public interface IDiscordPlugin : IPluginBase - { - /// - /// Gets / Sets the DiscordClient on a plugin - /// - DiscordClient Client { get; set; } - } + DiscordClient Client { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Plugins/IDiscordPool.cs b/Oxide.Ext.Discord/Interfaces/Plugins/IDiscordPool.cs index 78b527c72..a39415ea7 100644 --- a/Oxide.Ext.Discord/Interfaces/Plugins/IDiscordPool.cs +++ b/Oxide.Ext.Discord/Interfaces/Plugins/IDiscordPool.cs @@ -1,15 +1,14 @@ using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Interface for plugins to use that need access to a pool +/// +public interface IDiscordPool { /// - /// Interface for plugins to use that need access to a pool + /// Pool for plugins to use /// - public interface IDiscordPool - { - /// - /// Pool for plugins to use - /// - DiscordPluginPool Pool { get; set; } - } + DiscordPluginPool Pool { get; set; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Plugins/IPluginBase.cs b/Oxide.Ext.Discord/Interfaces/Plugins/IPluginBase.cs index 2d43f56aa..1eb9fa645 100644 --- a/Oxide.Ext.Discord/Interfaces/Plugins/IPluginBase.cs +++ b/Oxide.Ext.Discord/Interfaces/Plugins/IPluginBase.cs @@ -1,35 +1,34 @@ using Oxide.Core; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents an interface for a plugin +/// +public interface IPluginBase { /// - /// Represents an interface for a plugin + /// Name of the plugin /// - public interface IPluginBase - { - /// - /// Name of the plugin - /// - string Name { get; } + string Name { get; } - /// - /// Title of the plugin - /// - string Title { get; } + /// + /// Title of the plugin + /// + string Title { get; } - /// - /// Description of the plugin - /// - string Description { get; } + /// + /// Description of the plugin + /// + string Description { get; } - /// - /// Author of the plugin - /// - string Author { get; } + /// + /// Author of the plugin + /// + string Author { get; } - /// - /// Version of the plugin - /// - VersionNumber Version { get; } - } + /// + /// Version of the plugin + /// + VersionNumber Version { get; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Promises/IPendingPromise.cs b/Oxide.Ext.Discord/Interfaces/Promises/IPendingPromise.cs index f8d12d8d0..fbe2f5a7d 100644 --- a/Oxide.Ext.Discord/Interfaces/Promises/IPendingPromise.cs +++ b/Oxide.Ext.Discord/Interfaces/Promises/IPendingPromise.cs @@ -1,16 +1,15 @@ // Originally from: https://github.com/Real-Serious-Games/C-Sharp-Promise // Modified by: MJSU -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents a promise the is still pending waiting to be resolved +/// +public interface IPendingPromise : IPromise, IRejectable { /// - /// Represents a promise the is still pending waiting to be resolved + /// Resolves the promise /// - public interface IPendingPromise : IPromise, IRejectable - { - /// - /// Resolves the promise - /// - void Resolve(); - } + void Resolve(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Promises/IPendingPromise{T}.cs b/Oxide.Ext.Discord/Interfaces/Promises/IPendingPromise{T}.cs index ad6d78bb6..289c439f0 100644 --- a/Oxide.Ext.Discord/Interfaces/Promises/IPendingPromise{T}.cs +++ b/Oxide.Ext.Discord/Interfaces/Promises/IPendingPromise{T}.cs @@ -1,18 +1,17 @@ // Originally from: https://github.com/Real-Serious-Games/C-Sharp-Promise // Modified by: MJSU -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents a promise waiting to be resolved +/// +/// Type of the resolved value +public interface IPendingPromise : IPromise, IRejectable { /// - /// Represents a promise waiting to be resolved + /// Resolves the promise with the given value /// - /// Type of the resolved value - public interface IPendingPromise : IPromise, IRejectable - { - /// - /// Resolves the promise with the given value - /// - /// - void Resolve(TPromised value); - } + /// + void Resolve(TPromised value); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Promises/IPromise.cs b/Oxide.Ext.Discord/Interfaces/Promises/IPromise.cs index ebc9c850b..47b5a6b41 100644 --- a/Oxide.Ext.Discord/Interfaces/Promises/IPromise.cs +++ b/Oxide.Ext.Discord/Interfaces/Promises/IPromise.cs @@ -3,111 +3,124 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Implements a non-generic C# promise, this is a promise that simply resolves without delivering a value. +/// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise +/// +public interface IPromise { /// - /// Implements a non-generic C# promise, this is a promise that simply resolves without delivering a value. - /// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise + /// ID of the promise, useful for debugging. /// - public interface IPromise - { - /// - /// ID of the promise, useful for debugging. - /// - Snowflake Id { get; } + Snowflake Id { get; } - /// - /// Handle errors for the promise. - /// - IPromise Catch(Action onRejected); - - /// - /// Catches a specified exception - /// - IPromise Catch(Action onRejected) where TException : Exception; - - /// - /// Add a resolved callback that chains a value promise (optionally converting to a different value type). - /// - IPromise Then(Func> onResolved); - - /// - /// Add a resolved callback that chains a non-value promise. - /// - IPromise Then(Func onResolved); - - /// - /// Add a resolved callback. - /// - IPromise Then(Action onResolved); - - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a value promise (optionally converting to a different value type). - /// - IPromise Then(Func> onResolved, Func> onRejected); - - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a non-value promise. - /// - IPromise Then(Func onResolved, Action onRejected); - - /// - /// Adds a promise to use as the callback - /// - /// Promise to use for callback - IPromise Then(IPromise promise); + /// + /// Handle errors for the promise. + /// + IPromise Catch(Action onRejected); + + /// + /// Catches a specified exception + /// + IPromise Catch(Action onRejected) where TException : Exception; + + /// + /// Add a resolved callback that chains a value promise (optionally converting to a different value type). + /// + IPromise Then(Func> onResolved); + + /// + /// Add a resolved callback that chains a non-value promise. + /// + IPromise Then(Func onResolved); + + /// + /// Add a resolved callback. + /// + IPromise Then(Action onResolved); + + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a value promise (optionally converting to a different value type). + /// + IPromise Then(Func> onResolved, Func> onRejected); + + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a non-value promise. + /// + IPromise Then(Func onResolved, Action onRejected); + + /// + /// Adds a promise to use as the callback + /// + /// Promise to use for callback + IPromise Then(IPromise promise); - /// - /// Add a resolved callback and a rejected callback. - /// - IPromise Then(Action onResolved, Action onRejected); - - /// - /// Chain an enumerable of promises, all of which must resolve. - /// The resulting promise is resolved when all of the promises have resolved. - /// It is rejected as soon as any of the promises have been rejected. - /// - IPromise ThenAll(Func> chain); - - /// - /// Chain an enumerable of promises, all of which must resolve. - /// Converts to a non-value promise. - /// The resulting promise is resolved when all of the promises have resolved. - /// It is rejected as soon as any of the promises have been rejected. - /// - IPromise> ThenAll(Func>> chain); - - /// - /// Chain a sequence of operations using promises. - /// Return a collection of functions each of which starts an async operation and yields a promise. - /// Each function will be called and each promise resolved in turn. - /// The resulting promise is resolved after each promise is resolved in sequence. - /// - IPromise ThenSequence(Func>> chain); - - /// - /// Add a finally callback. - /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// The returned promise will be resolved or rejected, as per the preceding promise. - /// - IPromise Finally(Action onComplete); - - /// - /// Add a callback that chains a non-value promise. - /// ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// The state of the returning promise will be based on the new non-value promise, not the preceding (rejected or resolved) promise. - /// - IPromise ContinueWith(Func onResolved); - - /// - /// Add a callback that chains a value promise (optionally converting to a different value type). - /// ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// The state of the returning promise will be based on the new value promise, not the preceding (rejected or resolved) promise. - /// - IPromise ContinueWith(Func> onComplete); - } + /// + /// Add a resolved callback and a rejected callback. + /// + IPromise Then(Action onResolved, Action onRejected); + + /// + /// Chain an enumerable of promises, all of which must resolve. + /// The resulting promise is resolved when all of the promises have resolved. + /// It is rejected as soon as any of the promises have been rejected. + /// + IPromise ThenAll(Func> chain); + + /// + /// Chain an enumerable of promises, all of which must resolve. + /// Converts to a non-value promise. + /// The resulting promise is resolved when all of the promises have resolved. + /// It is rejected as soon as any of the promises have been rejected. + /// + IPromise> ThenAll(Func>> chain); + + /// + /// Chain a sequence of operations using promises. + /// Return a collection of functions each of which starts an async operation and yields a promise. + /// Each function will be called and each promise resolved in turn. + /// The resulting promise is resolved after each promise is resolved in sequence. + /// + IPromise ThenSequence(Func>> chain); + + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// The returned promise will be resolved or rejected, as per the preceding promise. + /// + IPromise Finally(Action onComplete); + + /// + /// Add a callback that chains a non-value promise. + /// ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// The state of the returning promise will be based on the new non-value promise, not the preceding (rejected or resolved) promise. + /// + IPromise ContinueWith(Func onResolved); + + /// + /// Add a callback that chains a value promise (optionally converting to a different value type). + /// ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// The state of the returning promise will be based on the new value promise, not the preceding (rejected or resolved) promise. + /// + IPromise ContinueWith(Func> onComplete); + + /// + /// returns the task for this promise + /// + /// + ValueTask AsTask(); + + /// + /// returns the task awaiter for this promise + /// + /// + ValueTaskAwaiter GetAwaiter(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Promises/IPromise{T}.cs b/Oxide.Ext.Discord/Interfaces/Promises/IPromise{T}.cs index 7e5e9a558..9d8c7a212 100644 --- a/Oxide.Ext.Discord/Interfaces/Promises/IPromise{T}.cs +++ b/Oxide.Ext.Discord/Interfaces/Promises/IPromise{T}.cs @@ -3,110 +3,123 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Implements a C# promise. +/// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise +/// +public interface IPromise { /// - /// Implements a C# promise. - /// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise + /// ID of the promise, useful for debugging. /// - public interface IPromise - { - /// - /// ID of the promise, useful for debugging. - /// - Snowflake Id { get; } + Snowflake Id { get; } - /// - /// Handle errors for the promise. - /// - IPromise Catch(Action onRejected); + /// + /// Handle errors for the promise. + /// + IPromise Catch(Action onRejected); - /// - /// Catches a specified exception - /// - IPromise Catch(Action onRejected) where TException : Exception; + /// + /// Catches a specified exception + /// + IPromise Catch(Action onRejected) where TException : Exception; - /// - /// Handle errors for the promise. - /// - IPromise Catch(Func onRejected); + /// + /// Handle errors for the promise. + /// + IPromise Catch(Func onRejected); - /// - /// Add a resolved callback that chains a value promise (optionally converting to a different value type). - /// - IPromise Then(Func> onResolved); + /// + /// Add a resolved callback that chains a value promise (optionally converting to a different value type). + /// + IPromise Then(Func> onResolved); - /// - /// Add a resolved callback. - /// - IPromise Then(Action onResolved); + /// + /// Add a resolved callback. + /// + IPromise Then(Action onResolved); - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a value promise (optionally converting to a different value type). - /// - IPromise Then(Func> onResolved, Func> onRejected); + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a value promise (optionally converting to a different value type). + /// + IPromise Then(Func> onResolved, Func> onRejected); - /// - /// Adds a callback from the given promise - /// - /// Promise to use for the callback - IPromise Then(IPromise promise); + /// + /// Adds a callback from the given promise + /// + /// Promise to use for the callback + IPromise Then(IPromise promise); - /// - /// Add a resolved callback and a rejected callback. - /// The resolved callback chains a non-value promise. - /// - IPromise Then(Func onResolved, Action onRejected); + /// + /// Add a resolved callback and a rejected callback. + /// The resolved callback chains a non-value promise. + /// + IPromise Then(Func onResolved, Action onRejected); - /// - /// Add a resolved callback and a rejected callback. - /// - IPromise Then(Action onResolved, Action onRejected); + /// + /// Add a resolved callback and a rejected callback. + /// + IPromise Then(Action onResolved, Action onRejected); - /// - /// Return a new promise with a different value. - /// May also change the type of the value. - /// - IPromise Then(Func transform); + /// + /// Return a new promise with a different value. + /// May also change the type of the value. + /// + IPromise Then(Func transform); - /// - /// Chain an enumerable of promises, all of which must resolve. - /// Returns a promise for a collection of the resolved results. - /// The resulting promise is resolved when all of the promises have resolved. - /// It is rejected as soon as any of the promises have been rejected. - /// - IPromise> ThenAll(Func>> chain); + /// + /// Chain an enumerable of promises, all of which must resolve. + /// Returns a promise for a collection of the resolved results. + /// The resulting promise is resolved when all of the promises have resolved. + /// It is rejected as soon as any of the promises have been rejected. + /// + IPromise> ThenAll(Func>> chain); - /// - /// Chain an enumerable of promises, all of which must resolve. - /// Converts to a non-value promise. - /// The resulting promise is resolved when all of the promises have resolved. - /// It is rejected as soon as any of the promises have been rejected. - /// - IPromise ThenAll(Func> chain); + /// + /// Chain an enumerable of promises, all of which must resolve. + /// Converts to a non-value promise. + /// The resulting promise is resolved when all of the promises have resolved. + /// It is rejected as soon as any of the promises have been rejected. + /// + IPromise ThenAll(Func> chain); - /// - /// Add a finally callback. - /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// The returned promise will be resolved or rejected, as per the preceding promise. - /// - IPromise Finally(Action onComplete); + /// + /// Add a finally callback. + /// Finally callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// The returned promise will be resolved or rejected, as per the preceding promise. + /// + IPromise Finally(Action onComplete); - /// - /// Add a callback that chains a non-value promise. - /// ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// The state of the returning promise will be based on the new non-value promise, not the preceding (rejected or resolved) promise. - /// - IPromise ContinueWith(Func onResolved); + /// + /// Add a callback that chains a non-value promise. + /// ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// The state of the returning promise will be based on the new non-value promise, not the preceding (rejected or resolved) promise. + /// + IPromise ContinueWith(Func onResolved); - /// - /// Add a callback that chains a value promise (optionally converting to a different value type). - /// ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. - /// The state of the returning promise will be based on the new value promise, not the preceding (rejected or resolved) promise. - /// - IPromise ContinueWith(Func> onComplete); - } + /// + /// Add a callback that chains a value promise (optionally converting to a different value type). + /// ContinueWith callbacks will always be called, even if any preceding promise is rejected, or encounters an error. + /// The state of the returning promise will be based on the new value promise, not the preceding (rejected or resolved) promise. + /// + IPromise ContinueWith(Func> onComplete); + + /// + /// returns the task for this promise + /// + /// + ValueTask AsTask(); + + /// + /// returns the task awaiter for this promise + /// + /// + ValueTaskAwaiter GetAwaiter(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Promises/IRejectable.cs b/Oxide.Ext.Discord/Interfaces/Promises/IRejectable.cs index 957faac2b..4761878fa 100644 --- a/Oxide.Ext.Discord/Interfaces/Promises/IRejectable.cs +++ b/Oxide.Ext.Discord/Interfaces/Promises/IRejectable.cs @@ -3,16 +3,15 @@ using System; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Interface for a promise that can be rejected. +/// +public interface IRejectable { /// - /// Interface for a promise that can be rejected. + /// Reject the promise with an exception. /// - public interface IRejectable - { - /// - /// Reject the promise with an exception. - /// - void Reject(Exception ex); - } + void Reject(Exception ex); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/Templates/IBulkTemplate.cs b/Oxide.Ext.Discord/Interfaces/Templates/IBulkTemplate.cs index 3e65cca23..35c1bda69 100644 --- a/Oxide.Ext.Discord/Interfaces/Templates/IBulkTemplate.cs +++ b/Oxide.Ext.Discord/Interfaces/Templates/IBulkTemplate.cs @@ -1,28 +1,27 @@ using System.Collections.Generic; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents a Template that supports bulk operations +/// +/// +public interface IBulkTemplate where T : class { /// - /// Represents a Template that supports bulk operations + /// return the {T} entity with the given placeholder data + /// If entity is not specified a new one will be created /// - /// - public interface IBulkTemplate where T : class - { - /// - /// return the {T} entity with the given placeholder data - /// If entity is not specified a new one will be created - /// - /// Placeholder Data to apply - /// Initial entity - /// - T ToEntity(PlaceholderData data = null, T entity = null); + /// Placeholder Data to apply + /// Initial entity + /// + T ToEntity(PlaceholderData data = null, T entity = null); - /// - /// Returns a promise that returns a bulk to entity. - /// - /// List of data to be bulk converter - /// - IPromise> ToEntityBulk(List data = null); - } + /// + /// Returns a promise that returns a bulk to entity. + /// + /// List of data to be bulk converter + /// + IPromise> ToEntityBulk(List data = null); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Interfaces/WebSockets/IWebSocketEventHandler.cs b/Oxide.Ext.Discord/Interfaces/WebSockets/IWebSocketEventHandler.cs index e457cce61..326e08871 100644 --- a/Oxide.Ext.Discord/Interfaces/WebSockets/IWebSocketEventHandler.cs +++ b/Oxide.Ext.Discord/Interfaces/WebSockets/IWebSocketEventHandler.cs @@ -4,43 +4,42 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Interfaces +namespace Oxide.Ext.Discord.Interfaces; + +/// +/// Represents a Handler for Websocket Events +/// +public interface IWebSocketEventHandler { /// - /// Represents a Handler for Websocket Events + /// Called when the web socket is opened /// - public interface IWebSocketEventHandler - { - /// - /// Called when the web socket is opened - /// - /// ID of the web socket - /// - ValueTask SocketOpened(Snowflake id); + /// ID of the web socket + /// + ValueTask SocketOpened(Snowflake id); - /// - /// Called when the web socket is closed - /// - /// ID of the websocket - /// Web socket close code - /// Web socket close message - /// - ValueTask SocketClosed(Snowflake id, WebSocketCloseStatus code, string message); + /// + /// Called when the web socket is closed + /// + /// ID of the websocket + /// Web socket close code + /// Web socket close message + /// + ValueTask SocketClosed(Snowflake id, WebSocketCloseStatus code, string message); - /// - /// Called when an error occurs on the web socket - /// - /// ID of the websocket - /// Exception that was thrown - /// - ValueTask SocketErrored(Snowflake id, Exception ex); + /// + /// Called when an error occurs on the web socket + /// + /// ID of the websocket + /// Exception that was thrown + /// + ValueTask SocketErrored(Snowflake id, Exception ex); - /// - /// Called when a message is received from the websocket - /// - /// ID of the message - /// Stream containing the message - /// - ValueTask SocketMessage(Snowflake id, DiscordJsonReader stream); - } + /// + /// Called when a message is received from the websocket + /// + /// ID of the message + /// Stream containing the message + /// + ValueTask SocketMessage(Snowflake id, DiscordJsonReader stream); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/DiscordColorConverter.cs b/Oxide.Ext.Discord/Json/Converters/DiscordColorConverter.cs index b957b3a91..8ca85864a 100644 --- a/Oxide.Ext.Discord/Json/Converters/DiscordColorConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/DiscordColorConverter.cs @@ -3,51 +3,55 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Extensions; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// Handles the JSON Serialization / Deserialization for DiscordColor +/// +public class DiscordColorConverter : JsonConverter { /// - /// Handles the JSON Serialization / Deserialization for DiscordColor + /// Writes to JSON /// - public class DiscordColorConverter : JsonConverter + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - /// - /// Writes to JSON - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - DiscordColor color = (DiscordColor) value; - writer.WriteValue(color.Color); - } + DiscordColor color = (DiscordColor) value; + writer.WriteValue(color.Color); + } - /// - /// Reads from JSON - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + /// + /// Reads from JSON + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) { - if (reader.TokenType == JsonToken.Null) + if (!objectType.IsNullable()) { - if (!objectType.IsNullable()) - { - throw new JsonException($"Cannot convert null value to {objectType}. Path: {reader.Path}"); - } - - return null; + throw new JsonException($"Cannot convert null value to {objectType}. Path: {reader.Path}"); } - if (reader.TokenType == JsonToken.Integer) - { - return new DiscordColor(uint.Parse(reader.Value.ToString())); - } - - throw new JsonException($"Unexpected token {reader.TokenType} when parsing discord color. Path: {reader.Path}"); + return null; } - /// - /// Check if can convert - /// - public override bool CanConvert(Type objectType) + if (reader.TokenType == JsonToken.Integer) { - return objectType != null && (objectType.IsNullable() ? Nullable.GetUnderlyingType(objectType) : objectType) == typeof(DiscordColor); + return new DiscordColor(uint.Parse(reader.Value.ToString())); } + + if (reader.TokenType == JsonToken.String) + { + return new DiscordColor(reader.Value.ToString()); + } + + throw new JsonException($"Unexpected token {reader.TokenType} when parsing discord color. Path: {reader.Path}"); + } + + /// + /// Check if it can convert + /// + public override bool CanConvert(Type objectType) + { + return objectType != null && (objectType.IsNullable() ? Nullable.GetUnderlyingType(objectType) : objectType) == typeof(DiscordColor); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/DiscordEnumConverter.cs b/Oxide.Ext.Discord/Json/Converters/DiscordEnumConverter.cs index 4b9542d90..6de1a61af 100644 --- a/Oxide.Ext.Discord/Json/Converters/DiscordEnumConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/DiscordEnumConverter.cs @@ -2,85 +2,84 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Extensions; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// Handles deserializing JSON values as strings. If the value doesn't exist, return the default value. +/// +public class DiscordEnumConverter : JsonConverter { /// - /// Handles deserializing JSON values as strings. If the value doesn't exist return the default value. + /// Write Enum value to Discord Enum String /// - public class DiscordEnumConverter : JsonConverter + /// + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - /// - /// Write Enum value to Discord Enum String - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + if (value == null) { - if (value == null) - { - writer.WriteNull(); - return; - } - - Enum enumValue = (Enum) value; - string enumText = enumValue.ToString("G"); - if (char.IsNumber(enumText[0]) || enumText[0] == '-') - { - writer.WriteValue(value); - return; - } - - string enumName = JsonEnumUtils.ToEnumName(enumValue.GetType(), enumText); - if (!string.IsNullOrEmpty(enumName)) - { - writer.WriteValue(enumName); - } + writer.WriteNull(); + return; } - /// - /// Read enum value from Discord Enum String - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + Enum enumValue = (Enum) value; + string enumText = enumValue.ToString("G"); + if (char.IsNumber(enumText[0]) || enumText[0] == '-') { - if (reader.TokenType == JsonToken.Null) - { - if (!objectType.IsNullable()) - { - throw new JsonException($"Cannot convert null value to {objectType}. Path: {reader.Path}"); - } + writer.WriteValue(value); + return; + } - return null; - } + string enumName = JsonEnumUtils.ToEnumName(enumValue.GetType(), enumText); + if (!string.IsNullOrEmpty(enumName)) + { + writer.WriteValue(enumName); + } + } - string value = reader.Value.ToString(); - if (reader.TokenType == JsonToken.Integer) + /// + /// Read enum value from Discord Enum String + /// + /// + /// + /// + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + { + if (!objectType.IsNullable()) { - return Enum.IsDefined(objectType, value) ? Enum.Parse(objectType, value) : JsonEnumUtils.GetDefault(objectType); + throw new JsonException($"Cannot convert null value to {objectType}. Path: {reader.Path}"); } - if (reader.TokenType == JsonToken.String) - { - string enumName = JsonEnumUtils.FromEnumName(objectType, value) ?? value; - return Enum.IsDefined(objectType, enumName) ? Enum.Parse(objectType, enumName) : JsonEnumUtils.GetDefault(objectType); - } + return null; + } - throw new JsonException($"Unexpected token {reader.TokenType} when parsing enum. Path: {reader.Path}"); + string value = reader.Value.ToString(); + if (reader.TokenType == JsonToken.Integer) + { + return Enum.IsDefined(objectType, value) ? Enum.Parse(objectType, value) : JsonEnumUtils.GetDefault(objectType); } - - /// - /// Checks if this type is enum or nullable enum - /// - /// - /// - public override bool CanConvert(Type objectType) + + if (reader.TokenType == JsonToken.String) { - return objectType != null && ((objectType.IsNullable() ? Nullable.GetUnderlyingType(objectType) : objectType)?.IsEnum ?? false); + string enumName = JsonEnumUtils.FromEnumName(objectType, value) ?? value; + return Enum.IsDefined(objectType, enumName) ? Enum.Parse(objectType, enumName) : JsonEnumUtils.GetDefault(objectType); } + + throw new JsonException($"Unexpected token {reader.TokenType} when parsing enum. Path: {reader.Path}"); + } + + /// + /// Checks if this type is enum or nullable enum + /// + /// + /// + public override bool CanConvert(Type objectType) + { + return objectType != null && ((objectType.IsNullable() ? Nullable.GetUnderlyingType(objectType) : objectType)?.IsEnum ?? false); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/DiscordImageDataConverter.cs b/Oxide.Ext.Discord/Json/Converters/DiscordImageDataConverter.cs index d616bfc39..ced8a86af 100644 --- a/Oxide.Ext.Discord/Json/Converters/DiscordImageDataConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/DiscordImageDataConverter.cs @@ -3,64 +3,63 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// Represents the for +/// +public class DiscordImageDataConverter : JsonConverter { /// - /// Represents the for + /// /// - public class DiscordImageDataConverter : JsonConverter + /// + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - /// - /// - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - DiscordImageData image = (DiscordImageData)value; - writer.WriteValue(image.GetBase64Image()); - } + DiscordImageData image = (DiscordImageData)value; + writer.WriteValue(image.GetBase64Image()); + } - /// - /// - /// - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + /// + /// + /// + /// + /// + /// + /// + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch (reader.TokenType) { - switch (reader.TokenType) - { - case JsonToken.Null: - if (Nullable.GetUnderlyingType(objectType) != null) - { - return null; - } + case JsonToken.Null: + if (Nullable.GetUnderlyingType(objectType) != null) + { + return null; + } - DiscordExtension.GlobalLogger.Warning("DiscordImageData tried to parse null to non nullable field: {0}. Please give this message to the discord extension authors.", reader.Path); - return default(DiscordImageData); + DiscordExtension.GlobalLogger.Warning("DiscordImageData tried to parse null to non nullable field: {0}. Please give this message to the discord extension authors.", reader.Path); + return default(DiscordImageData); - case JsonToken.String: - string value = reader.Value.ToString(); - return new DiscordImageData(value); + case JsonToken.String: + string value = reader.Value.ToString(); + return new DiscordImageData(value); - default: - throw new JsonException($"Token type {reader.TokenType} does not match DiscordImageData valid types of string or null. Path: {reader.Path}"); - } + default: + throw new JsonException($"Token type {reader.TokenType} does not match DiscordImageData valid types of string or null. Path: {reader.Path}"); } + } - /// - /// - /// - /// - /// - public override bool CanConvert(Type objectType) - { - return objectType == typeof(DiscordImageData); - } + /// + /// + /// + /// + /// + public override bool CanConvert(Type objectType) + { + return objectType == typeof(DiscordImageData); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/DiscordLocaleConverter.cs b/Oxide.Ext.Discord/Json/Converters/DiscordLocaleConverter.cs index 065ceee83..332eae204 100644 --- a/Oxide.Ext.Discord/Json/Converters/DiscordLocaleConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/DiscordLocaleConverter.cs @@ -2,31 +2,30 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +internal class DiscordLocaleConverter : JsonConverter { - internal class DiscordLocaleConverter : JsonConverter + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - writer.WriteValue(value.ToString()); - } + writer.WriteValue(value.ToString()); + } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch (reader.TokenType) { - switch (reader.TokenType) - { - case JsonToken.String: - string value = reader.Value.ToString(); - return !string.IsNullOrEmpty(value) ? DiscordLocale.Parse(value) : default(DiscordLocale); + case JsonToken.String: + string value = reader.Value.ToString(); + return !string.IsNullOrEmpty(value) ? DiscordLocale.Parse(value) : default; - case JsonToken.Null: - return Nullable.GetUnderlyingType(objectType) != null ? (object)null : default(DiscordLocale); + case JsonToken.Null: + return Nullable.GetUnderlyingType(objectType) != null ? null : default(DiscordLocale); - default: - throw new JsonException($"Token type {reader.TokenType} does not match DiscordLocale valid types of string or null. Path: {reader.Path}"); - } + default: + throw new JsonException($"Token type {reader.TokenType} does not match DiscordLocale valid types of string or null. Path: {reader.Path}"); } - - public override bool CanConvert(Type objectType) => typeof(DiscordLocale) == objectType; } + + public override bool CanConvert(Type objectType) => typeof(DiscordLocale) == objectType; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/EventPayloadConverter.cs b/Oxide.Ext.Discord/Json/Converters/EventPayloadConverter.cs index 16fd1e163..1aeeeed5d 100644 --- a/Oxide.Ext.Discord/Json/Converters/EventPayloadConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/EventPayloadConverter.cs @@ -5,70 +5,69 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.WebSockets; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// JSON converter for +/// +public class EventPayloadConverter : JsonConverter { + private const string EventCode = "op"; + private const string Sequence = "s"; + private const string DiscordCode = "t"; + private const string Data = "d"; + /// - /// JSON converter for + /// We do not write with this converter /// - public class EventPayloadConverter : JsonConverter - { - private const string EventCode = "op"; - private const string Sequence = "s"; - private const string DiscordCode = "t"; - private const string Data = "d"; - - /// - /// We do not write with this converter - /// - public override bool CanWrite => false; + public override bool CanWrite => false; - /// - /// We do nto write with this converter - /// - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotSupportedException(); - - /// - /// Reads the JSON into a pooled - /// Populates the Data field with the correct type during deserialization - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - JObject obj = JObject.Load(reader); - EventPayload payload = DiscordPool.Internal.Get(); - payload.OpCode = obj[EventCode].ToObject(serializer); - payload.Sequence = obj[Sequence]?.ToObject(serializer); + /// + /// We do nto write with this converter + /// + /// + /// + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotSupportedException(); - switch (payload.OpCode) - { - case GatewayEventCode.Dispatch: - payload.DispatchCode = obj[DiscordCode].ToObject(serializer); - payload.JsonData = obj[Data]; - break; - case GatewayEventCode.InvalidSession: - payload.ShouldResume = obj[Data]?.ToObject(serializer) ?? false; - break; - case GatewayEventCode.Hello: - payload.JsonData = obj[Data]; - break; - } + /// + /// Reads the JSON into a pooled + /// Populates the Data field with the correct type during deserialization + /// + /// + /// + /// + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + JObject obj = JObject.Load(reader); + EventPayload payload = DiscordPool.Internal.Get(); + payload.OpCode = obj[EventCode].ToObject(serializer); + payload.Sequence = obj[Sequence]?.ToObject(serializer); - return payload; + switch (payload.OpCode) + { + case GatewayEventCode.Dispatch: + payload.DispatchCode = obj[DiscordCode].ToObject(serializer); + payload.JsonData = obj[Data]; + break; + case GatewayEventCode.InvalidSession: + payload.ShouldResume = obj[Data]?.ToObject(serializer) ?? false; + break; + case GatewayEventCode.Hello: + payload.JsonData = obj[Data]; + break; } - /// - /// Returns if this converter can convert the given type - /// - /// - /// - public override bool CanConvert(Type objectType) => typeof(EventPayload) == objectType; + return payload; } + + /// + /// Returns if this converter can convert the given type + /// + /// + /// + public override bool CanConvert(Type objectType) => typeof(EventPayload) == objectType; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/HashListConverter.cs b/Oxide.Ext.Discord/Json/Converters/HashListConverter.cs index 4451cb026..0449669cf 100644 --- a/Oxide.Ext.Discord/Json/Converters/HashListConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/HashListConverter.cs @@ -6,61 +6,60 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// Converts to and from a list in JSON to a hash +/// +/// +public class HashListConverter : JsonConverter where TValue : class, ISnowflakeEntity { /// - /// Converts to and from a list in JSON to a hash + /// Read an array in JSON as a hash /// - /// - public class HashListConverter : JsonConverter where TValue : class, ISnowflakeEntity + /// + /// + /// + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - /// - /// Read an array in JSON as a hash - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - Hash data = new Hash(); + Hash data = new(); - foreach (JToken token in JArray.Load(reader)) - { - TValue value = token.ToObject(); - data[value.Id] = value; - } - - return data; - } - - /// - /// Write a hash as a list in JSON - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + foreach (JToken token in JArray.Load(reader)) { - Hash data = (Hash) value; - - writer.WriteStartArray(); - foreach (TValue tValue in data.Values) - { - serializer.Serialize(writer, tValue); - } - writer.WriteEndArray(); + TValue value = token.ToObject(); + data[value.Id] = value; } - /// - /// Can we convert the given type - /// - /// - /// - public override bool CanConvert(Type objectType) + return data; + } + + /// + /// Write a hash as a list in JSON + /// + /// + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + Hash data = (Hash) value; + + writer.WriteStartArray(); + foreach (TValue tValue in data.Values) { - return objectType == typeof(List) || objectType == typeof(Hash); + serializer.Serialize(writer, tValue); } + writer.WriteEndArray(); + } + + /// + /// Can we convert the given type + /// + /// + /// + public override bool CanConvert(Type objectType) + { + return objectType == typeof(List) || objectType == typeof(Hash); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/MessageComponentsConverter.cs b/Oxide.Ext.Discord/Json/Converters/MessageComponentsConverter.cs index 30c0e1e63..05df05054 100644 --- a/Oxide.Ext.Discord/Json/Converters/MessageComponentsConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/MessageComponentsConverter.cs @@ -4,93 +4,92 @@ using Newtonsoft.Json.Linq; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// Converter for a list of message components +/// +public class MessageComponentsConverter : JsonConverter { /// - /// Converter for list of message components + /// Ignored as we don't write JSON + /// + /// + /// + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotSupportedException(); + } + + /// + /// Populate the correct types in components instead of just the BaseComponent /// - public class MessageComponentsConverter : JsonConverter + /// + /// + /// + /// + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - /// - /// Ignored as we don't write JSON - /// - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + JArray array = JArray.Load(reader); + if (existingValue is not List components) { - throw new NotSupportedException(); + components = new List(); } - /// - /// Populate the correct types in components instead of just the BaseComponent - /// - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + foreach (JToken token in array) { - JArray array = JArray.Load(reader); - if (!(existingValue is List components)) + MessageComponentType type = (MessageComponentType)Enum.Parse(typeof(MessageComponentType), token["type"].ToString()); + switch (type) { - components = new List(); - } - - foreach (JToken token in array) - { - MessageComponentType type = (MessageComponentType)Enum.Parse(typeof(MessageComponentType), token["type"].ToString()); - switch (type) - { - case MessageComponentType.Button: - components.Add(token.ToObject(serializer)); - break; + case MessageComponentType.Button: + components.Add(token.ToObject(serializer)); + break; - case MessageComponentType.StringSelect: - components.Add(token.ToObject(serializer)); - break; + case MessageComponentType.StringSelect: + components.Add(token.ToObject(serializer)); + break; - case MessageComponentType.UserSelect: - components.Add(token.ToObject(serializer)); - break; + case MessageComponentType.UserSelect: + components.Add(token.ToObject(serializer)); + break; - case MessageComponentType.RoleSelect: - components.Add(token.ToObject(serializer)); - break; + case MessageComponentType.RoleSelect: + components.Add(token.ToObject(serializer)); + break; - case MessageComponentType.MentionableSelect: - components.Add(token.ToObject(serializer)); - break; + case MessageComponentType.MentionableSelect: + components.Add(token.ToObject(serializer)); + break; - case MessageComponentType.ChannelSelect: - components.Add(token.ToObject(serializer)); - break; + case MessageComponentType.ChannelSelect: + components.Add(token.ToObject(serializer)); + break; - case MessageComponentType.InputText: - components.Add(token.ToObject(serializer)); - break; - } + case MessageComponentType.InputText: + components.Add(token.ToObject(serializer)); + break; } - - return components; } - /// - /// Returns if this can convert the value - /// - /// - /// - public override bool CanConvert(Type objectType) - { - return objectType == typeof(List); - } + return components; + } - /// - /// Message Component Convert does not write JSON - /// - public override bool CanWrite => false; + /// + /// Returns if this can convert the value + /// + /// + /// + public override bool CanConvert(Type objectType) + { + return objectType == typeof(List); } + + /// + /// Message Component Convert does not write JSON + /// + public override bool CanWrite => false; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/PermissionFlagsStringConverter.cs b/Oxide.Ext.Discord/Json/Converters/PermissionFlagsStringConverter.cs index dd7585f00..99c4492fe 100644 --- a/Oxide.Ext.Discord/Json/Converters/PermissionFlagsStringConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/PermissionFlagsStringConverter.cs @@ -3,57 +3,56 @@ using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// Converts Permission Flags to and from a JSON string +/// +public class PermissionFlagsStringConverter : JsonConverter { /// - /// Converts Permission Flags to and from a JSON string + /// Writes Permission Flags as a JSON string /// - public class PermissionFlagsStringConverter : JsonConverter + /// + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - /// - /// Writes Permission Flags as a JSON string - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + if (value == null) { - if (value == null) - { - writer.WriteValue("0"); - return; - } - - writer.WriteValue(EnumCache.Instance.ToNumber((PermissionFlags)value)); + writer.WriteValue("0"); + return; } - - /// - /// Converts the ulong JSON string to Permission Flags - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - if (reader.TokenType == JsonToken.Null) - { - return PermissionFlags.None; - } - ulong value = ulong.Parse(reader.Value.ToString()); - return (PermissionFlags)value; - } + writer.WriteValue(EnumCache.Instance.ToNumber((PermissionFlags)value)); + } - /// - /// Returns if the type equals PermissionFlags - /// - /// - /// - public override bool CanConvert(Type objectType) + /// + /// Converts the ulong JSON string to Permission Flags + /// + /// + /// + /// + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) { - return typeof(PermissionFlags) == objectType; + return PermissionFlags.None; } + + ulong value = ulong.Parse(reader.Value.ToString()); + return (PermissionFlags)value; + } + + /// + /// Returns if the type equals PermissionFlags + /// + /// + /// + public override bool CanConvert(Type objectType) + { + return typeof(PermissionFlags) == objectType; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/RoleTagsConverter.cs b/Oxide.Ext.Discord/Json/Converters/RoleTagsConverter.cs index e6ad118e4..3a60f21fb 100644 --- a/Oxide.Ext.Discord/Json/Converters/RoleTagsConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/RoleTagsConverter.cs @@ -3,60 +3,59 @@ using Newtonsoft.Json.Linq; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// Handles converting +/// This type contains special deserialization types +/// +public class RoleTagsConverter : JsonConverter { /// - /// Handles converting - /// This type contains special deserialization types + /// Cannot write /// - public class RoleTagsConverter : JsonConverter - { - /// - /// Cannot write - /// - public override bool CanWrite => false; + public override bool CanWrite => false; - /// - /// Cannot Write - /// - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new JsonSerializationException($"{nameof(RoleTagsConverter)} does not support writing."); - } + /// + /// Cannot Write + /// + /// + /// + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new JsonSerializationException($"{nameof(RoleTagsConverter)} does not support writing."); + } - /// - /// Converts the JSON to a - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + /// + /// Converts the JSON to a + /// + /// + /// + /// + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + JObject obj = JObject.Load(reader); + RoleTags tags = new() { - JObject obj = JObject.Load(reader); - RoleTags tags = new RoleTags - { - BotId = obj["bot_id"]?.ToObject(serializer), - IntegrationId = obj["integration_id"]?.ToObject(serializer), - SubscriptionListingId = obj["subscription_listing_id"]?.ToObject(serializer), - PremiumSubscriber = obj["premium_subscriber"] != null, - AvailableForPurchase = obj["available_for_purchase"] != null, - GuildConnections = obj["guild_connections"] != null - }; - - return tags; - } + BotId = obj["bot_id"]?.ToObject(serializer), + IntegrationId = obj["integration_id"]?.ToObject(serializer), + SubscriptionListingId = obj["subscription_listing_id"]?.ToObject(serializer), + PremiumSubscriber = obj["premium_subscriber"] != null, + AvailableForPurchase = obj["available_for_purchase"] != null, + GuildConnections = obj["guild_connections"] != null + }; - /// - /// Returns if the type can be converter - /// - /// - /// - public override bool CanConvert(Type objectType) => typeof(RoleTags) == objectType; + return tags; } + + /// + /// Returns if the type can be converter + /// + /// + /// + public override bool CanConvert(Type objectType) => typeof(RoleTags) == objectType; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/ServerLocaleConverter.cs b/Oxide.Ext.Discord/Json/Converters/ServerLocaleConverter.cs index f8275c13e..f9d51aac6 100644 --- a/Oxide.Ext.Discord/Json/Converters/ServerLocaleConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/ServerLocaleConverter.cs @@ -2,31 +2,30 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +internal class ServerLocaleConverter : JsonConverter { - internal class ServerLocaleConverter : JsonConverter + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - writer.WriteValue(value.ToString()); - } + writer.WriteValue(value.ToString()); + } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch (reader.TokenType) { - switch (reader.TokenType) - { - case JsonToken.String: - string value = reader.Value.ToString(); - return !string.IsNullOrEmpty(value) ? ServerLocale.Parse(value) : default(ServerLocale); + case JsonToken.String: + string value = reader.Value.ToString(); + return !string.IsNullOrEmpty(value) ? ServerLocale.Parse(value) : default; - case JsonToken.Null: - return Nullable.GetUnderlyingType(objectType) != null ? (object)null : default(ServerLocale); + case JsonToken.Null: + return Nullable.GetUnderlyingType(objectType) != null ? null : default(ServerLocale); - default: - throw new JsonException($"Token type {reader.TokenType} does not match ServerLocale valid types of string or null. Path: {reader.Path}"); - } + default: + throw new JsonException($"Token type {reader.TokenType} does not match ServerLocale valid types of string or null. Path: {reader.Path}"); } - - public override bool CanConvert(Type objectType) => typeof(ServerLocale) == objectType; } + + public override bool CanConvert(Type objectType) => typeof(ServerLocale) == objectType; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/SnowflakeConverter.cs b/Oxide.Ext.Discord/Json/Converters/SnowflakeConverter.cs index 4caee105f..4e8a06277 100644 --- a/Oxide.Ext.Discord/Json/Converters/SnowflakeConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/SnowflakeConverter.cs @@ -3,83 +3,82 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// Converts a snowflake to and from its JSON string value +/// +public class SnowflakeConverter : JsonConverter { /// - /// Converts a snowflake to and from it's JSON string value + /// Reads the JSON string and converts it to a snowflake /// - public class SnowflakeConverter : JsonConverter + /// + /// + /// + /// + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - /// - /// Reads the JSON string and converts it to a snowflake - /// - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + switch (reader.TokenType) { - switch (reader.TokenType) - { - case JsonToken.Integer: - return new Snowflake(ulong.Parse(reader.Value.ToString())); + case JsonToken.Integer: + return new Snowflake(ulong.Parse(reader.Value.ToString())); - case JsonToken.String: - string value = reader.Value.ToString(); - if (string.IsNullOrEmpty(value)) - { - return default(Snowflake); - } + case JsonToken.String: + string value = reader.Value.ToString(); + if (string.IsNullOrEmpty(value)) + { + return default(Snowflake); + } - if (Snowflake.TryParse(value, out Snowflake snowflake)) - { - return snowflake; - } + if (Snowflake.TryParse(value, out Snowflake snowflake)) + { + return snowflake; + } - throw new JsonException($"Snowflake string JSON token failed to parse to snowflake: '{reader.Value}' Path: {reader.Path}"); + throw new JsonException($"Snowflake string JSON token failed to parse to snowflake: '{reader.Value}' Path: {reader.Path}"); - case JsonToken.Null: - if (Nullable.GetUnderlyingType(objectType) != null) - { - return null; - } + case JsonToken.Null: + if (Nullable.GetUnderlyingType(objectType) != null) + { + return null; + } - DiscordExtension.GlobalLogger.Warning("Snowflake tried to parse null to non nullable field: {0}. Please give this message to the discord extension authors.", reader.Path); - return default(Snowflake); + DiscordExtension.GlobalLogger.Warning("Snowflake tried to parse null to non nullable field: {0}. Please give this message to the discord extension authors.", reader.Path); + return default(Snowflake); - default: - throw new JsonException($"Token type {reader.TokenType} does not match snowflake valid types of string or integer. Path: {reader.Path}"); - } + default: + throw new JsonException($"Token type {reader.TokenType} does not match snowflake valid types of string or integer. Path: {reader.Path}"); } + } - /// - /// Writes a snowflake as a JSON string - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + /// + /// Writes a snowflake as a JSON string + /// + /// + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + Snowflake snowflake = (Snowflake)value; + if (!snowflake.IsValid()) { - Snowflake snowflake = (Snowflake)value; - if (!snowflake.IsValid()) - { - writer.WriteValue(string.Empty); - return; - } - - writer.WriteValue(snowflake.ToString()); + writer.WriteValue(string.Empty); + return; } + + writer.WriteValue(snowflake.ToString()); + } - /// - /// Returns if we can convert this type - /// - /// - /// - public override bool CanConvert(Type objectType) - { - return objectType == typeof(Snowflake); - } + /// + /// Returns if we can convert this type + /// + /// + /// + public override bool CanConvert(Type objectType) + { + return objectType == typeof(Snowflake); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/TemplateComponentsConverter.cs b/Oxide.Ext.Discord/Json/Converters/TemplateComponentsConverter.cs index ac3b57f5c..fda31b863 100644 --- a/Oxide.Ext.Discord/Json/Converters/TemplateComponentsConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/TemplateComponentsConverter.cs @@ -5,75 +5,74 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// Converter for a list of message components +/// +public class TemplateComponentsConverter : JsonConverter { /// - /// Converter for list of message components + /// Ignored as we don't write JSON /// - public class TemplateComponentsConverter : JsonConverter - { - /// - /// Ignored as we don't write JSON - /// - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotSupportedException(); + /// + /// + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotSupportedException(); - /// - /// Populate the correct types in components instead of just the BaseComponent - /// - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + /// + /// Populate the correct types in components instead of just the BaseComponent + /// + /// + /// + /// + /// + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + JArray array = JArray.Load(reader); + if (existingValue is not List components) { - JArray array = JArray.Load(reader); - if (!(existingValue is List components)) - { - components = new List(); - } + components = new List(); + } - foreach (JToken token in array) + foreach (JToken token in array) + { + MessageComponentType type = (MessageComponentType)Enum.Parse(typeof(MessageComponentType), token["Type"].ToString()); + switch (type) { - MessageComponentType type = (MessageComponentType)Enum.Parse(typeof(MessageComponentType), token["Type"].ToString()); - switch (type) - { - case MessageComponentType.Button: - components.Add(token.ToObject(serializer)); - break; + case MessageComponentType.Button: + components.Add(token.ToObject(serializer)); + break; - case MessageComponentType.StringSelect: - case MessageComponentType.UserSelect: - case MessageComponentType.RoleSelect: - case MessageComponentType.MentionableSelect: - case MessageComponentType.ChannelSelect: - components.Add(token.ToObject(serializer)); - break; + case MessageComponentType.StringSelect: + case MessageComponentType.UserSelect: + case MessageComponentType.RoleSelect: + case MessageComponentType.MentionableSelect: + case MessageComponentType.ChannelSelect: + components.Add(token.ToObject(serializer)); + break; - case MessageComponentType.InputText: - components.Add(token.ToObject(serializer)); - break; - } + case MessageComponentType.InputText: + components.Add(token.ToObject(serializer)); + break; } - - return components; } - /// - /// Returns if this can convert the value - /// - /// - /// - public override bool CanConvert(Type objectType) => objectType == typeof(List); - - /// - /// Message Component Convert does not write JSON - /// - public override bool CanWrite => false; + return components; } + + /// + /// Returns if this can convert the value + /// + /// + /// + public override bool CanConvert(Type objectType) => objectType == typeof(List); + + /// + /// Message Component Convert does not write JSON + /// + public override bool CanWrite => false; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/TemplateKeyConverter.cs b/Oxide.Ext.Discord/Json/Converters/TemplateKeyConverter.cs index 725b8641d..4b01601f2 100644 --- a/Oxide.Ext.Discord/Json/Converters/TemplateKeyConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/TemplateKeyConverter.cs @@ -2,32 +2,31 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// JSON Template Key Converter +/// +public class TemplateKeyConverter : JsonConverter { - /// - /// Json Template Key Converter - /// - public class TemplateKeyConverter : JsonConverter + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - TemplateKey key = (TemplateKey)value; - writer.WriteValue(key.Name); - } + TemplateKey key = (TemplateKey)value; + writer.WriteValue(key.Name); + } - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.String) { - if (reader.TokenType == JsonToken.String) - { - return new TemplateKey(reader.Value.ToString()); - } - - throw new JsonException($"Unexpected token {reader.TokenType} when parsing TemplateKey."); + return new TemplateKey(reader.Value.ToString()); } - - /// - public override bool CanConvert(Type objectType) => typeof(TemplateKey) == objectType; + + throw new JsonException($"Unexpected token {reader.TokenType} when parsing TemplateKey."); } + + /// + public override bool CanConvert(Type objectType) => typeof(TemplateKey) == objectType; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/TemplateVersionConverter.cs b/Oxide.Ext.Discord/Json/Converters/TemplateVersionConverter.cs index 3694e585b..cbb6d7edb 100644 --- a/Oxide.Ext.Discord/Json/Converters/TemplateVersionConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/TemplateVersionConverter.cs @@ -3,41 +3,40 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +internal class TemplateVersionConverter : JsonConverter { - internal class TemplateVersionConverter : JsonConverter - { - private const string Token = "."; + private const string Token = "."; - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue(value.ToString()); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + string value = reader.Value.ToString(); + ReadOnlySpan span = value; + + if (!span.TryParseNextString(Token, out span, out ReadOnlySpan majorSpan) || !ushort.TryParse(majorSpan, out ushort major)) { - writer.WriteValue(value.ToString()); + throw new JsonSerializationException($"{value} is not a valid major template version for. Major: {majorSpan.ToString()} Path: {reader.Path}."); } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + if (!span.TryParseNextString(Token, out span, out ReadOnlySpan minorSpan) || !ushort.TryParse(minorSpan, out ushort minor)) { - string value = reader.Value.ToString(); - ReadOnlySpan span = value; - - if (!span.TryParseNextString(Token, out span, out ReadOnlySpan majorSpan) || !ushort.TryParse(majorSpan, out ushort major)) - { - throw new JsonSerializationException($"{value} is not a valid major template version for. Major: {majorSpan.ToString()} Path: {reader.Path}."); - } - if (!span.TryParseNextString(Token, out span, out ReadOnlySpan minorSpan) || !ushort.TryParse(minorSpan, out ushort minor)) - { - throw new JsonSerializationException($"{value} is not a valid minor template version for. Minor: {minorSpan.ToString()} Path: {reader.Path}."); - } - if (!span.TryParseNextString(Token, out span, out ReadOnlySpan revisionSpan) || !ushort.TryParse(revisionSpan, out ushort revision)) - { - throw new JsonSerializationException($"{value} is not a valid revision template version for. Revision: {revisionSpan.ToString()} Path: {reader.Path}."); - } - - return new TemplateVersion(major, minor, revision); + throw new JsonSerializationException($"{value} is not a valid minor template version for. Minor: {minorSpan.ToString()} Path: {reader.Path}."); } - - public override bool CanConvert(Type objectType) + if (!span.TryParseNextString(Token, out span, out ReadOnlySpan revisionSpan) || !ushort.TryParse(revisionSpan, out ushort revision)) { - return typeof(TemplateVersion) == objectType; + throw new JsonSerializationException($"{value} is not a valid revision template version for. Revision: {revisionSpan.ToString()} Path: {reader.Path}."); } + + return new TemplateVersion(major, minor, revision); + } + + public override bool CanConvert(Type objectType) + { + return typeof(TemplateVersion) == objectType; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Converters/UnixDateTimeConverter.cs b/Oxide.Ext.Discord/Json/Converters/UnixDateTimeConverter.cs index b69ad5ff4..34f3a16eb 100644 --- a/Oxide.Ext.Discord/Json/Converters/UnixDateTimeConverter.cs +++ b/Oxide.Ext.Discord/Json/Converters/UnixDateTimeConverter.cs @@ -2,47 +2,46 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// Converts a to and from a json long +/// +public class UnixDateTimeConverter : JsonConverter { /// - /// Converts a to and from a json long + /// Write to UnixTimeMilliseconds /// - public class UnixDateTimeConverter : JsonConverter + /// + /// + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - /// - /// Write to UnixTimeMilliseconds - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - DateTimeOffset dateTime = (DateTimeOffset)value; - writer.WriteValue(dateTime.ToUnixTimeMilliseconds()); - } + DateTimeOffset dateTime = (DateTimeOffset)value; + writer.WriteValue(dateTime.ToUnixTimeMilliseconds()); + } - /// - /// Convert to from UnixTimeMilliseconds - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - long value = JToken.ReadFrom(reader).ToObject(serializer); - return DateTimeOffset.FromUnixTimeMilliseconds(value); - } + /// + /// Convert to from UnixTimeMilliseconds + /// + /// + /// + /// + /// + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + long value = JToken.ReadFrom(reader).ToObject(serializer); + return DateTimeOffset.FromUnixTimeMilliseconds(value); + } - /// - /// Can the type be converted - /// - /// - /// - public override bool CanConvert(Type objectType) - { - return typeof(DateTimeOffset) == objectType; - } + /// + /// Can the type be converted + /// + /// + /// + public override bool CanConvert(Type objectType) + { + return typeof(DateTimeOffset) == objectType; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/DiscordJson.cs b/Oxide.Ext.Discord/Json/DiscordJson.cs new file mode 100644 index 000000000..80742371f --- /dev/null +++ b/Oxide.Ext.Discord/Json/DiscordJson.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +namespace Oxide.Ext.Discord.Json; + +internal static class DiscordJson +{ + internal static readonly JsonSerializerSettings Settings = new() + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }; + + internal static readonly JsonSerializerSettings IndentedSettings = new() + { + Formatting = Formatting.Indented + }; +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/JsonSettings.cs b/Oxide.Ext.Discord/Json/JsonSettings.cs deleted file mode 100644 index 98766f91e..000000000 --- a/Oxide.Ext.Discord/Json/JsonSettings.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Oxide.Ext.Discord.Json -{ - internal static class JsonSettings - { - internal static readonly JsonSerializerSettings Indented = new JsonSerializerSettings - { - Formatting = Formatting.Indented - }; - } -} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Serialization/DiscordJsonReader.cs b/Oxide.Ext.Discord/Json/Serialization/DiscordJsonReader.cs index 146a3b745..37fd84601 100644 --- a/Oxide.Ext.Discord/Json/Serialization/DiscordJsonReader.cs +++ b/Oxide.Ext.Discord/Json/Serialization/DiscordJsonReader.cs @@ -6,126 +6,123 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// This is a pooled JSON reader that can read as string, deserialize object, or populate a given object async +/// +public class DiscordJsonReader : BasePoolable { + internal readonly MemoryStream Stream; + private readonly StreamReader _reader; + /// - /// This is a pooled JSON reader that can read as string, deserialize object, or populate a given object async + /// Constructor /// - public class DiscordJsonReader : BasePoolable + public DiscordJsonReader() { - internal readonly MemoryStream Stream; - private readonly StreamReader _reader; - - /// - /// Constructor - /// - public DiscordJsonReader() - { - Stream = new MemoryStream(); - _reader = new StreamReader(Stream, DiscordEncoding.Instance.Encoding); - } + Stream = new MemoryStream(); + _reader = new StreamReader(Stream, DiscordEncoding.Instance.Encoding); + } - /// - /// Returns a pooled - /// - /// - public static DiscordJsonReader Create(DiscordPluginPool pluginPool) - { - return pluginPool.Get(); - } + /// + /// Returns a pooled + /// + /// + public static DiscordJsonReader Create(DiscordPluginPool pluginPool) + { + return pluginPool.Get(); + } - /// - /// Returns a pooled with stream loaded into it - /// - /// The to pool from - /// Stream to load - /// - public static DiscordJsonReader CreateFromStream(DiscordPluginPool pluginPool, Stream stream) - { - DiscordJsonReader reader = Create(pluginPool); - reader.CopyFrom(stream); - return reader; - } + /// + /// Returns a pooled with stream loaded into it + /// + /// The to pool from + /// Stream to load + /// + public static DiscordJsonReader CreateFromStream(DiscordPluginPool pluginPool, Stream stream) + { + DiscordJsonReader reader = Create(pluginPool); + reader.CopyFrom(stream); + return reader; + } - /// - /// Deserialize from stream to type {T} - /// - /// Serializer to use - /// Stream to read from - /// Type to return - /// - public static T DeserializeFrom(JsonSerializer serializer, Stream stream) - { - DiscordJsonReader reader = new DiscordJsonReader(); - reader.CopyFrom(stream); - T result = reader.Deserialize(serializer); - reader.Dispose(); - return result; - } + /// + /// Deserialize from stream to type {T} + /// + /// Serializer to use + /// Stream to read from + /// Type to return + /// + public static T DeserializeFrom(JsonSerializer serializer, Stream stream) + { + DiscordJsonReader reader = new(); + reader.CopyFrom(stream); + T result = reader.Deserialize(serializer); + reader.Dispose(); + return result; + } - /// - /// Copy from the given stream to our internal stream - /// - /// Stream to copy - public void CopyFrom(Stream stream) - { - ClearStream(); - stream.CopyToPooled(Stream); - } + /// + /// Copy from the given stream to our internal stream + /// + /// Stream to copy + public void CopyFrom(Stream stream) + { + ClearStream(); + stream.CopyToPooled(Stream); + } - /// - /// Returns the Stream data as a string - /// - /// String of the stream data - public string ReadAsString() + /// + /// Returns the Stream data as a string + /// + /// String of the stream data + public string ReadAsString() + { + ResetStream(); + return _reader.ReadToEnd(); + } + + /// + /// Deserializes the stream data to {T} + /// + /// to use with the Deserialization + /// Type to deserialize to + /// {T} + public T Deserialize(JsonSerializer serializer) + { + ResetStream(); + try { - ResetStream(); - return _reader.ReadToEnd(); + using JsonTextReader reader = new(_reader); + reader.CloseInput = false; + return serializer.Deserialize(reader); } - - /// - /// Deserializes the stream data to {T} - /// - /// to use with the Deserialization - /// Type to deserialize to - /// {T} - public T Deserialize(JsonSerializer serializer) + catch (Exception ex) { + Interface.Oxide.LogException($"Failed to Deserialize. Pos: {Stream.Position} Length: {Stream.Length}", ex); ResetStream(); - try - { - using (JsonTextReader reader = new JsonTextReader(_reader)) - { - reader.CloseInput = false; - return serializer.Deserialize(reader); - } - } - catch (Exception ex) - { - Interface.Oxide.LogException($"Failed to Deserialize. Pos: {Stream.Position} Length: {Stream.Length}", ex); - ResetStream(); - Interface.Oxide.LogDebug($"A:{ReadAsString()}"); - Interface.Oxide.LogDebug($"B:{DiscordEncoding.Instance.Encoding.GetString(Stream.ToArray(), 0, (int)Stream.Length)}"); - throw; - } + Interface.Oxide.LogDebug($"A:{ReadAsString()}"); + Interface.Oxide.LogDebug($"B:{DiscordEncoding.Instance.Encoding.GetString(Stream.ToArray(), 0, (int)Stream.Length)}"); + throw; } + } - private void ResetStream() - { - Stream.Position = 0; - _reader.DiscardBufferedData(); - } + private void ResetStream() + { + Stream.Position = 0; + _reader.DiscardBufferedData(); + } - private void ClearStream() - { - _reader.DiscardBufferedData(); - Stream.SetLength(0); - } + private void ClearStream() + { + _reader.DiscardBufferedData(); + Stream.SetLength(0); + } - /// - protected override void EnterPool() - { - ClearStream(); - } + /// + protected override void EnterPool() + { + ClearStream(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Serialization/DiscordJsonWriter.cs b/Oxide.Ext.Discord/Json/Serialization/DiscordJsonWriter.cs index bd8e1aee3..5e003a841 100644 --- a/Oxide.Ext.Discord/Json/Serialization/DiscordJsonWriter.cs +++ b/Oxide.Ext.Discord/Json/Serialization/DiscordJsonWriter.cs @@ -4,105 +4,101 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +/// +/// This is a pooled JSON writer that can write JSON to a stream +/// +public class DiscordJsonWriter : BasePoolable { /// - /// This is a pooled JSON writer that can write JSON to a stream + /// Stream that is written to /// - public class DiscordJsonWriter : BasePoolable - { - /// - /// Stream that is written to - /// - public readonly MemoryStream Stream; + public readonly MemoryStream Stream; - private readonly StreamWriter _streamWriter; - private readonly JsonTextWriter _writer; - private StreamReader _reader; + private readonly StreamWriter _streamWriter; + private readonly JsonTextWriter _writer; + private StreamReader _reader; - /// - /// Constructor - /// - public DiscordJsonWriter() - { - Stream = new MemoryStream(); - _streamWriter = new StreamWriter(Stream, DiscordEncoding.Instance.Encoding, 2048, true); - _writer = new JsonTextWriter(_streamWriter); - _writer.Formatting = Formatting.None; - } + /// + /// Constructor + /// + public DiscordJsonWriter() + { + Stream = new MemoryStream(); + _streamWriter = new StreamWriter(Stream, DiscordEncoding.Instance.Encoding, 2048, true); + _writer = new JsonTextWriter(_streamWriter); + _writer.Formatting = Formatting.None; + } - /// - /// Returns a pooled - /// - /// - public static DiscordJsonWriter Get(DiscordPluginPool pluginPool) - { - return pluginPool.Get(); - } + /// + /// Returns a pooled + /// + /// + public static DiscordJsonWriter Get(DiscordPluginPool pluginPool) + { + return pluginPool.Get(); + } - /// - /// Serializes the payload to the output stream - /// - /// The to pool from - /// Serializer to use - /// Payload to serialize - /// Output stream to write to - public static void WriteAndCopy(DiscordPluginPool pluginPool, JsonSerializer serializer, object payload, Stream output) - { - DiscordJsonWriter writer = Get(pluginPool); - writer.Write(serializer, payload); - writer.Stream.CopyToPooled(output); - writer.Dispose(); - } + /// + /// Serializes the payload to the output stream + /// + /// The to pool from + /// Serializer to use + /// Payload to serialize + /// Output stream to write to + public static void WriteAndCopy(DiscordPluginPool pluginPool, JsonSerializer serializer, object payload, Stream output) + { + DiscordJsonWriter writer = Get(pluginPool); + writer.Write(serializer, payload); + writer.Stream.CopyToPooled(output); + writer.Dispose(); + } - /// - /// Writes the payload to the Stream - /// - /// to serialize with - /// Payload to be serialized - public void Write(JsonSerializer serializer, object payload) - { - ClearStream(); - serializer.Serialize(_writer, payload); - _writer.Flush(); - _streamWriter.Flush(); - } + /// + /// Writes the payload to the Stream + /// + /// to serialize with + /// Payload to be serialized + public void Write(JsonSerializer serializer, object payload) + { + ClearStream(); + serializer.Serialize(_writer, payload); + _writer.Flush(); + _streamWriter.Flush(); + } - internal string ReadAsString() - { - //DiscordExtension.GlobalLogger.Debug($"{nameof(JsonWriterPoolable)}.{nameof(ReadAsStringAsync)} Read: {{0}} Position: {{1}}", Stream.Length, Stream.Position); - if (_reader == null) - { - _reader = new StreamReader(Stream, DiscordEncoding.Instance.Encoding, false, 2048, true); - } + internal string ReadAsString() + { + //DiscordExtension.GlobalLogger.Debug($"{nameof(JsonWriterPoolable)}.{nameof(ReadAsStringAsync)} Read: {{0}} Position: {{1}}", Stream.Length, Stream.Position); + _reader ??= new StreamReader(Stream, DiscordEncoding.Instance.Encoding, false, 2048, true); - ResetStream(); - return _reader.ReadToEnd(); - } + ResetStream(); + return _reader.ReadToEnd(); + } - private void ResetStream() - { - Flush(); - Stream.Position = 0; - } + private void ResetStream() + { + Flush(); + Stream.Position = 0; + } - private void ClearStream() - { - Flush(); - Stream.SetLength(0); - } + private void ClearStream() + { + Flush(); + Stream.SetLength(0); + } - private void Flush() - { - _writer.Flush(); - _streamWriter.Flush(); - _reader?.DiscardBufferedData(); - } + private void Flush() + { + _writer.Flush(); + _streamWriter.Flush(); + _reader?.DiscardBufferedData(); + } - /// - protected override void EnterPool() - { - ClearStream(); - } + /// + protected override void EnterPool() + { + ClearStream(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Json/Utilities/JsonEnumUtils.cs b/Oxide.Ext.Discord/Json/Utilities/JsonEnumUtils.cs index cd03b7bf4..feb93d88d 100644 --- a/Oxide.Ext.Discord/Json/Utilities/JsonEnumUtils.cs +++ b/Oxide.Ext.Discord/Json/Utilities/JsonEnumUtils.cs @@ -5,80 +5,79 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Json +namespace Oxide.Ext.Discord.Json; + +internal static class JsonEnumUtils { - internal static class JsonEnumUtils - { - private static readonly ConcurrentDictionary EnumData = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary EnumData = new(); - internal static object GetDefault(Type enumType) => GetEnumData(enumType).Default; + internal static object GetDefault(Type enumType) => GetEnumData(enumType).Default; - internal static string ToEnumName(Type enumType, string enumText) + internal static string ToEnumName(Type enumType, string enumText) + { + EnumData data = GetEnumData(enumType); + if (enumText.IndexOf(",", StringComparison.Ordinal) == -1) { - EnumData data = GetEnumData(enumType); - if (enumText.IndexOf(",", StringComparison.Ordinal) == -1) - { - return data.NameToProperty[enumText]; - } - - return ParseEnumNameList(enumText, data.NameToProperty); + return data.NameToProperty[enumText]; } + + return ParseEnumNameList(enumText, data.NameToProperty); + } - internal static string FromEnumName(Type enumType, string enumText) + internal static string FromEnumName(Type enumType, string enumText) + { + EnumData data = GetEnumData(enumType); + if (enumText.IndexOf(",", StringComparison.Ordinal) == -1) { - EnumData data = GetEnumData(enumType); - if (enumText.IndexOf(",", StringComparison.Ordinal) == -1) - { - return data.PropertyToName[enumText]; - } - - return ParseEnumNameList(enumText, data.PropertyToName); + return data.PropertyToName[enumText]; } + + return ParseEnumNameList(enumText, data.PropertyToName); + } - private static string ParseEnumNameList(string enumText, Hash lookup) + private static string ParseEnumNameList(string enumText, Hash lookup) + { + string[] enums = enumText.Split(','); + for (int index = 0; index < enums.Length; index++) { - string[] enums = enumText.Split(','); - for (int index = 0; index < enums.Length; index++) - { - enums[index] = lookup[enums[index].Trim()]; - } - - return string.Join(", ", enums); + enums[index] = lookup[enums[index].Trim()]; } - private static EnumData GetEnumData(Type type) - { - if (!EnumData.TryGetValue(type, out EnumData data)) - { - data = new EnumData(type); - EnumData[type] = data; - } - - return data; - } + return string.Join(", ", enums); } - internal class EnumData + private static EnumData GetEnumData(Type type) { - public readonly object Default; - public readonly Hash NameToProperty = new Hash(); - public readonly Hash PropertyToName = new Hash(); - - public EnumData(Type type) + if (!EnumData.TryGetValue(type, out EnumData data)) { - Default = type.GetDefault(); - foreach (FieldInfo field in type.GetFields()) - { - string name = field.Name; - string propertyName = field.GetCustomAttribute()?.Name ?? field.Name; - Add(name, propertyName); - } + data = new EnumData(type); + EnumData[type] = data; } - private void Add(string name, string propertyName) + return data; + } +} + +internal class EnumData +{ + public readonly object Default; + public readonly Hash NameToProperty = new(); + public readonly Hash PropertyToName = new(); + + public EnumData(Type type) + { + Default = type.GetDefault(); + foreach (FieldInfo field in type.GetFields()) { - NameToProperty[name] = propertyName; - PropertyToName[propertyName] = name; + string name = field.Name; + string propertyName = field.GetCustomAttribute()?.Name ?? field.Name; + Add(name, propertyName); } } + + private void Add(string name, string propertyName) + { + NameToProperty[name] = propertyName; + PropertyToName[propertyName] = name; + } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/AppCommands/AppCommandHandler.cs b/Oxide.Ext.Discord/Libraries/AppCommands/AppCommandHandler.cs index ebc91a248..26bfd6274 100644 --- a/Oxide.Ext.Discord/Libraries/AppCommands/AppCommandHandler.cs +++ b/Oxide.Ext.Discord/Libraries/AppCommands/AppCommandHandler.cs @@ -7,106 +7,101 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal class AppCommandHandler { - internal class AppCommandHandler + public bool IsEmpty => _commands.Count == 0; + private readonly ConcurrentDictionary _commands = new(); + private readonly List _components = []; + private readonly ILogger _logger; + + public AppCommandHandler(ILogger logger) { - public bool IsEmpty => _commands.Count == 0; - private readonly ConcurrentDictionary _commands = new ConcurrentDictionary(); - private readonly List _components = new List(); - private readonly ILogger _logger; + _logger = logger; + } - public AppCommandHandler(ILogger logger) + public BaseAppCommand GetCommandById(AppCommandId id) + { + return id.Type switch { - _logger = logger; - } + InteractionType.ApplicationCommand or InteractionType.ApplicationCommandAutoComplete => _commands.GetValueOrDefault(id), + InteractionType.MessageComponent or InteractionType.ModalSubmit => GetComponentCommand(id), + _ => null + }; - public BaseAppCommand GetCommandById(AppCommandId id) - { - switch (id.Type) - { - case InteractionType.ApplicationCommand: - case InteractionType.ApplicationCommandAutoComplete: - return _commands.GetValueOrDefault(id); - case InteractionType.MessageComponent: - case InteractionType.ModalSubmit: - return GetComponentCommand(id); - } + } - return null; + public void AddAppCommand(BaseAppCommand command) + { + if (command is ComponentCommand component) + { + _components.Add(component); } - - public void AddAppCommand(BaseAppCommand command) + else { - if (command is ComponentCommand component) - { - _components.Add(component); - } - else - { - _commands[command.CommandId] = command; - } - - _logger.Verbose($"{nameof(AppCommandHandler)}.{nameof(AddAppCommand)} Command: {{0}}", command.CommandId); + _commands[command.CommandId] = command; } + + _logger.Verbose($"{nameof(AppCommandHandler)}.{nameof(AddAppCommand)} Command: {{0}}", command.CommandId); + } - public bool RemoveAppCommand(BaseAppCommand command) + public bool RemoveAppCommand(BaseAppCommand command) + { + _logger.Verbose($"{nameof(AppCommandHandler)}.{nameof(RemoveAppCommand)} Command: {{0}}", command.CommandId); + if (command is ComponentCommand component) { - _logger.Verbose($"{nameof(AppCommandHandler)}.{nameof(RemoveAppCommand)} Command: {{0}}", command.CommandId); - if (command is ComponentCommand component) - { - return _components.Remove(component); - } - - return _commands.TryRemove(command.CommandId, out _); + return _components.Remove(component); } + + return _commands.TryRemove(command.CommandId, out _); + } - private ComponentCommand GetComponentCommand(AppCommandId id) + private ComponentCommand GetComponentCommand(AppCommandId id) + { + for (int index = 0; index < _components.Count; index++) { - for (int index = 0; index < _components.Count; index++) + ComponentCommand command = _components[index]; + if (command.IsForCommand(id)) { - ComponentCommand command = _components[index]; - if (command.IsForCommand(id)) - { - return command; - } + return command; } - - return null; } - public IEnumerable GetCommandsForPlugin(Plugin plugin) - { - PluginId id = plugin.Id(); - foreach (BaseAppCommand command in _commands.Values) - { - if (command.IsForPlugin(id)) - { - yield return command; - } - } + return null; + } - for (int index = 0; index < _components.Count; index++) + public IEnumerable GetCommandsForPlugin(Plugin plugin) + { + PluginId id = plugin.Id(); + foreach (BaseAppCommand command in _commands.Values) + { + if (command.IsForPlugin(id)) { - ComponentCommand command = _components[index]; - if (command.IsForPlugin(id)) - { - yield return command; - } + yield return command; } } - public IEnumerable GetCommands() + for (int index = 0; index < _components.Count; index++) { - foreach (BaseAppCommand command in _commands.Values) + ComponentCommand command = _components[index]; + if (command.IsForPlugin(id)) { yield return command; } + } + } + + public IEnumerable GetCommands() + { + foreach (BaseAppCommand command in _commands.Values) + { + yield return command; + } - for (int index = 0; index < _components.Count; index++) - { - yield return _components[index]; - } + for (int index = 0; index < _components.Count; index++) + { + yield return _components[index]; } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AppCommand.cs b/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AppCommand.cs index 635f4d35b..1010d3482 100644 --- a/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AppCommand.cs +++ b/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AppCommand.cs @@ -4,27 +4,26 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal class AppCommand : BaseAppCommand { - internal class AppCommand : BaseAppCommand - { - private readonly Action _callback; + private readonly Action _callback; - public AppCommand(Plugin plugin, Snowflake appId, AppCommandId command, Action callback, ILogger logger) : base(plugin, appId, command, logger) - { - _callback = callback; - } + public AppCommand(Plugin plugin, Snowflake appId, AppCommandId command, Action callback, ILogger logger) : base(plugin, appId, command, logger) + { + _callback = callback; + } - protected override string GetCommandType() => "Application Command"; + protected override string GetCommandType() => "Application Command"; - protected override void RunCommand(DiscordInteraction interaction) => _callback(interaction, interaction.Parsed); + protected override void RunCommand(DiscordInteraction interaction) => _callback(interaction, interaction.Parsed); - protected override string GetExceptionMessage() => $"An error occured during callback. Plugin: {PluginName} Method: {_callback.Method.DeclaringType?.Name}.{_callback.Method.Name}"; + protected override string GetExceptionMessage() => $"An error occured during callback. Plugin: {PluginName} Method: {_callback.Method.DeclaringType?.Name}.{_callback.Method.Name}"; - public override void LogDebug(DebugLogger logger) - { - base.LogDebug(logger); - logger.AppendMethod("Callback", _callback.Method); - } + public override void LogDebug(DebugLogger logger) + { + base.LogDebug(logger); + logger.AppendMethod("Callback", _callback.Method); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AppCommandId.cs b/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AppCommandId.cs index 2908e36f5..e2bea3596 100644 --- a/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AppCommandId.cs +++ b/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AppCommandId.cs @@ -1,72 +1,51 @@ using System; -using System.Text; using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Entities; +using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal readonly record struct AppCommandId { - internal struct AppCommandId : IEquatable + public readonly InteractionType Type; + public readonly string Command; + public readonly string Group; + public readonly string SubCommand; + public readonly string Argument; + + public AppCommandId(InteractionType type, string command, string group = null, string subCommand = null, string argument = null) { - public readonly InteractionType Type; - public readonly string Command; - public readonly string Group; - public readonly string SubCommand; - public readonly string Argument; + if(string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); - public AppCommandId(InteractionType type, string command, string group = null, string subCommand = null, string argument = null) + Type = type; + Command = command; + Group = group; + SubCommand = subCommand; + Argument = argument; + } + + public override string ToString() + { + ValueStringBuilder sb = new(); + sb.Append(EnumCache.Instance.ToString(Type)); + sb.Append(':'); + sb.Append(Command); + if (!string.IsNullOrEmpty(Group)) { - if(string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); - - Type = type; - Command = command; - Group = group; - SubCommand = subCommand; - Argument = argument; + sb.Append('/'); + sb.Append(Group); } - - public static bool operator == (AppCommandId left, AppCommandId right) => left.Equals(right); - public static bool operator !=(AppCommandId left, AppCommandId right) => !(left == right); - - public bool Equals(AppCommandId other) => Type == other.Type && Command == other.Command && Group == other.Group && SubCommand == other.SubCommand && Argument == other.Argument; - - public override bool Equals(object obj) => obj is AppCommandId other && Equals(other); - - public override int GetHashCode() + if (!string.IsNullOrEmpty(SubCommand)) { - unchecked - { - int hashCode = (int)Type; - hashCode = (hashCode * 397) ^ (Command != null ? Command.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (Group != null ? Group.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (SubCommand != null ? SubCommand.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (Argument != null ? Argument.GetHashCode() : 0); - return hashCode; - } + sb.Append('/'); + sb.Append(SubCommand); } - - public override string ToString() + if (!string.IsNullOrEmpty(Argument)) { - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); - sb.Append(EnumCache.Instance.ToString(Type)); - sb.Append(':'); - sb.Append(Command); - if (!string.IsNullOrEmpty(Group)) - { - sb.Append('/'); - sb.Append(Group); - } - if (!string.IsNullOrEmpty(SubCommand)) - { - sb.Append('/'); - sb.Append(SubCommand); - } - if (!string.IsNullOrEmpty(Argument)) - { - sb.Append('#'); - sb.Append(Argument); - } - - return DiscordPool.Internal.ToStringAndFree(sb); + sb.Append('#'); + sb.Append(Argument); } + + return sb.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AutoCompleteCommand.cs b/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AutoCompleteCommand.cs index 6dacfc5ed..e6e595f6d 100644 --- a/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AutoCompleteCommand.cs +++ b/Oxide.Ext.Discord/Libraries/AppCommands/Commands/AutoCompleteCommand.cs @@ -3,21 +3,20 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal class AutoCompleteCommand : BaseAppCommand { - internal class AutoCompleteCommand : BaseAppCommand - { - private readonly Action _callback; + private readonly Action _callback; - public AutoCompleteCommand(Plugin plugin, Snowflake appId, AppCommandId command, Action callback, ILogger logger) : base(plugin, appId, command, logger) - { - _callback = callback; - } + public AutoCompleteCommand(Plugin plugin, Snowflake appId, AppCommandId command, Action callback, ILogger logger) : base(plugin, appId, command, logger) + { + _callback = callback; + } - protected override string GetCommandType() => "AutoComplete Command"; + protected override string GetCommandType() => "AutoComplete Command"; - protected override void RunCommand(DiscordInteraction interaction) => _callback(interaction, interaction.Focused); + protected override void RunCommand(DiscordInteraction interaction) => _callback(interaction, interaction.Focused); - protected override string GetExceptionMessage() => $"An error occured during callback. Plugin: {PluginName} Method: {_callback.Method.DeclaringType.Name}.{_callback.Method.Name}"; - } + protected override string GetExceptionMessage() => $"An error occured during callback. Plugin: {PluginName} Method: {_callback.Method.DeclaringType?.Name}.{_callback.Method.Name}"; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/AppCommands/Commands/BaseAppCommand.cs b/Oxide.Ext.Discord/Libraries/AppCommands/Commands/BaseAppCommand.cs index a30c7fee8..adeda381d 100644 --- a/Oxide.Ext.Discord/Libraries/AppCommands/Commands/BaseAppCommand.cs +++ b/Oxide.Ext.Discord/Libraries/AppCommands/Commands/BaseAppCommand.cs @@ -7,72 +7,71 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a Base Registered Application Command +/// +internal abstract class BaseAppCommand : IDebugLoggable { + internal readonly Snowflake AppId; + internal readonly AppCommandId CommandId; + internal readonly string PluginName; + private readonly PluginId _pluginId; + private readonly ILogger _logger; + /// - /// Represents a Base Registered Application Command + /// Constructor /// - internal abstract class BaseAppCommand : IDebugLoggable + /// Plugin for the command + /// ID of the for the command + /// Command ID for the command + /// Logger for the command + protected BaseAppCommand(Plugin plugin, Snowflake appId, AppCommandId commandId, ILogger logger) { - internal readonly Snowflake AppId; - internal readonly AppCommandId CommandId; - internal readonly string PluginName; - private readonly PluginId _pluginId; - private readonly ILogger _logger; + PluginName = plugin.FullName(); + _pluginId = plugin.Id(); + AppId = appId; + CommandId = commandId; + _logger = logger; + } - /// - /// Constructor - /// - /// Plugin for the command - /// ID of the for the command - /// Command ID for the command - /// Logger for the command - protected BaseAppCommand(Plugin plugin, Snowflake appId, AppCommandId commandId, ILogger logger) + public void HandleCommand(DiscordInteraction interaction) + { + if (ThreadEx.IsMain) { - PluginName = plugin.FullName(); - _pluginId = plugin.Id(); - AppId = appId; - CommandId = commandId; - _logger = logger; + HandleCommandInternal(interaction); } - - public void HandleCommand(DiscordInteraction interaction) + else { - if (ThreadEx.IsMain) - { - HandleCommandInternal(interaction); - } - else - { - AppCommandCallback.Start(this, interaction); - } + AppCommandCallback.Start(this, interaction); } + } - internal void HandleCommandInternal(DiscordInteraction interaction) + internal void HandleCommandInternal(DiscordInteraction interaction) + { + try { - try - { - RunCommand(interaction); - } - catch (Exception ex) - { - _logger.Exception(GetExceptionMessage(), ex); - } + RunCommand(interaction); } + catch (Exception ex) + { + _logger.Exception(GetExceptionMessage(), ex); + } + } - public bool IsForPlugin(PluginId id) => _pluginId == id; + public bool IsForPlugin(PluginId id) => _pluginId == id; - protected abstract string GetCommandType(); + protected abstract string GetCommandType(); - protected abstract string GetExceptionMessage(); + protected abstract string GetExceptionMessage(); - protected abstract void RunCommand(DiscordInteraction interaction); + protected abstract void RunCommand(DiscordInteraction interaction); - public virtual void LogDebug(DebugLogger logger) - { - logger.AppendField("Type", GetCommandType()); - logger.AppendField("Plugin", PluginName); - logger.AppendField("Command", CommandId.ToString()); - } + public virtual void LogDebug(DebugLogger logger) + { + logger.AppendField("Type", GetCommandType()); + logger.AppendField("Plugin", PluginName); + logger.AppendField("Command", CommandId.ToString()); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/AppCommands/Commands/ComponentCommand.cs b/Oxide.Ext.Discord/Libraries/AppCommands/Commands/ComponentCommand.cs index 2ebb33ab3..29274f980 100644 --- a/Oxide.Ext.Discord/Libraries/AppCommands/Commands/ComponentCommand.cs +++ b/Oxide.Ext.Discord/Libraries/AppCommands/Commands/ComponentCommand.cs @@ -4,29 +4,28 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal class ComponentCommand : BaseAppCommand { - internal class ComponentCommand : BaseAppCommand - { - private readonly Action _callback; + private readonly Action _callback; - public ComponentCommand(Plugin plugin, Snowflake appId, AppCommandId customId, Action callback, ILogger logger) : base(plugin, appId, customId, logger) - { - _callback = callback; - } + public ComponentCommand(Plugin plugin, Snowflake appId, AppCommandId customId, Action callback, ILogger logger) : base(plugin, appId, customId, logger) + { + _callback = callback; + } - protected override string GetCommandType() => "Component Command"; + protected override string GetCommandType() => "Component Command"; - protected override void RunCommand(DiscordInteraction interaction) => _callback(interaction); + protected override void RunCommand(DiscordInteraction interaction) => _callback(interaction); - protected override string GetExceptionMessage() => $"An error occured during callback. Plugin: {PluginName} Method: {_callback.Method.DeclaringType?.Name}.{_callback.Method.Name}"; + protected override string GetExceptionMessage() => $"An error occured during callback. Plugin: {PluginName} Method: {_callback.Method.DeclaringType?.Name}.{_callback.Method.Name}"; - public bool IsForCommand(AppCommandId id) => id.Command.StartsWith(CommandId.Command); + public bool IsForCommand(AppCommandId id) => id.Command.StartsWith(CommandId.Command); - public override void LogDebug(DebugLogger logger) - { - base.LogDebug(logger); - logger.AppendField("Command Name", CommandId.Command); - } + public override void LogDebug(DebugLogger logger) + { + base.LogDebug(logger); + logger.AppendField("Command Name", CommandId.Command); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/AppCommands/DiscordAppCommand.cs b/Oxide.Ext.Discord/Libraries/AppCommands/DiscordAppCommand.cs index bac12e05a..e61190003 100644 --- a/Oxide.Ext.Discord/Libraries/AppCommands/DiscordAppCommand.cs +++ b/Oxide.Ext.Discord/Libraries/AppCommands/DiscordAppCommand.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Text; using Oxide.Core.Plugins; using Oxide.Ext.Discord.Attributes; +using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Connections; using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; @@ -12,307 +12,292 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Application Command Oxide Library handler +/// Routes Application Commands to their respective hook method handlers instead of having to manually handle it. +/// +public class DiscordAppCommand : BaseDiscordLibrary, IDebugLoggable { + private readonly ConcurrentDictionary _handlers = new(); + private readonly Func _create; + private readonly ILogger _logger; + /// - /// Application Command Oxide Library handler - /// Routes Application Commands to their respective hook method handlers instead of having to manually handle it. + /// Constructor /// - public class DiscordAppCommand : BaseDiscordLibrary, IDebugLoggable + /// Logger for the library + internal DiscordAppCommand(ILogger logger) { - private readonly ConcurrentDictionary _handlers = new ConcurrentDictionary(); - private readonly Func _create; - private readonly ILogger _logger; - - /// - /// Constructor - /// - /// Logger for the library - internal DiscordAppCommand(ILogger logger) - { - _logger = logger; - _create = id => new AppCommandHandler(_logger); - } + _logger = logger; + _create = _ => new AppCommandHandler(_logger); + } - private AppCommandHandler GetCommandHandler(Snowflake applicationId) => _handlers.TryGetValue(applicationId, out AppCommandHandler handler) ? handler : null; + private AppCommandHandler GetCommandHandler(Snowflake applicationId) => _handlers.GetValueOrDefault(applicationId); - private AppCommandHandler GetOrAddCommandHandler(Snowflake applicationId) => _handlers.GetOrAdd(applicationId, _create); + private AppCommandHandler GetOrAddCommandHandler(Snowflake applicationId) => _handlers.GetOrAdd(applicationId, _create); - /// - /// Registers a new Application Command for the given plugin - /// - /// the Application Command is for - /// ID of the for the command - /// Callback for the command - /// Command name - /// Sub Command Group for the command - /// Sub Command for the command - /// Thrown if inputs are null - public void AddApplicationCommand(Plugin plugin, Snowflake applicationId, Action callback, string command, string group = null, string subCommand = null) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - InvalidSnowflakeException.ThrowIfInvalid(applicationId, nameof(applicationId)); - if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); - if (callback == null) throw new ArgumentNullException(nameof(callback)); + /// + /// Registers a new Application Command for the given plugin + /// + /// the Application Command is for + /// ID of the for the command + /// Callback for the command + /// Command name + /// Sub Command Group for the command + /// Sub Command for the command + /// Thrown if inputs are null + public void AddApplicationCommand(Plugin plugin, Snowflake applicationId, Action callback, string command, string group = null, string subCommand = null) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + InvalidSnowflakeException.ThrowIfInvalid(applicationId); + if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); + if (callback == null) throw new ArgumentNullException(nameof(callback)); - AppCommandHandler handler = GetOrAddCommandHandler(applicationId); - const InteractionType Type = InteractionType.ApplicationCommand; - AppCommandId commandId = new AppCommandId(Type, command, group, subCommand); + AppCommandHandler handler = GetOrAddCommandHandler(applicationId); + const InteractionType Type = InteractionType.ApplicationCommand; + AppCommandId commandId = new(Type, command, group, subCommand); - BaseAppCommand existing = handler.GetCommandById(commandId); - if (existing != null && !existing.IsForPlugin(plugin.Id())) - { - _logger.Warning("{0} has replaced the '{1}' ({2}) discord application command previously registered by {3}", plugin.PluginName(), command, Type, existing.PluginName); - } - - handler.AddAppCommand(new AppCommand(plugin, applicationId, commandId, callback, _logger)); - _logger.Debug("Adding App Command For: {0} Command: {1} Callback: {2}", plugin.PluginName(), commandId, callback.Method.Name); + BaseAppCommand existing = handler.GetCommandById(commandId); + if (existing != null && !existing.IsForPlugin(plugin.Id())) + { + _logger.Warning("{0} has replaced the '{1}' ({2}) discord application command previously registered by {3}", plugin.PluginName(), command, Type, existing.PluginName); } - /// - /// Registers a new Application Command for the given plugin - /// - /// the Application Command is for - /// ID of For the command - /// Callback for the command - /// Command name - /// Command Argument name for the Auto Complete - /// Sub Command Group for the command - /// Sub Command for the command - /// Thrown if inputs are null - public void AddAutoCompleteCommand(Plugin plugin, Snowflake applicationId, Action callback, string command, string argument, string group = null, string subCommand = null) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - InvalidSnowflakeException.ThrowIfInvalid(applicationId, nameof(applicationId)); - if (callback == null) throw new ArgumentNullException(nameof(callback)); - if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); - if (string.IsNullOrEmpty(argument)) throw new ArgumentNullException(nameof(argument)); - - AppCommandHandler handler = GetOrAddCommandHandler(applicationId); - const InteractionType Type = InteractionType.ApplicationCommandAutoComplete; - AppCommandId commandId = new AppCommandId(Type, command, group, subCommand, argument); + handler.AddAppCommand(new AppCommand(plugin, applicationId, commandId, callback, _logger)); + _logger.Debug("Adding App Command For: {0} Command: {1} Callback: {2}", plugin.PluginName(), commandId, callback.Method.Name); + } - BaseAppCommand existing = handler.GetCommandById(commandId); - if (existing != null && !existing.IsForPlugin(plugin.Id())) - { - _logger.Warning("{0} has replaced the '{1}' ({2}) discord auto complete command previously registered by {3}", plugin.PluginName(), command, Type, existing.PluginName); - } + /// + /// Registers a new Application Command for the given plugin + /// + /// the Application Command is for + /// ID of For the command + /// Callback for the command + /// Command name + /// Command Argument name for the Auto Complete + /// Sub Command Group for the command + /// Sub Command for the command + /// Thrown if inputs are null + public void AddAutoCompleteCommand(Plugin plugin, Snowflake applicationId, Action callback, string command, string argument, string group = null, string subCommand = null) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + InvalidSnowflakeException.ThrowIfInvalid(applicationId); + if (callback == null) throw new ArgumentNullException(nameof(callback)); + if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); + if (string.IsNullOrEmpty(argument)) throw new ArgumentNullException(nameof(argument)); - handler.AddAppCommand(new AutoCompleteCommand(plugin, applicationId, commandId, callback, _logger)); - _logger.Debug("Adding Auto Complete Command For: {0} Command: {1} Callback: {2}", plugin.PluginName(), commandId, callback.Method.Name); - } + AppCommandHandler handler = GetOrAddCommandHandler(applicationId); + const InteractionType Type = InteractionType.ApplicationCommandAutoComplete; + AppCommandId commandId = new(Type, command, group, subCommand, argument); - /// - /// Adds a Command type. - /// This matches CustomId with starts with - /// - /// Plugin the command is for - /// ID of for the command - /// Command to match with Starts with - /// Callback for the command - public void AddMessageComponentCommand(Plugin plugin, Snowflake applicationId, string customId, Action callback) + BaseAppCommand existing = handler.GetCommandById(commandId); + if (existing != null && !existing.IsForPlugin(plugin.Id())) { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - InvalidSnowflakeException.ThrowIfInvalid(applicationId, nameof(applicationId)); - if (string.IsNullOrEmpty(customId)) throw new ArgumentNullException(nameof(customId)); - if (callback == null) throw new ArgumentNullException(nameof(callback)); + _logger.Warning("{0} has replaced the '{1}' ({2}) discord auto complete command previously registered by {3}", plugin.PluginName(), command, Type, existing.PluginName); + } - AppCommandHandler handler = GetOrAddCommandHandler(applicationId); - const InteractionType Type = InteractionType.MessageComponent; - AppCommandId commandId = new AppCommandId(Type, customId); + handler.AddAppCommand(new AutoCompleteCommand(plugin, applicationId, commandId, callback, _logger)); + _logger.Debug("Adding Auto Complete Command For: {0} Command: {1} Callback: {2}", plugin.PluginName(), commandId, callback.Method.Name); + } + + /// + /// Adds a Command type. + /// This matches CustomId with starts with + /// + /// Plugin the command is for + /// ID of for the command + /// Command to match with Starts with + /// Callback for the command + public void AddMessageComponentCommand(Plugin plugin, Snowflake applicationId, string customId, Action callback) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + InvalidSnowflakeException.ThrowIfInvalid(applicationId); + if (string.IsNullOrEmpty(customId)) throw new ArgumentNullException(nameof(customId)); + if (callback == null) throw new ArgumentNullException(nameof(callback)); - BaseAppCommand existing = handler.GetCommandById(commandId); - if (existing != null && !existing.IsForPlugin(plugin.Id())) - { - _logger.Warning("{0} has replaced the '{1}' ({2}) discord message component command previously registered by {3}", plugin.PluginName(), customId, Type, existing.PluginName); - } + AppCommandHandler handler = GetOrAddCommandHandler(applicationId); + const InteractionType Type = InteractionType.MessageComponent; + AppCommandId commandId = new(Type, customId); - handler.AddAppCommand(new ComponentCommand(plugin, applicationId, commandId, callback, _logger)); - _logger.Debug("Adding Message Component Command For: {0} CustomId: {1} Callback: {2}", plugin.PluginName(), customId, callback.Method.Name); - } - - /// - /// Adds a Command type. - /// This matches CustomId with starts with - /// - /// Plugin the command is for - /// ID of for the command - /// Command to match with Starts with - /// Callback for the command - public void AddModalSubmitCommand(Plugin plugin, Snowflake applicationId, string customId, Action callback) + BaseAppCommand existing = handler.GetCommandById(commandId); + if (existing != null && !existing.IsForPlugin(plugin.Id())) { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - InvalidSnowflakeException.ThrowIfInvalid(applicationId, nameof(applicationId)); - if (string.IsNullOrEmpty(customId)) throw new ArgumentNullException(nameof(customId)); - if (callback == null) throw new ArgumentNullException(nameof(callback)); + _logger.Warning("{0} has replaced the '{1}' ({2}) discord message component command previously registered by {3}", plugin.PluginName(), customId, Type, existing.PluginName); + } - const InteractionType Type = InteractionType.ModalSubmit; - AppCommandHandler handler = GetOrAddCommandHandler(applicationId); - AppCommandId commandId = new AppCommandId(Type, customId); + handler.AddAppCommand(new ComponentCommand(plugin, applicationId, commandId, callback, _logger)); + _logger.Debug("Adding Message Component Command For: {0} CustomId: {1} Callback: {2}", plugin.PluginName(), customId, callback.Method.Name); + } + + /// + /// Adds a Command type. + /// This matches CustomId with starts with + /// + /// Plugin the command is for + /// ID of for the command + /// Command to match with Starts with + /// Callback for the command + public void AddModalSubmitCommand(Plugin plugin, Snowflake applicationId, string customId, Action callback) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + InvalidSnowflakeException.ThrowIfInvalid(applicationId); + if (string.IsNullOrEmpty(customId)) throw new ArgumentNullException(nameof(customId)); + if (callback == null) throw new ArgumentNullException(nameof(callback)); - BaseAppCommand existing = handler.GetCommandById(commandId); - if (existing != null && !existing.IsForPlugin(plugin.Id())) - { - _logger.Warning("{0} has replaced the '{1}' ({2}) discord modal submit command previously registered by {3}", plugin.PluginName(), customId, Type, existing.PluginName); - } + const InteractionType Type = InteractionType.ModalSubmit; + AppCommandHandler handler = GetOrAddCommandHandler(applicationId); + AppCommandId commandId = new(Type, customId); - handler.AddAppCommand(new ComponentCommand(plugin, applicationId, commandId, callback, _logger)); - _logger.Debug("Adding Modal Submit Command For: {0} CustomId: {1} Callback: {2}", plugin.PluginName(), customId, callback.Method.Name); + BaseAppCommand existing = handler.GetCommandById(commandId); + if (existing != null && !existing.IsForPlugin(plugin.Id())) + { + _logger.Warning("{0} has replaced the '{1}' ({2}) discord modal submit command previously registered by {3}", plugin.PluginName(), customId, Type, existing.PluginName); } + + handler.AddAppCommand(new ComponentCommand(plugin, applicationId, commandId, callback, _logger)); + _logger.Debug("Adding Modal Submit Command For: {0} CustomId: {1} Callback: {2}", plugin.PluginName(), customId, callback.Method.Name); + } - /// - /// Removes an application command - /// - /// Plugin to remove the command for - /// for the command - /// Type of the command - /// Command name - /// Sub Command Group for the command - /// Sub Command for the command - /// Thrown if command is null or empty - public void RemoveApplicationCommand(Plugin plugin, DiscordApplication app, InteractionType type, string command, string group, string subCommand) - { - if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); + /// + /// Removes an application command + /// + /// Plugin to remove the command for + /// for the command + /// Type of the command + /// Command name + /// Sub Command Group for the command + /// Sub Command for the command + /// Thrown if command is null or empty + public void RemoveApplicationCommand(Plugin plugin, DiscordApplication app, InteractionType type, string command, string group, string subCommand) + { + if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); - BaseAppCommand appCommand = GetCommandHandler(app.Id).GetCommandById(new AppCommandId(type, command, group, subCommand)); - if (appCommand != null && appCommand.IsForPlugin(plugin.Id())) - { - RemoveApplicationCommandInternal(appCommand); - } + BaseAppCommand appCommand = GetCommandHandler(app.Id).GetCommandById(new AppCommandId(type, command, group, subCommand)); + if (appCommand != null && appCommand.IsForPlugin(plugin.Id())) + { + RemoveApplicationCommandInternal(appCommand); } + } - private void RemoveApplicationCommandInternal(BaseAppCommand appCommand) + private void RemoveApplicationCommandInternal(BaseAppCommand appCommand) + { + AppCommandHandler handler = GetCommandHandler(appCommand.AppId); + if (handler == null) { - AppCommandHandler handler = GetCommandHandler(appCommand.AppId); - if (handler == null) - { - return; - } - - if (!handler.RemoveAppCommand(appCommand)) - { - return; - } + return; + } - if (handler.IsEmpty) - { - _handlers.TryRemove(appCommand.AppId, out _); - } + if (!handler.RemoveAppCommand(appCommand)) + { + return; } - internal void RegisterApplicationCommands(PluginSetup data, BotConnection connection) + if (handler.IsEmpty) { - _logger.Debug("Registering application commands for {0}", data.PluginName); + _handlers.TryRemove(appCommand.AppId, out _); + } + } - Plugin plugin = data.Plugin; - Snowflake applicationId = connection.ApplicationId; - foreach (PluginHookResult hook in data.GetCallbacksWithAttribute()) + internal void RegisterApplicationCommands(Plugin plugin, PluginSetup setup, BotConnection connection) + { + _logger.Debug("Registering application commands for {0}", setup.PluginName); + + Snowflake applicationId = connection.ApplicationId; + foreach (PluginHookResult hook in setup.GetCallbacksWithAttribute()) + { + switch (hook.Attribute) { - switch (hook.Attribute) + case DiscordAutoCompleteCommandAttribute autoComplete: { - case DiscordAutoCompleteCommandAttribute autoComplete: + Action callback = hook.Method.CreateDelegate(plugin); + if (callback != null) { - Action callback = hook.Method.CreateDelegate(plugin); - if (callback != null) - { - AddAutoCompleteCommand(plugin, applicationId, callback, autoComplete.Command, autoComplete.ArgumentName, autoComplete.Group, autoComplete.SubCommand); - } - break; - + AddAutoCompleteCommand(plugin, applicationId, callback, autoComplete.Command, autoComplete.ArgumentName, autoComplete.Group, autoComplete.SubCommand); } + break; + + } - case DiscordApplicationCommandAttribute appCommand: + case DiscordApplicationCommandAttribute appCommand: + { + Action callback = hook.Method.CreateDelegate(plugin); + if (callback != null) { - Action callback = hook.Method.CreateDelegate(plugin); - if (callback != null) - { - AddApplicationCommand(plugin, applicationId, callback, appCommand.Command, appCommand.Group, appCommand.SubCommand); - } - - break; + AddApplicationCommand(plugin, applicationId, callback, appCommand.Command, appCommand.Group, appCommand.SubCommand); } + + break; + } - case DiscordMessageComponentCommandAttribute component: + case DiscordMessageComponentCommandAttribute component: + { + Action callback = hook.Method.CreateDelegate(plugin); + if (callback != null) { - Action callback = hook.Method.CreateDelegate(plugin); - if (callback != null) - { - AddMessageComponentCommand(plugin, applicationId, component.CustomId, callback); - } - - break; + AddMessageComponentCommand(plugin, applicationId, component.CustomId, callback); } + + break; + } - case DiscordModalSubmitAttribute modal: + case DiscordModalSubmitAttribute modal: + { + Action callback = hook.Method.CreateDelegate(plugin); + if (callback != null) { - Action callback = hook.Method.CreateDelegate(plugin); - if (callback != null) - { - AddModalSubmitCommand(plugin, applicationId, modal.CustomId, callback); - } - - break; + AddModalSubmitCommand(plugin, applicationId, modal.CustomId, callback); } + + break; } } } + } - /// - protected override void OnPluginLoaded(PluginSetup data, BotConnection connection) => RegisterApplicationCommands(data, connection); + /// + protected override void OnClientBotConnect(DiscordClient client) => RegisterApplicationCommands(client.Plugin, client.PluginSetup, client.Connection); - /// - protected override void OnPluginUnloaded(Plugin plugin) + /// + protected override void OnPluginUnloaded(Plugin plugin) + { + List commands = DiscordPool.Internal.GetList(); + foreach (KeyValuePair handler in _handlers) { - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); - try - { - List commands = DiscordPool.Internal.GetList(); - foreach (KeyValuePair handler in _handlers) - { - sb.AppendLine($"C - {handler.Key} = {handler.Value == null}"); - commands.AddRange(handler.Value.GetCommandsForPlugin(plugin)); - } - - for (int index = 0; index < commands.Count; index++) - { - BaseAppCommand command = commands[index]; - RemoveApplicationCommandInternal(command); - } + commands.AddRange(handler.Value.GetCommandsForPlugin(plugin)); + } - DiscordPool.Internal.FreeList(commands); - } - catch (Exception ex) - { - _logger.Exception($"An error occured during unload\n{sb}", ex); - } - finally - { - DiscordPool.Internal.FreeStringBuilder(sb); - } + for (int index = 0; index < commands.Count; index++) + { + BaseAppCommand command = commands[index]; + RemoveApplicationCommandInternal(command); } + + DiscordPool.Internal.FreeList(commands); + } - internal bool HandleInteraction(DiscordInteraction interaction) + internal bool HandleInteraction(DiscordInteraction interaction) + { + BaseAppCommand command = GetCommandHandler(interaction.ApplicationId)?.GetCommandById(interaction.GetCommandId()); + if (command == null) { - BaseAppCommand command = GetCommandHandler(interaction.ApplicationId)?.GetCommandById(interaction.GetCommandId()); - if (command == null) - { - return false; - } - - command.HandleCommand(interaction); - return true; + return false; } - /// - public void LogDebug(DebugLogger logger) + command.HandleCommand(interaction); + return true; + } + + /// + public void LogDebug(DebugLogger logger) + { + logger.StartArray("Application Commands"); + foreach (KeyValuePair handler in _handlers) { - logger.StartArray("Application Commands"); - foreach (KeyValuePair handler in _handlers) - { - logger.AppendField("Application ID", handler.Key); - logger.AppendList("Application Commands", handler.Value.GetCommands()); - } - logger.EndArray(); + logger.AppendField("Application ID", handler.Key); + logger.AppendList("Application Commands", handler.Value.GetCommands()); } + logger.EndArray(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary.cs b/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary.cs index 6091df435..0ac16c318 100644 --- a/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary.cs +++ b/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary.cs @@ -1,55 +1,80 @@ using System.Collections.Generic; using Oxide.Core.Libraries; using Oxide.Core.Plugins; -using Oxide.Ext.Discord.Connections; +using Oxide.Ext.Discord.Clients; +using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents the base class for Discord Libraries +/// +public abstract class BaseDiscordLibrary : Library { + private static readonly List Libraries = []; + private static readonly HashSet LoadedPlugins = []; + private static readonly HashSet BotConnectedPlugins = []; + /// - /// Represents the base class for Discord Libraries + /// Constructor /// - public abstract class BaseDiscordLibrary : Library + protected BaseDiscordLibrary() { - private static readonly List Libraries = new List(); - - /// - /// Constructor - /// - protected BaseDiscordLibrary() - { - Libraries.Add(this); - } + Libraries.Add(this); + } - internal static void ProcessPluginLoaded(PluginSetup plugin, BotConnection connection) + internal static void ProcessPluginLoaded(DiscordClient client) + { + if (LoadedPlugins.Add(client.PluginId)) { for (int index = 0; index < Libraries.Count; index++) { BaseDiscordLibrary library = Libraries[index]; - library.OnPluginLoaded(plugin, connection); + library.OnPluginLoaded(client); } } - - internal static void ProcessPluginUnloaded(Plugin plugin) + } + + internal static void ProcessBotConnection(DiscordClient client) + { + if (BotConnectedPlugins.Add(client.PluginId)) { for (int index = 0; index < Libraries.Count; index++) { BaseDiscordLibrary library = Libraries[index]; - library.OnPluginUnloaded(plugin); + library.OnClientBotConnect(client); } } - - /// - /// Called on the library when a plugin is loaded - /// - /// Plugin that was loaded - /// Connection for the plugin - protected virtual void OnPluginLoaded(PluginSetup data, BotConnection connection) {} + } - /// - /// Called on the library when a plugin is unloaded - /// - /// Plugin that was unloaded - protected virtual void OnPluginUnloaded(Plugin plugin) {} + internal static void ProcessPluginUnloaded(Plugin plugin) + { + for (int index = 0; index < Libraries.Count; index++) + { + BaseDiscordLibrary library = Libraries[index]; + library.OnPluginUnloaded(plugin); + } + PluginId pluginId = plugin.Id(); + LoadedPlugins.Remove(pluginId); + BotConnectedPlugins.Remove(pluginId); } + + /// + /// Called on the library when a plugin is loaded + /// + /// Client for the loaded plugin + protected virtual void OnPluginLoaded(DiscordClient client) {} + + /// + /// Called on the library when a plugin is loaded + /// + /// Client for the connecting bot + protected virtual void OnClientBotConnect(DiscordClient client) {} + + /// + /// Called on the library when a plugin is unloaded + /// + /// Plugin that was unloaded + protected virtual void OnPluginUnloaded(Plugin plugin) {} } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary{T}.cs b/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary{T}.cs index 133bf96ee..62daa55cf 100644 --- a/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary{T}.cs +++ b/Oxide.Ext.Discord/Libraries/BaseDiscordLibrary{T}.cs @@ -1,27 +1,26 @@ using System; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Base Discord Library for Oxide Libraries +/// +/// +public abstract class BaseDiscordLibrary : BaseDiscordLibrary where TLibrary : BaseDiscordLibrary { + internal static TLibrary Instance; + /// - /// Base Discord Library for Oxide Libraries + /// Constructor /// - /// - public abstract class BaseDiscordLibrary : BaseDiscordLibrary where TLibrary : BaseDiscordLibrary + /// Thrown if the Library has already been initialized + protected BaseDiscordLibrary() { - internal static TLibrary Instance; - - /// - /// Constructor - /// - /// Thrown if the Library has already been initialized - protected BaseDiscordLibrary() + if (Instance != null) { - if (Instance != null) - { - throw new Exception($"Duplicate Library Instances for type {typeof(TLibrary).FullName}"); - } - - Instance = (TLibrary)this; + throw new Exception($"Duplicate Library Instances for type {typeof(TLibrary).FullName}"); } + + Instance = (TLibrary)this; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Command/BaseCommand.cs b/Oxide.Ext.Discord/Libraries/Command/BaseCommand.cs index 2dc40fedc..01965cbec 100644 --- a/Oxide.Ext.Discord/Libraries/Command/BaseCommand.cs +++ b/Oxide.Ext.Discord/Libraries/Command/BaseCommand.cs @@ -6,46 +6,45 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L76) +/// +internal abstract class BaseCommand : IDebugLoggable { - /// - /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L76) - /// - internal abstract class BaseCommand : IDebugLoggable - { - internal readonly string Name; - private readonly string _hook; - internal Plugin Plugin; + internal readonly string Name; + private readonly string _hook; + internal Plugin Plugin; - protected BaseCommand(Plugin plugin, string name, string hook) - { - Name = name; - _hook = hook; - Plugin = plugin; - } + protected BaseCommand(Plugin plugin, string name, string hook) + { + Name = name; + _hook = hook; + Plugin = plugin; + } - public void HandleCommand(DiscordMessage message, string name, string[] args) - { - DiscordHook.CallPluginHook(Plugin, _hook, message, name, args); - } + public void HandleCommand(DiscordMessage message, string name, string[] args) + { + DiscordHook.CallPluginHook(Plugin, _hook, message, name, args); + } - /// - /// Returns if a command can run. - /// They can only run for the client that they were created for. - /// - /// Client to compare against - /// True if same bot client; false otherwise - public bool CanRun(BotClient client) - { - return client != null && DiscordClientFactory.Instance.GetClient(Plugin)?.Bot == client; - } + /// + /// Returns if a command can run. + /// They can only run for the client that they were created for. + /// + /// Client to compare against + /// True if same bot client; false otherwise + public bool CanRun(BotClient client) + { + return client != null && DiscordClientFactory.Instance.GetClient(Plugin)?.Bot == client; + } - public abstract bool CanHandle(DiscordMessage message, DiscordChannel channel); - public abstract void LogDebug(DebugLogger logger); + public abstract bool CanHandle(DiscordMessage message, DiscordChannel channel); + public abstract void LogDebug(DebugLogger logger); - internal void OnRemoved() - { - Plugin = null; - } + internal void OnRemoved() + { + Plugin = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Command/DirectMessageCommand.cs b/Oxide.Ext.Discord/Libraries/Command/DirectMessageCommand.cs index 8998ef8e4..abca37d6a 100644 --- a/Oxide.Ext.Discord/Libraries/Command/DirectMessageCommand.cs +++ b/Oxide.Ext.Discord/Libraries/Command/DirectMessageCommand.cs @@ -3,25 +3,21 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal class DirectMessageCommand : BaseCommand { - internal class DirectMessageCommand : BaseCommand - { - internal DirectMessageCommand(Plugin plugin, string name, string hook) : base(plugin, name, hook) - { - - } + internal DirectMessageCommand(Plugin plugin, string name, string hook) : base(plugin, name, hook) { } - public override bool CanHandle(DiscordMessage message, DiscordChannel channel) - { - return !message.GuildId.HasValue; - } + public override bool CanHandle(DiscordMessage message, DiscordChannel channel) + { + return !message.GuildId.HasValue; + } - public override void LogDebug(DebugLogger logger) - { - logger.AppendField("Name", Name); - logger.AppendField("Plugin", Plugin.FullName()); - logger.AppendField("Type", "DM Command"); - } + public override void LogDebug(DebugLogger logger) + { + logger.AppendField("Name", Name); + logger.AppendField("Plugin", Plugin.FullName()); + logger.AppendField("Type", "DM Command"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Command/DiscordCommand.cs b/Oxide.Ext.Discord/Libraries/Command/DiscordCommand.cs index 9cac32a1e..2d0061a22 100644 --- a/Oxide.Ext.Discord/Libraries/Command/DiscordCommand.cs +++ b/Oxide.Ext.Discord/Libraries/Command/DiscordCommand.cs @@ -5,7 +5,6 @@ using Oxide.Ext.Discord.Attributes; using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Clients; -using Oxide.Ext.Discord.Connections; using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Interfaces; @@ -13,398 +12,398 @@ using Oxide.Ext.Discord.Plugins; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a library for discord commands +/// +[Obsolete("DiscordCommand is deprecated and will be removed in a future update. Please upgrade to DiscordAppCommand")] +public class DiscordCommand : BaseDiscordLibrary, IDebugLoggable { /// - /// Represents a library for discord commands + /// Available command prefixes used by the extension /// - [Obsolete("DiscordCommand is deprecated and will be removed in a future update. Please upgrade to DiscordAppCommand")] - public class DiscordCommand : BaseDiscordLibrary, IDebugLoggable - { - /// - /// Available command prefixes used by the extension - /// - public readonly char[] CommandPrefixes; + public readonly char[] CommandPrefixes; - private readonly Hash _directMessageCommands = new Hash(); - private readonly Hash _guildCommands = new Hash(); - private readonly ILogger _logger; + private readonly Hash _directMessageCommands = new(); + private readonly Hash _guildCommands = new(); + private readonly ILogger _logger; - /// - /// Discord Commands Constructor - /// - /// Command prefixes used by the extension - /// Logger to use - internal DiscordCommand(char[] prefixes, ILogger logger) - { - CommandPrefixes = prefixes; - _logger = logger; - } + /// + /// Discord Commands Constructor + /// + /// Command prefixes used by the extension + /// Logger to use + internal DiscordCommand(char[] prefixes, ILogger logger) + { + CommandPrefixes = prefixes; + _logger = logger; + } - /// - /// Returns if there are any guild discord commands are registered - /// - /// - [LibraryFunction(nameof(HasCommands))] - public bool HasCommands() - { - return HasDirectMessageCommands() || HasGuildCommands(); - } + /// + /// Returns if there are any guild discord commands are registered + /// + /// + [LibraryFunction(nameof(HasCommands))] + public bool HasCommands() + { + return HasDirectMessageCommands() || HasGuildCommands(); + } - /// - /// Returns if there are any guild discord commands are registered - /// - /// - [LibraryFunction(nameof(HasDirectMessageCommands))] - public bool HasDirectMessageCommands() - { - return _directMessageCommands.Count != 0; - } + /// + /// Returns if there are any guild discord commands are registered + /// + /// + [LibraryFunction(nameof(HasDirectMessageCommands))] + public bool HasDirectMessageCommands() + { + return _directMessageCommands.Count != 0; + } - /// - /// Returns if there are any guild discord commands are registered - /// - /// - [LibraryFunction(nameof(HasGuildCommands))] - public bool HasGuildCommands() - { - return _guildCommands.Count != 0; - } + /// + /// Returns if there are any guild discord commands are registered + /// + /// + [LibraryFunction(nameof(HasGuildCommands))] + public bool HasGuildCommands() + { + return _guildCommands.Count != 0; + } - /// - /// Adds a localized discord direct message command - /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L123) - /// - /// Lang Key on the plugin that contains the command - /// Plugin to add the localized command for - /// Method name of the callback - [LibraryFunction(nameof(AddDirectMessageLocalizedCommand))] - public void AddDirectMessageLocalizedCommand(string langKey, Plugin plugin, string callback) - { - if (string.IsNullOrEmpty(langKey)) throw new ArgumentNullException(nameof(langKey)); - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (string.IsNullOrEmpty(callback)) throw new ArgumentNullException(nameof(callback)); + /// + /// Adds a localized discord direct message command + /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L123) + /// + /// Lang Key on the plugin that contains the command + /// Plugin to add the localized command for + /// Method name of the callback + [LibraryFunction(nameof(AddDirectMessageLocalizedCommand))] + public void AddDirectMessageLocalizedCommand(string langKey, Plugin plugin, string callback) + { + if (string.IsNullOrEmpty(langKey)) throw new ArgumentNullException(nameof(langKey)); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (string.IsNullOrEmpty(callback)) throw new ArgumentNullException(nameof(callback)); - foreach (string langType in OxideLibrary.Instance.Lang.GetLanguages(plugin)) + foreach (string langType in OxideLibrary.Instance.Lang.GetLanguages(plugin)) + { + Dictionary langKeys = OxideLibrary.Instance.Lang.GetMessages(langType, plugin); + if (langKeys.TryGetValue(langKey, out string command) && !string.IsNullOrEmpty(command)) { - Dictionary langKeys = OxideLibrary.Instance.Lang.GetMessages(langType, plugin); - if (langKeys.TryGetValue(langKey, out string command) && !string.IsNullOrEmpty(command)) - { - AddDirectMessageCommand(command, plugin, callback); - } + AddDirectMessageCommand(command, plugin, callback); } } + } - /// - /// Adds a discord direct message command - /// Sourced From Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L134) - /// - /// Command to add - /// Plugin to add the command for - /// Method name of the callback - public void AddDirectMessageCommand(string command, Plugin plugin, string callback) - { - if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (string.IsNullOrEmpty(callback)) throw new ArgumentNullException(nameof(callback)); + /// + /// Adds a discord direct message command + /// Sourced From Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L134) + /// + /// Command to add + /// Plugin to add the command for + /// Method name of the callback + public void AddDirectMessageCommand(string command, Plugin plugin, string callback) + { + if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (string.IsNullOrEmpty(callback)) throw new ArgumentNullException(nameof(callback)); - string commandName = command.ToLowerInvariant(); + string commandName = command.ToLowerInvariant(); - if (_directMessageCommands.TryGetValue(commandName, out DirectMessageCommand cmd)) - { - string previousPluginName = cmd.Plugin?.FullName() ?? "an unknown plugin"; - string newPluginName = plugin.FullName() ?? "An unknown plugin"; - _logger.Warning("{0} has replaced the '{1}' discord direct message command previously registered by {2}", newPluginName, commandName, previousPluginName); - } + if (_directMessageCommands.TryGetValue(commandName, out DirectMessageCommand cmd)) + { + string previousPluginName = cmd.Plugin?.FullName() ?? "an unknown plugin"; + string newPluginName = plugin.FullName() ?? "An unknown plugin"; + _logger.Warning("{0} has replaced the '{1}' discord direct message command previously registered by {2}", newPluginName, commandName, previousPluginName); + } - _logger.Debug("Adding Direct Command For: {0} Command: {1} Callback: {2}", plugin.FullName(), command, callback); + _logger.Debug("Adding Direct Command For: {0} Command: {1} Callback: {2}", plugin.FullName(), command, callback); - cmd = new DirectMessageCommand(plugin, commandName, callback); + cmd = new DirectMessageCommand(plugin, commandName, callback); - // Add the new command to collections - _directMessageCommands[commandName] = cmd; - } + // Add the new command to collections + _directMessageCommands[commandName] = cmd; + } - /// - /// Adds a localized discord guild command - /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L123) - /// - /// Lang Key on the plugin that contains the command - /// Plugin to add the localized command for - /// Channel or Category Id's this command is allowed in - /// Method name of the callback - [LibraryFunction(nameof(AddGuildLocalizedCommand))] - public void AddGuildLocalizedCommand(string langKey, Plugin plugin, List allowedChannels, string callback) - { - if (string.IsNullOrEmpty(langKey)) throw new ArgumentNullException(nameof(langKey)); - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (string.IsNullOrEmpty(callback)) throw new ArgumentNullException(nameof(callback)); + /// + /// Adds a localized discord guild command + /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L123) + /// + /// Lang Key on the plugin that contains the command + /// Plugin to add the localized command for + /// Channel or Category ID's this command is allowed in + /// Method name of the callback + [LibraryFunction(nameof(AddGuildLocalizedCommand))] + public void AddGuildLocalizedCommand(string langKey, Plugin plugin, List allowedChannels, string callback) + { + if (string.IsNullOrEmpty(langKey)) throw new ArgumentNullException(nameof(langKey)); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (string.IsNullOrEmpty(callback)) throw new ArgumentNullException(nameof(callback)); - foreach (string langType in OxideLibrary.Instance.Lang.GetLanguages(plugin)) + foreach (string langType in OxideLibrary.Instance.Lang.GetLanguages(plugin)) + { + Dictionary langKeys = OxideLibrary.Instance.Lang.GetMessages(langType, plugin); + if (langKeys.TryGetValue(langKey, out string command) && !string.IsNullOrEmpty(command)) { - Dictionary langKeys = OxideLibrary.Instance.Lang.GetMessages(langType, plugin); - if (langKeys.TryGetValue(langKey, out string command) && !string.IsNullOrEmpty(command)) - { - AddGuildCommand(command, plugin, allowedChannels, callback); - } + AddGuildCommand(command, plugin, allowedChannels, callback); } } + } - /// - /// Adds a discord guild command - /// Sourced From Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L134) - /// - /// Name of the command - /// Plugin to add the localized command for - /// Channel or Category Id's this command is allowed in - /// Method name of the callback - public void AddGuildCommand(string command, Plugin plugin, List allowedChannels, string callback) - { - if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (string.IsNullOrEmpty(callback)) throw new ArgumentNullException(nameof(callback)); + /// + /// Adds a discord guild command + /// Sourced From Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L134) + /// + /// Name of the command + /// Plugin to add the localized command for + /// Channel or Category ID's this command is allowed in + /// Method name of the callback + public void AddGuildCommand(string command, Plugin plugin, List allowedChannels, string callback) + { + if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (string.IsNullOrEmpty(callback)) throw new ArgumentNullException(nameof(callback)); - string commandName = command.ToLowerInvariant(); + string commandName = command.ToLowerInvariant(); - if (_guildCommands.TryGetValue(commandName, out GuildCommand cmd)) - { - string previousPluginName = cmd.Plugin?.FullName() ?? "an unknown plugin"; - string newPluginName = plugin.FullName(); - _logger.Warning("{0} has replaced the '{1}' discord guild command previously registered by {2}", newPluginName, commandName, previousPluginName); - } + if (_guildCommands.TryGetValue(commandName, out GuildCommand cmd)) + { + string previousPluginName = cmd.Plugin?.FullName() ?? "an unknown plugin"; + string newPluginName = plugin.FullName(); + _logger.Warning("{0} has replaced the '{1}' discord guild command previously registered by {2}", newPluginName, commandName, previousPluginName); + } - _logger.Debug("Adding Guild Command For: {0} Command: {1} Callback: {2}", plugin.FullName(), command, callback); + _logger.Debug("Adding Guild Command For: {0} Command: {1} Callback: {2}", plugin.FullName(), command, callback); - cmd = new GuildCommand(plugin, commandName, callback, allowedChannels); + cmd = new GuildCommand(plugin, commandName, callback, allowedChannels); - // Add the new command to collections - _guildCommands[commandName] = cmd; - } + // Add the new command to collections + _guildCommands[commandName] = cmd; + } - /// - /// Removes a previously registered discord command - /// Sourced From Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L286) - /// - /// Command to remove - /// Plugin the command is for - [LibraryFunction(nameof(RemoveDiscordCommand))] - public void RemoveDiscordCommand(string command, Plugin plugin) + /// + /// Removes a previously registered discord command + /// Sourced From Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L286) + /// + /// Command to remove + /// Plugin the command is for + [LibraryFunction(nameof(RemoveDiscordCommand))] + public void RemoveDiscordCommand(string command, Plugin plugin) + { + DirectMessageCommand dmCommand = _directMessageCommands[command]; + if (dmCommand != null && (dmCommand.Plugin == null || !dmCommand.Plugin.IsLoaded || dmCommand.Plugin == plugin)) { - DirectMessageCommand dmCommand = _directMessageCommands[command]; - if (dmCommand != null && (dmCommand.Plugin == null || !dmCommand.Plugin.IsLoaded || dmCommand.Plugin == plugin)) - { - RemoveDmCommand(dmCommand); - } + RemoveDmCommand(dmCommand); + } - GuildCommand guildCommand = _guildCommands[command]; - if (guildCommand != null && (guildCommand.Plugin == null || !guildCommand.Plugin.IsLoaded || guildCommand.Plugin == plugin)) - { - RemoveGuildCommand(guildCommand); - } + GuildCommand guildCommand = _guildCommands[command]; + if (guildCommand != null && (guildCommand.Plugin == null || !guildCommand.Plugin.IsLoaded || guildCommand.Plugin == plugin)) + { + RemoveGuildCommand(guildCommand); } + } + + /// + /// Removes a discord command + /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L314) + /// + /// + private void RemoveDmCommand(DirectMessageCommand command) + { + DirectMessageCommand dmCommand = _directMessageCommands[command.Name]; + dmCommand.OnRemoved(); + _directMessageCommands.Remove(command.Name); + } + + private void RemoveGuildCommand(GuildCommand command) + { + GuildCommand guildCommand = _guildCommands[command.Name]; + guildCommand.OnRemoved(); + _guildCommands.Remove(command.Name); + } - /// - /// Removes a discord command - /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L314) - /// - /// - private void RemoveDmCommand(DirectMessageCommand command) + /// + /// Handles the specified direct message command + /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L361) + /// + /// + /// + /// + /// + /// + internal bool HandleDirectMessageCommand(BotClient client, DiscordMessage message, DiscordChannel channel, string name, string[] args) + { + DirectMessageCommand command = _directMessageCommands[name]; + if (command == null || !command.CanRun(client) || !command.CanHandle(message, channel)) { - DirectMessageCommand dmCommand = _directMessageCommands[command.Name]; - dmCommand.OnRemoved(); - _directMessageCommands.Remove(command.Name); + return false; } - - private void RemoveGuildCommand(GuildCommand command) + + if (!command.Plugin.IsLoaded) { - GuildCommand guildCommand = _guildCommands[command.Name]; - guildCommand.OnRemoved(); - _guildCommands.Remove(command.Name); + _directMessageCommands.Remove(name); + return false; } - /// - /// Handles the specified direct message command - /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L361) - /// - /// - /// - /// - /// - /// - internal bool HandleDirectMessageCommand(BotClient client, DiscordMessage message, DiscordChannel channel, string name, string[] args) + if (!client.IsPluginRegistered(command.Plugin)) { - DirectMessageCommand command = _directMessageCommands[name]; - if (command == null || !command.CanRun(client) || !command.CanHandle(message, channel)) - { - return false; - } - - if (!command.Plugin.IsLoaded) - { - _directMessageCommands.Remove(name); - return false; - } - - if (!client.IsPluginRegistered(command.Plugin)) - { - return false; - } - - command.HandleCommand(message, name, args); - return true; + return false; } - /// - /// Handles the specified direct message command - /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L361) - /// - /// - /// - /// - /// - /// - internal bool HandleGuildCommand(BotClient client, DiscordMessage message, DiscordChannel channel, string name, string[] args) + command.HandleCommand(message, name, args); + return true; + } + + /// + /// Handles the specified direct message command + /// Sourced from Command.cs of OxideMod (https://github.com/OxideMod/Oxide.Rust/blob/develop/src/Libraries/Command.cs#L361) + /// + /// + /// + /// + /// + /// + internal bool HandleGuildCommand(BotClient client, DiscordMessage message, DiscordChannel channel, string name, string[] args) + { + GuildCommand command = _guildCommands[name]; + _logger.Debug("Processing Command: {0}", name); + if (command == null) { - GuildCommand command = _guildCommands[name]; - _logger.Debug("Processing Command: {0}", name); - if (command == null) - { - _logger.Debug("Can't handle: command is null"); - return false; - } + _logger.Debug("Can't handle: command is null"); + return false; + } - if (!command.Plugin.IsLoaded) - { - _logger.Debug("Can't handle command plugin not loaded"); - _guildCommands.Remove(name); - return false; - } + if (!command.Plugin.IsLoaded) + { + _logger.Debug("Can't handle command plugin not loaded"); + _guildCommands.Remove(name); + return false; + } - if (!command.CanRun(client)) - { - _logger.Debug("Can't handle: command can't run for client"); - return false; - } + if (!command.CanRun(client)) + { + _logger.Debug("Can't handle: command can't run for client"); + return false; + } - if (!command.CanHandle(message, channel)) - { - _logger.Debug("Can't handle: command can't handle message / channel"); - return false; - } + if (!command.CanHandle(message, channel)) + { + _logger.Debug("Can't handle: command can't handle message / channel"); + return false; + } - if (!client.IsPluginRegistered(command.Plugin)) - { - _logger.Debug("Can't handle command plugin not registered"); - return false; - } - - command.HandleCommand(message, name, args); - _logger.Debug("Handling command"); - return true; + if (!client.IsPluginRegistered(command.Plugin)) + { + _logger.Debug("Can't handle command plugin not registered"); + return false; } - internal IEnumerable GetCommands() + command.HandleCommand(message, name, args); + _logger.Debug("Handling command"); + return true; + } + + internal IEnumerable GetCommands() + { + foreach (GuildCommand command in _guildCommands.Values) { - foreach (GuildCommand command in _guildCommands.Values) - { - yield return command; - } + yield return command; + } - foreach (DirectMessageCommand command in _directMessageCommands.Values) - { - yield return command; - } + foreach (DirectMessageCommand command in _directMessageCommands.Values) + { + yield return command; } + } - /// - protected override void OnPluginLoaded(PluginSetup data, BotConnection connection) + /// + protected override void OnClientBotConnect(DiscordClient client) + { + Plugin plugin = client.Plugin; + foreach (PluginHookResult result in client.PluginSetup.GetCallbacksWithAttribute()) { - foreach (PluginHookResult result in data.GetCallbacksWithAttribute()) + if (!result.IsValid) { - if (!result.IsValid) - { - continue; - } + continue; + } - DirectMessageCommandAttribute command = result.Attribute; - if (command.IsLocalized) - { - AddDirectMessageLocalizedCommand(command.Name, data.Plugin, result.Name); - _logger.Debug("Adding Localized Direct Message Command {0} Method: {1}", command.Name, result.Name); - } - else - { - AddDirectMessageCommand(command.Name, data.Plugin, result.Name); - _logger.Debug("Adding Direct Message Command {0} Method: {1}", command.Name, result.Name); - } + DirectMessageCommandAttribute command = result.Attribute; + if (command.IsLocalized) + { + AddDirectMessageLocalizedCommand(command.Name, plugin, result.Name); + _logger.Debug("Adding Localized Direct Message Command {0} Method: {1}", command.Name, result.Name); } - - foreach (PluginHookResult result in data.GetCallbacksWithAttribute()) + else { - if (!result.IsValid) - { - continue; - } - - GuildCommandAttribute command = result.Attribute; - if (command.IsLocalized) - { - AddGuildLocalizedCommand(command.Name, data.Plugin, null, result.Name); - _logger.Debug("Adding Localized Direct Message Command {0} Method: {1}", command.Name, result.Name); - } - else - { - AddGuildCommand(command.Name, data.Plugin, null, result.Name); - _logger.Debug("Adding Direct Message Command {0} Method: {1}", command.Name, result.Name); - } + AddDirectMessageCommand(command.Name, plugin, result.Name); + _logger.Debug("Adding Direct Message Command {0} Method: {1}", command.Name, result.Name); } } - - /// - /// Called when a plugin has been unloaded - /// - /// - protected override void OnPluginUnloaded(Plugin sender) + + foreach (PluginHookResult result in client.PluginSetup.GetCallbacksWithAttribute()) { - List dmCommands = DiscordPool.Internal.GetList(); - List guildCommands = DiscordPool.Internal.GetList(); - // Remove all discord commands which were registered by the plugin - foreach (DirectMessageCommand cmd in _directMessageCommands.Values) + if (!result.IsValid) { - if (cmd.Plugin.Id() == sender.Id()) - { - dmCommands.Add(cmd); - } + continue; } - - foreach (GuildCommand cmd in _guildCommands.Values) + + GuildCommandAttribute command = result.Attribute; + if (command.IsLocalized) { - if (cmd.Plugin.Id() == sender.Id()) - { - guildCommands.Add(cmd); - } + AddGuildLocalizedCommand(command.Name, plugin, null, result.Name); + _logger.Debug("Adding Localized Direct Message Command {0} Method: {1}", command.Name, result.Name); } + else + { + AddGuildCommand(command.Name, plugin, null, result.Name); + _logger.Debug("Adding Direct Message Command {0} Method: {1}", command.Name, result.Name); + } + } + } - for (int index = 0; index < dmCommands.Count; index++) + /// + /// Called when a plugin has been unloaded + /// + /// + protected override void OnPluginUnloaded(Plugin sender) + { + List dmCommands = DiscordPool.Internal.GetList(); + List guildCommands = DiscordPool.Internal.GetList(); + // Remove all discord commands that were registered by the plugin + foreach (DirectMessageCommand cmd in _directMessageCommands.Values) + { + if (cmd.Plugin.Id() == sender.Id()) { - DirectMessageCommand cmd = dmCommands[index]; - RemoveDmCommand(cmd); + dmCommands.Add(cmd); } + } - for (int index = 0; index < guildCommands.Count; index++) + foreach (GuildCommand cmd in _guildCommands.Values) + { + if (cmd.Plugin.Id() == sender.Id()) { - GuildCommand cmd = guildCommands[index]; - RemoveGuildCommand(cmd); + guildCommands.Add(cmd); } - - DiscordPool.Internal.FreeList(dmCommands); - DiscordPool.Internal.FreeList(guildCommands); } - /// - public void LogDebug(DebugLogger logger) + for (int index = 0; index < dmCommands.Count; index++) + { + DirectMessageCommand cmd = dmCommands[index]; + RemoveDmCommand(cmd); + } + + for (int index = 0; index < guildCommands.Count; index++) { - logger.AppendList("Commands", GetCommands()); + GuildCommand cmd = guildCommands[index]; + RemoveGuildCommand(cmd); } + + DiscordPool.Internal.FreeList(dmCommands); + DiscordPool.Internal.FreeList(guildCommands); + } + + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendList("Commands", GetCommands()); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Command/GuildCommand.cs b/Oxide.Ext.Discord/Libraries/Command/GuildCommand.cs index dda9a2853..fb51c0644 100644 --- a/Oxide.Ext.Discord/Libraries/Command/GuildCommand.cs +++ b/Oxide.Ext.Discord/Libraries/Command/GuildCommand.cs @@ -4,47 +4,46 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal class GuildCommand : BaseCommand { - internal class GuildCommand : BaseCommand + private readonly List _allowedChannels; + + public GuildCommand(Plugin plugin, string name, string hook, List allowedChannels) : base(plugin, name, hook) { - private readonly List _allowedChannels; + _allowedChannels = allowedChannels; + } - public GuildCommand(Plugin plugin, string name, string hook, List allowedChannels) : base(plugin, name, hook) + public override bool CanHandle(DiscordMessage message, DiscordChannel channel) + { + if (!message.GuildId.HasValue) { - _allowedChannels = allowedChannels; + return false; } - - public override bool CanHandle(DiscordMessage message, DiscordChannel channel) - { - if (!message.GuildId.HasValue) - { - return false; - } - if (channel == null) - { - return true; - } - - if (_allowedChannels == null || _allowedChannels.Count == 0 || _allowedChannels.Contains(channel.Id)) - { - return true; - } + if (channel == null) + { + return true; + } - if (channel.ParentId.HasValue && _allowedChannels.Contains(channel.ParentId.Value)) - { - return true; - } - - return false; + if (_allowedChannels == null || _allowedChannels.Count == 0 || _allowedChannels.Contains(channel.Id)) + { + return true; } - public override void LogDebug(DebugLogger logger) + if (channel.ParentId.HasValue && _allowedChannels.Contains(channel.ParentId.Value)) { - logger.AppendField("Name", Name); - logger.AppendField("Plugin", Plugin.FullName()); - logger.AppendField("Type", "Guild Command"); + return true; } + + return false; + } + + public override void LogDebug(DebugLogger logger) + { + logger.AppendField("Name", Name); + logger.AppendField("Plugin", Plugin.FullName()); + logger.AppendField("Type", "Guild Command"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Linking/DiscordLink.cs b/Oxide.Ext.Discord/Libraries/Linking/DiscordLink.cs index d6c6053ef..578589a7d 100644 --- a/Oxide.Ext.Discord/Libraries/Linking/DiscordLink.cs +++ b/Oxide.Ext.Discord/Libraries/Linking/DiscordLink.cs @@ -12,344 +12,343 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a library for discord linking +/// +public class DiscordLink : BaseDiscordLibrary, IDebugLoggable { /// - /// Represents a library for discord linking + /// Readonly Dictionary of Player ID's to Discord ID's /// - public class DiscordLink : BaseDiscordLibrary, IDebugLoggable - { - /// - /// Readonly Dictionary of Player ID's to Discord ID's - /// - public readonly IReadOnlyDictionary PlayerToDiscordIds; + public readonly IReadOnlyDictionary PlayerToDiscordIds; - /// - /// Readonly Dictionary of Discord ID's to Player ID's - /// - public readonly IReadOnlyDictionary DiscordToPlayerIds; + /// + /// Readonly Dictionary of Discord ID's to Player ID's + /// + public readonly IReadOnlyDictionary DiscordToPlayerIds; - /// - /// Readonly Collection of all Player ID's - /// - public readonly ICollection PlayerIds; + /// + /// Readonly Collection of all Player ID's + /// + public readonly ICollection PlayerIds; - /// - /// Readonly Collection of all Discord ID's - /// - public readonly ICollection DiscordIds; + /// + /// Readonly Collection of all Discord ID's + /// + public readonly ICollection DiscordIds; - /// - /// Returns if there is a registered link plugin - /// - /// - public bool IsEnabled => _linkPlugins.Count != 0; + /// + /// Returns if there is a registered link plugin + /// + /// + public bool IsEnabled => _linkPlugins.Count != 0; - /// - /// Returns the number of linked players - /// - /// - public int LinkedCount => _links.Count; + /// + /// Returns the number of linked players + /// + /// + public int LinkedCount => _links.Count; - private readonly BidirectionalDictionary _links = new BidirectionalDictionary(); - private readonly Hash> _linkPlugins = new Hash>(); + private readonly BidirectionalDictionary _links = new(); + private readonly Hash> _linkPlugins = new(); - private readonly ILogger _logger; + private readonly ILogger _logger; - /// - /// DiscordLink Constructor - /// - /// Logger for Discord Link - internal DiscordLink(ILogger logger) - { - _logger = logger; - PlayerToDiscordIds = _links.AsReadOnlyKeyToValue(); - DiscordToPlayerIds = _links.AsReadOnlyValueToKey(); - PlayerIds = _links.AsKeyCollection(); - DiscordIds = _links.AsValueCollection(); - } + /// + /// DiscordLink Constructor + /// + /// Logger for Discord Link + internal DiscordLink(ILogger logger) + { + _logger = logger; + PlayerToDiscordIds = _links.AsReadOnlyKeyToValue(); + DiscordToPlayerIds = _links.AsReadOnlyValueToKey(); + PlayerIds = _links.AsKeyCollection(); + DiscordIds = _links.AsValueCollection(); + } - /// - /// Adds a link plugin to be the plugin used with the Discord Link library - /// - /// - public void AddLinkPlugin(IDiscordLink link) - { - if (link == null) throw new ArgumentNullException(nameof(link)); + /// + /// Adds a link plugin to be the plugin used with the Discord Link library + /// + /// + public void AddLinkPlugin(IDiscordLink link) + { + if (link == null) throw new ArgumentNullException(nameof(link)); - IDictionary data = link.GetPlayerIdToDiscordIds(); - if (data == null) - { - _logger.Error($"{{0}} returned null when {nameof(link.GetPlayerIdToDiscordIds)} was called", link.Name); - return; - } + IDictionary data = link.GetPlayerIdToDiscordIds(); + if (data == null) + { + _logger.Error($"{{0}} returned null when {nameof(link.GetPlayerIdToDiscordIds)} was called", link.Name); + return; + } - _linkPlugins[link.Id()] = data; + _linkPlugins[link.Id()] = data; - foreach (KeyValuePair pair in data) - { - AddLink(pair.Key, pair.Value); - } - - _logger.Debug("{0} has been registered as a DiscordLink plugin", link.Name); + foreach (KeyValuePair pair in data) + { + AddLink(pair.Key, pair.Value); } + + _logger.Debug("{0} has been registered as a DiscordLink plugin", link.Name); + } - /// - /// Removes a link plugin from the Discord Link library - /// - /// - public void RemoveLinkPlugin(IDiscordLink plugin) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + /// + /// Removes a link plugin from the Discord Link library + /// + /// + public void RemoveLinkPlugin(IDiscordLink plugin) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - PluginId pluginId = plugin.Id(); - IDictionary pluginData = _linkPlugins[pluginId]; - if (pluginData == null) - { - return; - } + PluginId pluginId = plugin.Id(); + IDictionary pluginData = _linkPlugins[pluginId]; + if (pluginData == null) + { + return; + } - _linkPlugins.Remove(pluginId); - foreach (KeyValuePair link in pluginData) + _linkPlugins.Remove(pluginId); + foreach (KeyValuePair link in pluginData) + { + bool keepLink = false; + foreach (IDictionary links in _linkPlugins.Values) { - bool keepLink = false; - foreach (IDictionary links in _linkPlugins.Values) + if (links.ContainsKey(link.Key)) { - if (links.ContainsKey(link.Key)) - { - keepLink = true; - break; - } + keepLink = true; + break; } + } - if (!keepLink) - { - RemoveLink(link.Key, link.Value); - } + if (!keepLink) + { + RemoveLink(link.Key, link.Value); } } + } - /// - protected override void OnPluginUnloaded(Plugin plugin) + /// + protected override void OnPluginUnloaded(Plugin plugin) + { + // ReSharper disable once SuspiciousTypeConversion.Global + if (plugin is IDiscordLink link) { - // ReSharper disable once SuspiciousTypeConversion.Global - if (plugin is IDiscordLink link) - { - RemoveLinkPlugin(link); - } + RemoveLinkPlugin(link); } + } - /// - /// Returns if the specified ID is linked - /// - /// Player ID of the player - /// True if the ID is linked; false otherwise - public bool IsLinked(string playerId) => IsLinked(new PlayerId(playerId)); + /// + /// Returns if the specified ID is linked + /// + /// Player ID of the player + /// True if the ID is linked; false otherwise + public bool IsLinked(string playerId) => IsLinked(new PlayerId(playerId)); - /// - /// Returns if the specified ID is linked - /// - /// Player ID of the player - /// True if the ID is linked; false otherwise - public bool IsLinked(PlayerId playerId) => _links.ContainsKey(playerId); + /// + /// Returns if the specified ID is linked + /// + /// Player ID of the player + /// True if the ID is linked; false otherwise + public bool IsLinked(PlayerId playerId) => _links.ContainsKey(playerId); - /// - /// Returns if the specified ID is linked - /// - /// Discord ID of the player - /// True if the ID is linked; false otherwise - public bool IsLinked(Snowflake discordId) => _links.ContainsKey(discordId); + /// + /// Returns if the specified ID is linked + /// + /// Discord ID of the player + /// True if the ID is linked; false otherwise + public bool IsLinked(Snowflake discordId) => _links.ContainsKey(discordId); - /// - /// Returns if the specified ID is linked - /// - /// Player to check if linked - /// True if the player is linked; false otherwise - public bool IsLinked(IPlayer player) => IsLinked(player.Id); + /// + /// Returns if the specified ID is linked + /// + /// Player to check if linked + /// True if the player is linked; false otherwise + public bool IsLinked(IPlayer player) => IsLinked(player.Id); - /// - /// Returns if the specified ID is linked - /// - /// Discord user to check - /// True if the user is linked; false otherwise - public bool IsLinked(DiscordUser user) => IsLinked(user.Id); + /// + /// Returns if the specified ID is linked + /// + /// Discord user to check + /// True if the user is linked; false otherwise + public bool IsLinked(DiscordUser user) => IsLinked(user.Id); - /// - /// Returns the Player ID of the given Discord ID if there is a link - /// - /// Discord ID to get player ID for - /// Player ID of the given given discord ID if linked; null otherwise - public PlayerId GetPlayerId(Snowflake discordId) => _links.TryGetValue(discordId, out PlayerId playerId) ? playerId : default(PlayerId); + /// + /// Returns the Player ID of the given Discord ID if there is a link + /// + /// Discord ID to get player ID for + /// Player ID of the given discord ID if linked; null otherwise + public PlayerId GetPlayerId(Snowflake discordId) => _links.TryGetValue(discordId, out PlayerId playerId) ? playerId : default; - /// - /// Returns the Player ID of the given Discord ID if there is a link - /// - /// to get player Id for - /// Player ID of the given given discord ID if linked; null otherwise - public PlayerId GetPlayerId(DiscordUser user) => GetPlayerId(user.Id); + /// + /// Returns the Player ID of the given Discord ID if there is a link + /// + /// to get player ID for + /// Player ID of the given discord ID if linked; null otherwise + public PlayerId GetPlayerId(DiscordUser user) => GetPlayerId(user.Id); - /// - /// Returns the IPlayer for the given Discord ID - /// - /// Discord ID to get IPlayer for - /// IPlayer for the given Discord ID; null otherwise - public IPlayer GetPlayer(Snowflake discordId) => _links.TryGetValue(discordId, out PlayerId playerId) ? ServerPlayerCache.Instance.GetPlayerById(playerId.Id) : null; + /// + /// Returns the IPlayer for the given Discord ID + /// + /// Discord ID to get IPlayer for + /// IPlayer for the given Discord ID; null otherwise + public IPlayer GetPlayer(Snowflake discordId) => _links.TryGetValue(discordId, out PlayerId playerId) ? ServerPlayerCache.Instance.GetPlayerById(playerId.Id) : null; - /// - /// Returns the Discord ID for the given Player ID - /// - /// Player ID to get Discord ID for - /// Discord ID for the given Player ID; null otherwise - public Snowflake GetDiscordId(string playerId) => GetDiscordId(new PlayerId(playerId)); + /// + /// Returns the Discord ID for the given Player ID + /// + /// Player ID to get Discord ID for + /// Discord ID for the given Player ID; null otherwise + public Snowflake GetDiscordId(string playerId) => GetDiscordId(new PlayerId(playerId)); - /// - /// Returns the Discord ID for the given Player ID - /// - /// Player ID to get Discord ID for - /// Discord ID for the given Player ID; null otherwise - public Snowflake GetDiscordId(PlayerId playerId) => _links.TryGetValue(playerId, out Snowflake id) ? id : default(Snowflake); + /// + /// Returns the Discord ID for the given Player ID + /// + /// Player ID to get Discord ID for + /// Discord ID for the given Player ID; null otherwise + public Snowflake GetDiscordId(PlayerId playerId) => _links.TryGetValue(playerId, out Snowflake id) ? id : default; - /// - /// Returns the Discord ID for the given IPlayer - /// - /// Player to get Discord ID for - /// Discord ID for the given Player ID; null otherwise - public Snowflake GetDiscordId(IPlayer player) => GetDiscordId(player.Id); + /// + /// Returns the Discord ID for the given IPlayer + /// + /// Player to get Discord ID for + /// Discord ID for the given Player ID; null otherwise + public Snowflake GetDiscordId(IPlayer player) => GetDiscordId(player.Id); - /// - /// Returns a minimal Discord User - /// - /// ID of the in game player - /// Discord ID for the given Player ID; null otherwise - public DiscordUser GetDiscordUser(string playerId) => GetDiscordUser(new PlayerId(playerId)); + /// + /// Returns a minimal Discord User + /// + /// ID of the in game player + /// Discord ID for the given Player ID; null otherwise + public DiscordUser GetDiscordUser(string playerId) => GetDiscordUser(new PlayerId(playerId)); - /// - /// Returns a minimal Discord User - /// - /// ID of the in game player - /// Discord ID for the given Player ID; null otherwise - public DiscordUser GetDiscordUser(PlayerId playerId) => _links.TryGetValue(playerId, out Snowflake discordId) && discordId.IsValid() ? EntityCache.Instance.GetOrCreate(discordId) : null; + /// + /// Returns a minimal Discord User + /// + /// ID of the in game player + /// Discord ID for the given Player ID; null otherwise + public DiscordUser GetDiscordUser(PlayerId playerId) => _links.TryGetValue(playerId, out Snowflake discordId) && discordId.IsValid() ? EntityCache.Instance.GetOrCreate(discordId) : null; - /// - /// Returns a minimal Discord User - /// - /// Player to get the Discord User for - /// Discord ID for the given IPlayer; null otherwise - public DiscordUser GetDiscordUser(IPlayer player) => GetDiscordUser(player.Id); + /// + /// Returns a minimal Discord User + /// + /// Player to get the Discord User for + /// Discord ID for the given IPlayer; null otherwise + public DiscordUser GetDiscordUser(IPlayer player) => GetDiscordUser(player.Id); - /// - /// Returns a linked guild member for the matching player id in the given guild - /// - /// ID of the in game player - /// Guild the member is in - /// Discord ID for the given Player ID; null otherwise - public GuildMember GetLinkedMember(string playerId, DiscordGuild guild) => GetLinkedMember(new PlayerId(playerId), guild); + /// + /// Returns a linked guild member for the matching player id in the given guild + /// + /// ID of the in game player + /// Guild the member is in + /// Discord ID for the given Player ID; null otherwise + public GuildMember GetLinkedMember(string playerId, DiscordGuild guild) => GetLinkedMember(new PlayerId(playerId), guild); - /// - /// Returns a linked guild member for the matching player id in the given guild - /// - /// ID of the in game player - /// Guild the member is in - /// Discord ID for the given Player ID; null otherwise - public GuildMember GetLinkedMember(PlayerId playerId, DiscordGuild guild) + /// + /// Returns a linked guild member for the matching player id in the given guild + /// + /// ID of the in game player + /// Guild the member is in + /// Discord ID for the given Player ID; null otherwise + public GuildMember GetLinkedMember(PlayerId playerId, DiscordGuild guild) + { + if (guild == null) throw new ArgumentNullException(nameof(guild)); + Snowflake discordId = GetDiscordId(playerId); + if (!discordId.IsValid() || !guild.IsAvailable) { - if (guild == null) throw new ArgumentNullException(nameof(guild)); - Snowflake discordId = GetDiscordId(playerId); - if (!discordId.IsValid() || !guild.IsAvailable) - { - return null; - } - - return guild.Members[discordId]; + return null; } - /// - /// Returns a linked guild member for the matching in the given guild - /// - /// Player to get the Discord User for - /// Guild the member is in - /// Discord ID for the given Player ID; null otherwise - public GuildMember GetLinkedMember(IPlayer player, DiscordGuild guild) => GetLinkedMember(player.Id, guild); + return guild.Members[discordId]; + } + + /// + /// Returns a linked guild member for the matching in the given guild + /// + /// Player to get the Discord User for + /// Guild the member is in + /// Discord ID for the given Player ID; null otherwise + public GuildMember GetLinkedMember(IPlayer player, DiscordGuild guild) => GetLinkedMember(player.Id, guild); - /// - /// Called by a link plugin when a link occured - /// - /// Plugin that initiated the link - /// Player being linked - /// DiscordUser being linked - public void OnLinked(Plugin plugin, IPlayer player, DiscordUser discord) - { - if (player == null) throw new ArgumentNullException(nameof(player)); - if (discord == null) throw new ArgumentNullException(nameof(discord)); + /// + /// Called by a link plugin when a link occured + /// + /// Plugin that initiated the link + /// Player being linked + /// DiscordUser being linked + public void OnLinked(Plugin plugin, IPlayer player, DiscordUser discord) + { + if (player == null) throw new ArgumentNullException(nameof(player)); + if (discord == null) throw new ArgumentNullException(nameof(discord)); - if (!IsValidLinkPlugin(plugin)) - { - return; - } + if (!IsValidLinkPlugin(plugin)) + { + return; + } - _linkPlugins[plugin.Id()][player.PlayerId()] = discord.Id; - AddLink(new PlayerId(player.Id), discord.Id); + _linkPlugins[plugin.Id()][player.PlayerId()] = discord.Id; + AddLink(new PlayerId(player.Id), discord.Id); - DiscordHook.CallGlobalHook(DiscordExtHooks.OnDiscordPlayerLinked, player, discord); - } + DiscordHook.CallGlobalHook(DiscordExtHooks.OnDiscordPlayerLinked, player, discord); + } - /// - /// Called by a link plugin when an unlink occured - /// - /// Plugin that is unlinking - /// Player being unlinked - /// DiscordUser being unlinked - public void OnUnlinked(Plugin plugin, IPlayer player, DiscordUser discord) - { - if (player == null) throw new ArgumentNullException(nameof(player)); - if (discord == null) throw new ArgumentNullException(nameof(discord)); - - if (!IsValidLinkPlugin(plugin)) - { - return; - } + /// + /// Called by a link plugin when an unlink has occured + /// + /// Plugin that is unlinking + /// Player being unlinked + /// DiscordUser being unlinked + public void OnUnlinked(Plugin plugin, IPlayer player, DiscordUser discord) + { + if (player == null) throw new ArgumentNullException(nameof(player)); + if (discord == null) throw new ArgumentNullException(nameof(discord)); - DiscordHook.CallGlobalHook(DiscordExtHooks.OnDiscordPlayerUnlink, player, discord); - RemoveLink(new PlayerId(player.Id), discord.Id); - _linkPlugins[plugin.Id()].Remove(player.PlayerId()); - DiscordHook.CallGlobalHook(DiscordExtHooks.OnDiscordPlayerUnlinked, player, discord); - } - - private void AddLink(PlayerId playerId, Snowflake discordId) + if (!IsValidLinkPlugin(plugin)) { - _links[playerId] = discordId; + return; } + + DiscordHook.CallGlobalHook(DiscordExtHooks.OnDiscordPlayerUnlink, player, discord); + RemoveLink(new PlayerId(player.Id), discord.Id); + _linkPlugins[plugin.Id()].Remove(player.PlayerId()); + DiscordHook.CallGlobalHook(DiscordExtHooks.OnDiscordPlayerUnlinked, player, discord); + } - private void RemoveLink(PlayerId playerId, Snowflake discordId) - { - _links.Remove(playerId); - _links.Remove(discordId); - } + private void AddLink(PlayerId playerId, Snowflake discordId) + { + _links[playerId] = discordId; + } + + private void RemoveLink(PlayerId playerId, Snowflake discordId) + { + _links.Remove(playerId); + _links.Remove(discordId); + } - private bool IsValidLinkPlugin(Plugin plugin) + private bool IsValidLinkPlugin(Plugin plugin) + { + // ReSharper disable once SuspiciousTypeConversion.Global + if (plugin is not IDiscordLink link) { - // ReSharper disable once SuspiciousTypeConversion.Global - if (!(plugin is IDiscordLink link)) - { - _logger.Error($"{plugin.Name} tried to link but is not registered as a link plugin"); - return false; - } - - if (!_linkPlugins.ContainsKey(link.Id())) - { - _logger.Error($"{plugin.Name} has not been added as a link plugin and cannot set a link"); - return false; - } - - return true; + _logger.Error($"{plugin.Name} tried to link but is not registered as a link plugin"); + return false; } - /// - public void LogDebug(DebugLogger logger) + if (!_linkPlugins.ContainsKey(link.Id())) { - logger.AppendField("Total Links", _links.Count); - logger.AppendList("Plugins", _linkPlugins.Keys); + _logger.Error($"{plugin.Name} has not been added as a link plugin and cannot set a link"); + return false; } + + return true; + } + + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("Total Links", _links.Count); + logger.AppendList("Plugins", _linkPlugins.Keys); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Linking/IDiscordLink.cs b/Oxide.Ext.Discord/Libraries/Linking/IDiscordLink.cs index 4c36f3569..a67d405be 100644 --- a/Oxide.Ext.Discord/Libraries/Linking/IDiscordLink.cs +++ b/Oxide.Ext.Discord/Libraries/Linking/IDiscordLink.cs @@ -2,17 +2,16 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a plugin that supports Discord Link library +/// +public interface IDiscordLink : IPluginBase { /// - /// Represents a plugin that supports Discord Link library + /// Returns a of Steam ID's to Discord ID's /// - public interface IDiscordLink : IPluginBase - { - /// - /// Returns a of Steam ID's to Discord ID's - /// - /// - IDictionary GetPlayerIdToDiscordIds(); - } + /// + IDictionary GetPlayerIdToDiscordIds(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Linking/PlayerId.cs b/Oxide.Ext.Discord/Libraries/Linking/PlayerId.cs index 08856b86f..a56d6cf1e 100644 --- a/Oxide.Ext.Discord/Libraries/Linking/PlayerId.cs +++ b/Oxide.Ext.Discord/Libraries/Linking/PlayerId.cs @@ -2,55 +2,45 @@ using Oxide.Core.Libraries.Covalence; using Oxide.Ext.Discord.Cache; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a Player ID +/// +public readonly record struct PlayerId { /// - /// Represents a Player ID + /// ID of the player /// - public struct PlayerId : IEquatable - { - /// - /// ID of the player - /// - public readonly string Id; + public readonly string Id; - /// - /// Returns true if the ID is valid; false otherwise - /// - public bool IsValid => !string.IsNullOrEmpty(Id); + /// + /// Returns true if the ID is valid; false otherwise + /// + public bool IsValid => !string.IsNullOrEmpty(Id); - /// - /// Returns the IPlayer for the Player ID - /// - public IPlayer Player => IsValid ? ServerPlayerCache.Instance.GetPlayerById(Id) : null; + /// + /// Returns the IPlayer for the Player ID + /// + public IPlayer Player => IsValid ? ServerPlayerCache.Instance.GetPlayerById(Id) : null; - /// - /// Constructor - /// - /// ID of the player - /// Thrown if ID is null - public PlayerId(string id) - { - Id = !string.IsNullOrEmpty(id) ? id : throw new ArgumentNullException(nameof(id)); - } + /// + /// Constructor + /// + /// ID of the player + /// Thrown if ID is null + public PlayerId(string id) + { + Id = !string.IsNullOrEmpty(id) ? id : throw new ArgumentNullException(nameof(id)); + } - /// - /// Constructor - /// - /// IPlayer for the ID - /// Thrown if the IPlayer is null - public PlayerId(IPlayer player) - { - Id = player?.Id ?? throw new ArgumentNullException(nameof(player)); - } - - /// - public bool Equals(PlayerId other) => Id == other.Id; - - /// - public override bool Equals(object obj) => obj is PlayerId other && Equals(other); - - /// - public override int GetHashCode() => Id != null ? Id.GetHashCode() : 0; + /// + /// Constructor + /// + /// IPlayer for the ID + /// Thrown if the IPlayer is null + public PlayerId(IPlayer player) + { + Id = player?.Id ?? throw new ArgumentNullException(nameof(player)); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Locale/DiscordLocale.cs b/Oxide.Ext.Discord/Libraries/Locale/DiscordLocale.cs index 168034295..eb944e8c0 100644 --- a/Oxide.Ext.Discord/Libraries/Locale/DiscordLocale.cs +++ b/Oxide.Ext.Discord/Libraries/Locale/DiscordLocale.cs @@ -4,92 +4,66 @@ using Oxide.Ext.Discord.Json; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a Locale in Discord +/// +[JsonConverter(typeof(DiscordLocaleConverter))] +public readonly record struct DiscordLocale { /// - /// Represents a Locale in Discord + /// ID of the locale /// - [JsonConverter(typeof(DiscordLocaleConverter))] - public struct DiscordLocale : IEquatable - { - /// - /// ID of the locale - /// - public readonly string Id; + public readonly string Id; - /// - /// Is the Locale Valid - /// - public bool IsValid => !string.IsNullOrEmpty(Id); + /// + /// Is the Locale Valid + /// + public bool IsValid => !string.IsNullOrEmpty(Id); - /// - /// Returns the Server Locale for this Discord Locale - /// - /// - public ServerLocale GetServerLocale() => DiscordLocales.Instance.GetServerLanguage(this); + /// + /// Returns the Server Locale for this Discord Locale + /// + /// + public ServerLocale GetServerLocale() => DiscordLocales.Instance.GetServerLanguage(this); - private static DateTime _lastError; - private static readonly List LocaleError = new List(); + private static DateTime _lastError; + private static readonly List LocaleError = new(); - private DiscordLocale(string id) - { - Id = id; - } + private DiscordLocale(string id) + { + Id = id; + } - /// - /// Parses a Discord Locale - /// - /// Locale to Parse - /// Parsed Discord Locale - public static DiscordLocale Parse(string locale) + /// + /// Parses a Discord Locale + /// + /// Locale to Parse + /// Parsed Discord Locale + public static DiscordLocale Parse(string locale) + { + DiscordLocale discordLocale = new(locale); + if (!DiscordLocales.Instance.Contains(discordLocale)) { - DiscordLocale discordLocale = new DiscordLocale(locale); - if (!DiscordLocales.Instance.Contains(discordLocale)) + if (!LocaleError.Contains(locale) || _lastError + TimeSpan.FromMinutes(5) < DateTime.UtcNow) { - if (!LocaleError.Contains(locale) || _lastError + TimeSpan.FromMinutes(5) < DateTime.UtcNow) - { - LocaleError.Remove(locale); - LocaleError.Add(locale); - _lastError = DateTime.UtcNow; - DiscordExtension.GlobalLogger.Warning("Parsed DiscordLocale '{0}' which does not exist in DiscordLang. " + - "Please give this message to the Discord Extension Authors", locale); - } + LocaleError.Remove(locale); + LocaleError.Add(locale); + _lastError = DateTime.UtcNow; + DiscordExtension.GlobalLogger.Warning("Parsed DiscordLocale '{0}' which does not exist in DiscordLang. " + + "Please give this message to the Discord Extension Authors", locale); } - - return discordLocale; } - internal static DiscordLocale Create(string locale) => new DiscordLocale(locale); - - /// - public bool Equals(DiscordLocale other) => Id == other.Id; - - /// - public override bool Equals(object obj) => obj is DiscordLocale other && Equals(other); - - /// - public override int GetHashCode() => Id != null ? Id.GetHashCode() : 0; + return discordLocale; + } - /// - /// Returns if two Discord Locales are equal to each other - /// - /// - /// - /// - public static bool operator == (DiscordLocale left, DiscordLocale right) => left.Equals(right); - - /// - /// Returns if two Discord Locales are not equal to each other - /// - /// - /// - /// - public static bool operator != (DiscordLocale left, DiscordLocale right) => !(left == right); + internal static DiscordLocale Create(string locale) => new(locale); - /// - /// Returns the ID of the Locale - /// - /// - public override string ToString() => Id; - } + /// + /// Returns the ID of the Locale + /// + /// + public override string ToString() => Id; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Locale/DiscordLocales.cs b/Oxide.Ext.Discord/Libraries/Locale/DiscordLocales.cs index cf46f66a5..87bd59482 100644 --- a/Oxide.Ext.Discord/Libraries/Locale/DiscordLocales.cs +++ b/Oxide.Ext.Discord/Libraries/Locale/DiscordLocales.cs @@ -12,257 +12,270 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Converts discord locale codes into oxide locale codes +/// +public class DiscordLocales : BaseDiscordLibrary { /// - /// Converts discord locale codes into oxide locale codes + /// Default Oxide Lang (English) /// - public class DiscordLocales : BaseDiscordLibrary - { - /// - /// Default Oxide Lang (English) - /// - public const string DefaultServerLanguage = "en"; + public const string DefaultServerLanguage = "en"; - /// - /// Returns the Oxide Server language - /// - public ServerLocale ServerLanguage => ServerLocale.Create(OxideLibrary.Instance.Lang.GetServerLanguage()); + /// + /// Returns the Oxide Server language + /// + public ServerLocale ServerLanguage => ServerLocale.Create(OxideLibrary.Instance.Lang.GetServerLanguage()); - private readonly Hash> _pluginLangCache = new Hash>(); + private readonly Hash> _pluginLangCache = new(); - private readonly ILogger _logger; + private readonly ILogger _logger; - private readonly BidirectionalDictionary _locales = new BidirectionalDictionary - { - [ServerLocale.Create("en")] = DiscordLocale.Create("en-US"), - [ServerLocale.Create("bg")] = DiscordLocale.Create("bg"), - [ServerLocale.Create("zh")] = DiscordLocale.Create("zh-CN"), - [ServerLocale.Create("hr")] = DiscordLocale.Create("hr"), - [ServerLocale.Create("cs")] = DiscordLocale.Create("cs"), - [ServerLocale.Create("da")] = DiscordLocale.Create("da"), - [ServerLocale.Create("id")] = DiscordLocale.Create("id-Id"), - [ServerLocale.Create("nl")] = DiscordLocale.Create("nl"), - [ServerLocale.Create("fi")] = DiscordLocale.Create("fi"), - [ServerLocale.Create("fr")] = DiscordLocale.Create("fr"), - [ServerLocale.Create("de")] = DiscordLocale.Create("de"), - [ServerLocale.Create("el")] = DiscordLocale.Create("el"), - [ServerLocale.Create("hi")] = DiscordLocale.Create("hi"), - [ServerLocale.Create("hu")] = DiscordLocale.Create("hu"), - [ServerLocale.Create("it")] = DiscordLocale.Create("it"), - [ServerLocale.Create("ja")] = DiscordLocale.Create("ja"), - [ServerLocale.Create("ko")] = DiscordLocale.Create("ko"), - [ServerLocale.Create("lt")] = DiscordLocale.Create("lt"), - [ServerLocale.Create("no")] = DiscordLocale.Create("no"), - [ServerLocale.Create("pl")] = DiscordLocale.Create("pl"), - [ServerLocale.Create("pt")] = DiscordLocale.Create("pt-BR"), - [ServerLocale.Create("ro")] = DiscordLocale.Create("ro"), - [ServerLocale.Create("ru")] = DiscordLocale.Create("ru"), - [ServerLocale.Create("es")] = DiscordLocale.Create("es-ES"), - [ServerLocale.Create("sv")] = DiscordLocale.Create("sv-SE"), - [ServerLocale.Create("th")] = DiscordLocale.Create("th"), - [ServerLocale.Create("tr")] = DiscordLocale.Create("tr"), - [ServerLocale.Create("uk")] = DiscordLocale.Create("uk"), - [ServerLocale.Create("vi")] = DiscordLocale.Create("vi"), - }; + private readonly BidirectionalDictionary _locales = new() + { + [ServerLocale.Create("en")] = DiscordLocale.Create("en-US"), + [ServerLocale.Create("bg")] = DiscordLocale.Create("bg"), + [ServerLocale.Create("zh")] = DiscordLocale.Create("zh-CN"), + [ServerLocale.Create("hr")] = DiscordLocale.Create("hr"), + [ServerLocale.Create("cs")] = DiscordLocale.Create("cs"), + [ServerLocale.Create("da")] = DiscordLocale.Create("da"), + [ServerLocale.Create("id")] = DiscordLocale.Create("id-Id"), + [ServerLocale.Create("nl")] = DiscordLocale.Create("nl"), + [ServerLocale.Create("fi")] = DiscordLocale.Create("fi"), + [ServerLocale.Create("fr")] = DiscordLocale.Create("fr"), + [ServerLocale.Create("de")] = DiscordLocale.Create("de"), + [ServerLocale.Create("el")] = DiscordLocale.Create("el"), + [ServerLocale.Create("hi")] = DiscordLocale.Create("hi"), + [ServerLocale.Create("hu")] = DiscordLocale.Create("hu"), + [ServerLocale.Create("it")] = DiscordLocale.Create("it"), + [ServerLocale.Create("ja")] = DiscordLocale.Create("ja"), + [ServerLocale.Create("ko")] = DiscordLocale.Create("ko"), + [ServerLocale.Create("lt")] = DiscordLocale.Create("lt"), + [ServerLocale.Create("no")] = DiscordLocale.Create("no"), + [ServerLocale.Create("pl")] = DiscordLocale.Create("pl"), + [ServerLocale.Create("pt")] = DiscordLocale.Create("pt-BR"), + [ServerLocale.Create("ro")] = DiscordLocale.Create("ro"), + [ServerLocale.Create("ru")] = DiscordLocale.Create("ru"), + [ServerLocale.Create("es")] = DiscordLocale.Create("es-ES"), + [ServerLocale.Create("sv")] = DiscordLocale.Create("sv-SE"), + [ServerLocale.Create("th")] = DiscordLocale.Create("th"), + [ServerLocale.Create("tr")] = DiscordLocale.Create("tr"), + [ServerLocale.Create("uk")] = DiscordLocale.Create("uk"), + [ServerLocale.Create("vi")] = DiscordLocale.Create("vi"), + }; - /// - /// Constructor - /// - /// - internal DiscordLocales(ILogger logger) - { - _logger = logger; + /// + /// Constructor + /// + /// + internal DiscordLocales(ILogger logger) + { + _logger = logger; - AddOxideLocale(ServerLocale.Create("pt-BR"), DiscordLocale.Create("pt-BR")); - AddDiscordLocale(DiscordLocale.Create("en-GB"), ServerLocale.Create("en")); - AddDiscordLocale(DiscordLocale.Create("zh-TW"), ServerLocale.Create("zh")); - AddDiscordLocale(DiscordLocale.Create("es-419"), ServerLocale.Create("es")); - } + AddOxideLocale(ServerLocale.Create("pt-BR"), DiscordLocale.Create("pt-BR")); + AddOxideLocale(ServerLocale.Create("es-ES"), DiscordLocale.Create("es-ES")); + AddOxideLocale(ServerLocale.Create("zh-CN"), DiscordLocale.Create("zh-CN")); + AddDiscordLocale(DiscordLocale.Create("en-GB"), ServerLocale.Create("en")); + AddDiscordLocale(DiscordLocale.Create("zh-TW"), ServerLocale.Create("zh")); + AddDiscordLocale(DiscordLocale.Create("es-419"), ServerLocale.Create("es")); + } - /// - /// Adds a one way -> mapping - /// - /// - /// - public void AddOxideLocale(ServerLocale serverLang, DiscordLocale discordLang) => _locales.AddKey(serverLang, discordLang); + /// + /// Adds a one way -> mapping + /// + /// + /// + public void AddOxideLocale(ServerLocale serverLang, DiscordLocale discordLang) => _locales.AddKey(serverLang, discordLang); - /// - /// Adds a one way -> mapping - /// - /// - /// - public void AddDiscordLocale(DiscordLocale discordLang, ServerLocale serverLang) => _locales.AddValue(discordLang, serverLang); + /// + /// Adds a one way -> mapping + /// + /// + /// + public void AddDiscordLocale(DiscordLocale discordLang, ServerLocale serverLang) => _locales.AddValue(discordLang, serverLang); - /// - /// Returns if the mapping exists - /// - /// - /// - public bool Contains(ServerLocale locale) => _locales.ContainsKey(locale); + /// + /// Returns if the mapping exists + /// + /// + /// + public bool Contains(ServerLocale locale) => _locales.ContainsKey(locale); - /// - /// Returns if the mapping exists - /// - /// - /// - public bool Contains(DiscordLocale locale) => _locales.ContainsKey(locale); + /// + /// Returns if the mapping exists + /// + /// + /// + public bool Contains(DiscordLocale locale) => _locales.ContainsKey(locale); - /// - /// Returns the oxide locale for a given discord locale - /// - /// Discord locale to get oxide locale for - /// Oxide locale if it exists; null otherwise - public ServerLocale GetServerLanguage(DiscordLocale discordLocale) => _locales.TryGetValue(discordLocale, out ServerLocale serverLocale) ? serverLocale : default(ServerLocale); + /// + /// Returns the oxide locale for a given discord locale + /// + /// Discord locale to get oxide locale for + /// Oxide locale if it exists; null otherwise + public ServerLocale GetServerLanguage(DiscordLocale discordLocale) => _locales.TryGetValue(discordLocale, out ServerLocale serverLocale) ? serverLocale : default; - /// - /// Returns the discord locale for a given oxide locale - /// - /// oxide locale to get discord locale for - /// Discord locale if it exists; null otherwise - public DiscordLocale GetDiscordLocale(ServerLocale serverLocale) => _locales.TryGetValue(serverLocale, out DiscordLocale discordLocale) ? discordLocale : default(DiscordLocale); + /// + /// Returns the discord locale for a given oxide locale + /// + /// oxide locale to get discord locale for + /// Discord locale if it exists; null otherwise + public DiscordLocale GetDiscordLocale(ServerLocale serverLocale) => _locales.TryGetValue(serverLocale, out DiscordLocale discordLocale) ? discordLocale : default; - /// - /// Returns the oxide locale for the given IPlayer - /// - /// to get the locale for - /// Locale for the given IPlayer - public ServerLocale GetPlayerLanguage(IPlayer player) => GetPlayerLanguage(player?.Id); + /// + /// Returns the oxide locale for the given IPlayer + /// + /// to get the locale for + /// Locale for the given IPlayer + public ServerLocale GetPlayerLanguage(IPlayer player) => GetPlayerLanguage(player?.Id); - /// - /// Returns the oxide locale for the given playerId - /// - /// PlayerId to get the locale for - /// Locale for the given playerId - public ServerLocale GetPlayerLanguage(string playerId) => ServerLocale.Parse(OxideLibrary.Instance.Lang.GetLanguage(playerId)); + /// + /// Returns the oxide locale for the given playerId + /// + /// PlayerId to get the locale for + /// Locale for the given playerId + public ServerLocale GetPlayerLanguage(string playerId) => ServerLocale.Parse(OxideLibrary.Instance.Lang.GetLanguage(playerId)); - /// - /// Returns all the discord localizations for a specific lang key in a plugin - /// - /// - /// - /// - public Hash GetDiscordLocalizations(Plugin plugin, string langKey) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (langKey == null) throw new ArgumentNullException(nameof(langKey)); + /// + /// Returns all the discord localizations for a specific lang key in a plugin + /// + /// + /// + /// + public Hash GetDiscordLocalizations(Plugin plugin, string langKey) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (langKey == null) throw new ArgumentNullException(nameof(langKey)); - Hash localization = new Hash(); - string[] languages = OxideLibrary.Instance.Lang.GetLanguages(plugin); - for (int index = 0; index < languages.Length; index++) + Hash localization = new(); + string[] languages = OxideLibrary.Instance.Lang.GetLanguages(plugin); + for (int index = 0; index < languages.Length; index++) + { + ServerLocale serverLocale = ServerLocale.Parse(languages[index]); + DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); + if (!discordLocale.IsValid) { - ServerLocale serverLocale = ServerLocale.Parse(languages[index]); - DiscordLocale discordLocale = serverLocale.GetDiscordLocale(); - if (!discordLocale.IsValid) - { - _logger.Warning("Discord Extension failed to find discord locale for oxide language '{0}' for '{1}'. Please give this message to the Discord Extension Authors", serverLocale, plugin.FullName()); - continue; - } - - Hash messages = GetLanguageMessages(plugin, serverLocale); - if (!messages.ContainsKey(langKey)) - { - //DiscordExtension.GlobalLogger.Warning("Failed to add localized message for lang key '{0}' for plugin '{1} because lang key doesn't exist for language {2}", langKey, plugin.FullName(), language); - continue; - } - - localization[discordLocale.Id] = messages[langKey]; + _logger.Warning("Discord Extension failed to find discord locale for oxide language '{0}' for '{1}'. Please give this message to the Discord Extension Authors", serverLocale, plugin.FullName()); + continue; } - return localization; + Hash messages = GetLanguageMessages(plugin, serverLocale); + if (!messages.TryGetValue(langKey, out string message)) + { + //DiscordExtension.GlobalLogger.Warning("Failed to add localized message for lang key '{0}' for plugin '{1} because lang key doesn't exist for language {2}", langKey, plugin.FullName(), language); + continue; + } + + localization[discordLocale.Id] = message; } - /// - /// Retrieves the lang message for a Discord Interaction - /// - /// Plugin the lang is from - /// The interaction to be localized - /// The lang key to lookup - /// Localized message if found; Empty string otherwise - /// Thrown if any of the input arguments are null - public string GetDiscordInteractionLangMessage(Plugin plugin, DiscordInteraction interaction, string langKey) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (interaction == null) throw new ArgumentNullException(nameof(interaction)); - if (langKey == null) throw new ArgumentNullException(nameof(langKey)); + return localization; + } + + /// + /// Retrieves the lang message for a Discord Interaction + /// + /// Plugin the lang is from + /// The interaction to be localized + /// The lang key to lookup + /// Localized message if found; Empty string otherwise + /// Thrown if any of the input arguments are null + public string GetDiscordInteractionLangMessage(Plugin plugin, DiscordInteraction interaction, string langKey) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (interaction == null) throw new ArgumentNullException(nameof(interaction)); + if (langKey == null) throw new ArgumentNullException(nameof(langKey)); - IPlayer player = interaction.User.Player; + IPlayer player = interaction.User.Player; - //Retrieves the plugin lang messages. If the messages are not found for a language then it will check in the following order - // 1. Interaction.Locale - Discord User's Locale - // 2. Oxide IPlayer Locale - // 3. Interaction.GuildLocale - Application Command Guild Locale - // 4. Oxide Lang Language - // 5. English - string message = GetLanguageMessages(plugin, interaction.Locale.GetServerLocale())?[langKey] - ?? (player != null ? GetLanguageMessages(plugin, GetPlayerLanguage(player))?[langKey] : null) - ?? (interaction.GuildLocale.HasValue ? GetLanguageMessages(plugin, interaction.GuildLocale.Value.GetServerLocale())?[langKey] : null) - ?? GetLanguageMessages(plugin, ServerLanguage)?[langKey] - ?? GetLanguageMessages(plugin, ServerLocale.Default)?[langKey]; + //Retrieves the plugin lang messages. If the messages are not found for a language then it will check in the following order + // 1. Interaction.Locale - Discord User's Locale + // 2. Oxide IPlayer Locale + // 3. Interaction.GuildLocale - Application Command Guild Locale + // 4. Oxide Lang Language + // 5. English + string message = GetLanguageMessages(plugin, interaction.Locale.GetServerLocale())?[langKey] + ?? (player != null ? GetLanguageMessages(plugin, GetPlayerLanguage(player))?[langKey] : null) + ?? (interaction.GuildLocale.HasValue ? GetLanguageMessages(plugin, interaction.GuildLocale.Value.GetServerLocale())?[langKey] : null) + ?? GetLanguageMessages(plugin, ServerLanguage)?[langKey] + ?? GetLanguageMessages(plugin, ServerLocale.Default)?[langKey]; - return !string.IsNullOrEmpty(message) ? message : langKey; - } + return !string.IsNullOrEmpty(message) ? message : langKey; + } - /// - /// Retrieves the lang message for a Discord Interaction - /// - /// Plugin the lang is from - /// The interaction to be localized - /// The lang key to lookup - /// Localization formatting args - /// Localized message if found; Empty string otherwise - /// Thrown if any of the input arguments are null - public string GetDiscordInteractionLangMessage(Plugin plugin, DiscordInteraction interaction, string langKey, params object[] args) + internal string GetLangMessage(Plugin plugin, IPlayer player, string langKey) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (langKey == null) throw new ArgumentNullException(nameof(langKey)); + + string message = (player != null ? GetLanguageMessages(plugin, GetPlayerLanguage(player))?[langKey] : null) + ?? GetLanguageMessages(plugin, ServerLanguage)?[langKey] + ?? GetLanguageMessages(plugin, ServerLocale.Default)?[langKey]; + + return !string.IsNullOrEmpty(message) ? message : langKey; + } + + /// + /// Retrieves the lang message for a Discord Interaction + /// + /// Plugin the lang is from + /// The interaction to be localized + /// The lang key to lookup + /// Localization formatting args + /// Localized message if found; Empty string otherwise + /// Thrown if any of the input arguments are null + public string GetDiscordInteractionLangMessage(Plugin plugin, DiscordInteraction interaction, string langKey, params object[] args) + { + string message = GetDiscordInteractionLangMessage(plugin, interaction, langKey); + if (string.IsNullOrEmpty(message)) { - string message = GetDiscordInteractionLangMessage(plugin, interaction, langKey); - if (string.IsNullOrEmpty(message)) - { - return langKey; - } + return langKey; + } - try - { - return string.Format(message, args); - } - catch(Exception ex) - { - _logger.Exception("Plugin {0} Lang Key '{1}'\nMessage:{2}\nArgs:{3}", plugin, langKey, message, string.Join(", ", args.Select(a => a.ToString()).ToArray()), ex); - return message; - } + try + { + return string.Format(message, args); + } + catch(Exception ex) + { + _logger.Exception("Plugin {0} Lang Key '{1}'\nMessage:{2}\nArgs:{3}", plugin, langKey, message, string.Join(", ", args.Select(a => a.ToString()).ToArray()), ex); + return message; } + } - private Hash GetLanguageMessages(Plugin plugin, ServerLocale language) + private Hash GetLanguageMessages(Plugin plugin, ServerLocale language) + { + if (!language.IsValid) { - if (!language.IsValid) - { - return null; - } + return null; + } - PluginLocale id = new PluginLocale(plugin, language); - Hash langCache = _pluginLangCache[id]; + PluginLocale id = new(plugin, language); + Hash langCache = _pluginLangCache[id]; - if (langCache == null) + if (langCache == null) + { + langCache = new Hash(); + _pluginLangCache[id] = langCache; + Dictionary messages = OxideLibrary.Instance.Lang.GetMessages(language.Id, plugin); + if (messages != null) { - langCache = new Hash(); - _pluginLangCache[id] = langCache; - Dictionary messages = OxideLibrary.Instance.Lang.GetMessages(language.Id, plugin); - if (messages != null) + foreach (KeyValuePair lang in messages) { - foreach (KeyValuePair lang in messages) - { - langCache[lang.Key] = lang.Value; - } + langCache[lang.Key] = lang.Value; } } - - return langCache; } - /// - protected override void OnPluginUnloaded(Plugin plugin) - { - PluginId pluginId = plugin.Id(); - _pluginLangCache.RemoveAll(p => pluginId == p.Key.PluginId); - } + return langCache; + } + + /// + protected override void OnPluginUnloaded(Plugin plugin) + { + PluginId pluginId = plugin.Id(); + _pluginLangCache.RemoveAll(p => pluginId == p.Key.PluginId); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Locale/PluginLocale.cs b/Oxide.Ext.Discord/Libraries/Locale/PluginLocale.cs index f4077d794..23c6823ef 100644 --- a/Oxide.Ext.Discord/Libraries/Locale/PluginLocale.cs +++ b/Oxide.Ext.Discord/Libraries/Locale/PluginLocale.cs @@ -3,43 +3,22 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries -{ - internal struct PluginLocale : IEquatable - { - internal readonly PluginId PluginId; - private readonly ServerLocale _language; +namespace Oxide.Ext.Discord.Libraries; - public PluginLocale(Plugin plugin, ServerLocale language) - { - if(!language.IsValid) throw new ArgumentNullException(nameof(language)); - PluginId = plugin?.Id() ?? throw new ArgumentNullException(nameof(plugin)); - _language = language; - } - - public bool Equals(PluginLocale other) - { - return PluginId == other.PluginId && _language == other._language; - } - - public override bool Equals(object obj) - { - return obj is PluginLocale other && Equals(other); - } +internal readonly record struct PluginLocale +{ + internal readonly PluginId PluginId; + private readonly ServerLocale _language; - public override string ToString() - { - return $"Plugin: {PluginId.ToString()} Language: {_language}"; - } + public PluginLocale(Plugin plugin, ServerLocale language) + { + if(!language.IsValid) throw new ArgumentNullException(nameof(language)); + PluginId = plugin?.Id() ?? throw new ArgumentNullException(nameof(plugin)); + _language = language; + } - public override int GetHashCode() - { - unchecked - { - int hashCode = PluginId.GetHashCode(); - hashCode = (hashCode * 397) ^ _language.GetHashCode(); - return hashCode; - } - } + public override string ToString() + { + return $"Plugin: {PluginId.ToString()} Language: {_language}"; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Locale/ServerLocale.cs b/Oxide.Ext.Discord/Libraries/Locale/ServerLocale.cs index 55fb1f934..568ba5d9c 100644 --- a/Oxide.Ext.Discord/Libraries/Locale/ServerLocale.cs +++ b/Oxide.Ext.Discord/Libraries/Locale/ServerLocale.cs @@ -4,103 +4,77 @@ using Oxide.Ext.Discord.Json; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a Server Locale +/// +[JsonConverter(typeof(ServerLocaleConverter))] +public readonly record struct ServerLocale { /// - /// Represents a Server Locale + /// ID of the Locale /// - [JsonConverter(typeof(ServerLocaleConverter))] - public struct ServerLocale : IEquatable - { - /// - /// ID of the Locale - /// - public readonly string Id; + public readonly string Id; - /// - /// Returns if the Locale is valid - /// - public bool IsValid => !string.IsNullOrEmpty(Id); + /// + /// Returns if the Locale is valid + /// + public bool IsValid => !string.IsNullOrEmpty(Id); - /// - /// Returns if the Locale is the default server language "en" - /// - public bool IsDefault => IsValid && this == Default; + /// + /// Returns if the Locale is the default server language "en" + /// + public bool IsDefault => IsValid && this == Default; - /// - /// Returns the for this server locale - /// - /// - public DiscordLocale GetDiscordLocale() => DiscordLocales.Instance.GetDiscordLocale(this); + /// + /// Returns the for this server locale + /// + /// + public DiscordLocale GetDiscordLocale() => DiscordLocales.Instance.GetDiscordLocale(this); - /// - /// The default locale for servers - /// - public static readonly ServerLocale Default = new ServerLocale(DiscordLocales.DefaultServerLanguage); + /// + /// The default locale for servers + /// + public static readonly ServerLocale Default = new(DiscordLocales.DefaultServerLanguage); - private static DateTime _lastError; - private static readonly List LocaleError = new List(); + private static DateTime _lastError; + private static readonly List LocaleError = new(); - private ServerLocale(string id) - { - Id = id; - } + private ServerLocale(string id) + { + Id = id; + } - /// - /// Parses a locale returning a - /// - /// - /// - public static ServerLocale Parse(string locale) + /// + /// Parses a locale returning a + /// + /// + /// + public static ServerLocale Parse(string locale) + { + ServerLocale serverLocale = new(locale); + if (!DiscordLocales.Instance.Contains(serverLocale)) { - ServerLocale serverLocale = new ServerLocale(locale); - if (!DiscordLocales.Instance.Contains(serverLocale)) + if (!LocaleError.Contains(locale) || _lastError + TimeSpan.FromMinutes(5) < DateTime.UtcNow) { - if (!LocaleError.Contains(locale) || _lastError + TimeSpan.FromMinutes(5) < DateTime.UtcNow) - { - LocaleError.Remove(locale); - LocaleError.Add(locale); - _lastError = DateTime.UtcNow; - DiscordExtension.GlobalLogger.Warning("Parsed ServerLocale '{0}' which does not exist in DiscordLang. " + - "Please give this message to the Discord Extension Authors", locale); - } - + LocaleError.Remove(locale); + LocaleError.Add(locale); + _lastError = DateTime.UtcNow; + DiscordExtension.GlobalLogger.Warning("Parsed ServerLocale '{0}' which does not exist in DiscordLang. " + + "Please give this message to the Discord Extension Authors", locale); } - return serverLocale; } - internal static ServerLocale Create(string locale) => new ServerLocale(locale); - - /// - public bool Equals(ServerLocale other) => Id == other.Id; - - /// - public override bool Equals(object obj) => obj is ServerLocale other && Equals(other); + return serverLocale; + } - /// - public override int GetHashCode() => Id != null ? Id.GetHashCode() : 0; - - /// - /// Returns if two Server Locales are equal to each other - /// - /// - /// - /// - public static bool operator == (ServerLocale left, ServerLocale right) => left.Equals(right); - - /// - /// Returns if two Server Locales are not equal to each other - /// - /// - /// - /// - public static bool operator != (ServerLocale left, ServerLocale right) => !(left == right); + internal static ServerLocale Create(string locale) => new(locale); - /// - /// Returns the ID of the ServerLocale - /// - /// - public override string ToString() => Id; - } + /// + /// Returns the ID of the ServerLocale + /// + /// + public override string ToString() => Id; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/BasePlaceholder.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/BasePlaceholder.cs index e78b05639..7c15930ee 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/BasePlaceholder.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/BasePlaceholder.cs @@ -4,33 +4,32 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal abstract class BasePlaceholder : IPlaceholder { - internal abstract class BasePlaceholder : IPlaceholder - { - public string PluginName { get; } - private readonly PluginId _pluginId; - public bool IsExtensionPlaceholder { get; } - private readonly Action _apply; + public string PluginName { get; } + private readonly PluginId _pluginId; + public bool IsExtensionPlaceholder { get; } + private readonly Action _apply; - protected BasePlaceholder(Plugin plugin) - { - _pluginId = plugin.Id(); - PluginName = plugin.FullName(); - IsExtensionPlaceholder = plugin is DiscordExtensionCore; - _apply = PlaceholderFormatting.CreatePlaceholderCallback(); - } + protected BasePlaceholder(Plugin plugin) + { + _pluginId = plugin.Id(); + PluginName = plugin.FullName(); + IsExtensionPlaceholder = plugin is DiscordExtensionCore; + _apply = PlaceholderFormatting.CreatePlaceholderCallback(); + } - public void Invoke(StringBuilder sb, PlaceholderState state) - { - TResult result = InvokeInternal(state); - _apply.Invoke(sb, state, result); - } + public void Invoke(StringBuilder sb, PlaceholderState state) + { + TResult result = InvokeInternal(state); + _apply.Invoke(sb, state, result); + } - public abstract TResult InvokeInternal(PlaceholderState state); + public abstract TResult InvokeInternal(PlaceholderState state); - public bool IsForPlugin(Plugin plugin) => !IsExtensionPlaceholder && plugin.Id() == _pluginId; + public bool IsForPlugin(Plugin plugin) => !IsExtensionPlaceholder && plugin.Id() == _pluginId; - public Type GetReturnType() => typeof(TResult); - } + public Type GetReturnType() => typeof(TResult); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/IPlaceholder.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/IPlaceholder.cs index 4c4d0bdd8..acac720a6 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/IPlaceholder.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/IPlaceholder.cs @@ -2,17 +2,16 @@ using System.Text; using Oxide.Core.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal interface IPlaceholder { - internal interface IPlaceholder - { - string PluginName { get; } - bool IsExtensionPlaceholder { get; } + string PluginName { get; } + bool IsExtensionPlaceholder { get; } - void Invoke(StringBuilder sb, PlaceholderState state); + void Invoke(StringBuilder sb, PlaceholderState state); - bool IsForPlugin(Plugin plugin); + bool IsForPlugin(Plugin plugin); - Type GetReturnType(); - } + Type GetReturnType(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/Placeholder.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/Placeholder.cs index bb365e5a7..a218d106e 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/Placeholder.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/Placeholder.cs @@ -1,17 +1,16 @@ using System; using Oxide.Core.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal class Placeholder : BasePlaceholder { - internal class Placeholder : BasePlaceholder - { - private readonly Func _callback; + private readonly Func _callback; - public Placeholder(Plugin plugin, Func callback) : base(plugin) - { - _callback = callback; - } - - public override TResult InvokeInternal(PlaceholderState state) => _callback.Invoke(); + public Placeholder(Plugin plugin, Func callback) : base(plugin) + { + _callback = callback; } + + public override TResult InvokeInternal(PlaceholderState state) => _callback.Invoke(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/Placeholder{T}.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/Placeholder{T}.cs index a7c4efae5..34621ff57 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/Placeholder{T}.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/Placeholder{T}.cs @@ -1,35 +1,34 @@ using System; using Oxide.Core.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal class Placeholder : BasePlaceholder { - internal class Placeholder : BasePlaceholder - { - private readonly PlaceholderDataKey _dataKey; - private readonly Func _dataCallback; - private readonly Func _callback; + private readonly PlaceholderDataKey _dataKey; + private readonly Func _dataCallback; + private readonly Func _callback; - public Placeholder(PlaceholderDataKey dataKey, Plugin plugin, Func callback) : base(plugin) - { - _dataKey = dataKey; - _dataCallback = callback; - } + public Placeholder(PlaceholderDataKey dataKey, Plugin plugin, Func callback) : base(plugin) + { + _dataKey = dataKey; + _dataCallback = callback; + } - public Placeholder(PlaceholderDataKey dataKey, Plugin plugin, Func callback) : base(plugin) - { - _dataKey = dataKey; - _callback = callback; - } + public Placeholder(PlaceholderDataKey dataKey, Plugin plugin, Func callback) : base(plugin) + { + _dataKey = dataKey; + _callback = callback; + } - public override TResult InvokeInternal(PlaceholderState state) + public override TResult InvokeInternal(PlaceholderState state) + { + T data = state.Data.Get(_dataKey); + if (data != null) { - T data = state.Data.Get(_dataKey); - if (data != null) - { - return _callback != null ? _callback(data) : _dataCallback(state, data); - } - - return default(TResult); + return _callback != null ? _callback(data) : _dataCallback(state, data); } + + return default; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/StaticPlaceholder.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/StaticPlaceholder.cs index d39c3d37a..9e5f70023 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/StaticPlaceholder.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Callbacks/StaticPlaceholder.cs @@ -1,16 +1,15 @@ using Oxide.Core.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal class StaticPlaceholder : BasePlaceholder { - internal class StaticPlaceholder : BasePlaceholder - { - private readonly string _value; + private readonly string _value; - public StaticPlaceholder(Plugin plugin, string value) : base(plugin) - { - _value = value; - } - - public override string InvokeInternal(PlaceholderState state) => _value; + public StaticPlaceholder(Plugin plugin, string value) : base(plugin) + { + _value = value; } + + public override string InvokeInternal(PlaceholderState state) => _value; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/ApplicationCommandPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/ApplicationCommandPlaceholders.cs index 1d5052068..51a3fa49c 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/ApplicationCommandPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/ApplicationCommandPlaceholders.cs @@ -2,51 +2,50 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class ApplicationCommandPlaceholders { /// - /// placeholders + /// placeholder /// - public static class ApplicationCommandPlaceholders - { - /// - /// placeholder - /// - public static Snowflake Id(DiscordApplicationCommand command) => command.Id; + public static Snowflake Id(DiscordApplicationCommand command) => command.Id; - /// - /// placeholder - /// - public static string Name(DiscordApplicationCommand command) => command.Name; + /// + /// placeholder + /// + public static string Name(DiscordApplicationCommand command) => command.Name; - /// - /// placeholder - /// - public static string Mention(DiscordApplicationCommand command) => command.Mention; + /// + /// placeholder + /// + public static string Mention(DiscordApplicationCommand command) => command.Mention; - /// - /// placeholder - /// - public static string MentionCustom(PlaceholderState state, DiscordApplicationCommand command) => command.MentionCustom(state.Format); + /// + /// placeholder + /// + public static string MentionCustom(PlaceholderState state, DiscordApplicationCommand command) => command.MentionCustom(state.Format); - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.AppCommand, new PlaceholderDataKey(nameof(DiscordApplicationCommand))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.AppCommand, new PlaceholderDataKey(nameof(DiscordApplicationCommand))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, AppCommandKeys keys , PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); - placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); - placeholders.RegisterPlaceholder(plugin, keys.Mention, dataKey, Mention); - placeholders.RegisterPlaceholder(plugin, keys.MentionCustom, dataKey, MentionCustom); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, AppCommandKeys keys , PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); + placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); + placeholders.RegisterPlaceholder(plugin, keys.Mention, dataKey, Mention); + placeholders.RegisterPlaceholder(plugin, keys.MentionCustom, dataKey, MentionCustom); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/ChannelPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/ChannelPlaceholders.cs index 6ab760083..70412a1b5 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/ChannelPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/ChannelPlaceholders.cs @@ -2,57 +2,56 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholders +/// +public static class ChannelPlaceholders { /// - /// Placeholders + /// placeholder /// - public static class ChannelPlaceholders - { - /// - /// placeholder - /// - public static Snowflake Id(DiscordChannel channel) => channel.Id; + public static Snowflake Id(DiscordChannel channel) => channel.Id; - /// - /// placeholder - /// - public static string Name(DiscordChannel channel) => channel.Name; + /// + /// placeholder + /// + public static string Name(DiscordChannel channel) => channel.Name; - /// - /// placeholder - /// - public static string Icon(DiscordChannel channel) => channel.IconUrl; + /// + /// placeholder + /// + public static string Icon(DiscordChannel channel) => channel.IconUrl; - /// - /// placeholder - /// - public static string Topic(DiscordChannel channel) => channel.Topic; + /// + /// placeholder + /// + public static string Topic(DiscordChannel channel) => channel.Topic; - /// - /// placeholder - /// - public static string Mention(DiscordChannel channel) => channel.Mention; + /// + /// placeholder + /// + public static string Mention(DiscordChannel channel) => channel.Mention; - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Channel, new PlaceholderDataKey(nameof(DiscordChannel))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Channel, new PlaceholderDataKey(nameof(DiscordChannel))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, ChannelKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); - placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); - placeholders.RegisterPlaceholder(plugin, keys.Icon, dataKey, Icon); - placeholders.RegisterPlaceholder(plugin, keys.Topic, dataKey, Topic); - placeholders.RegisterPlaceholder(plugin, keys.Mention, dataKey, Mention); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, ChannelKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); + placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); + placeholders.RegisterPlaceholder(plugin, keys.Icon, dataKey, Icon); + placeholders.RegisterPlaceholder(plugin, keys.Topic, dataKey, Topic); + placeholders.RegisterPlaceholder(plugin, keys.Mention, dataKey, Mention); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/DateTimePlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/DateTimePlaceholders.cs index 3798e7f53..364fd3824 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/DateTimePlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/DateTimePlaceholders.cs @@ -2,84 +2,83 @@ using Oxide.Core.Plugins; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class DateTimePlaceholders { /// - /// placeholders + /// placeholder /// - public static class DateTimePlaceholders - { - /// - /// placeholder - /// - public static int Year(DateTime date) => date.Year; + public static int Year(DateTime date) => date.Year; - /// - /// placeholder - /// - public static int Month(DateTime date) => date.Month; + /// + /// placeholder + /// + public static int Month(DateTime date) => date.Month; - /// - /// placeholder - /// - public static int Day(DateTime date) => date.Day; + /// + /// placeholder + /// + public static int Day(DateTime date) => date.Day; - /// - /// placeholder - /// - public static int Hour(DateTime date) => date.Hour; + /// + /// placeholder + /// + public static int Hour(DateTime date) => date.Hour; - /// - /// placeholder - /// - public static int Minute(DateTime date) => date.Minute; + /// + /// placeholder + /// + public static int Minute(DateTime date) => date.Minute; - /// - /// placeholder - /// - public static int Second(DateTime date) => date.Second; + /// + /// placeholder + /// + public static int Second(DateTime date) => date.Second; - /// - /// placeholder - /// - public static int Millisecond(DateTime date) => date.Millisecond; + /// + /// placeholder + /// + public static int Millisecond(DateTime date) => date.Millisecond; - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.DateTime, new PlaceholderDataKey(nameof(DateTime))); - RegisterNowPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.DateTimeNow); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.DateTime, new PlaceholderDataKey(nameof(DateTime))); + RegisterNowPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.DateTimeNow); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, DateTimeKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Date, dataKey); - placeholders.RegisterPlaceholder(plugin, keys.Year, dataKey, Year); - placeholders.RegisterPlaceholder(plugin, keys.Month, dataKey, Month); - placeholders.RegisterPlaceholder(plugin, keys.Day, dataKey, Day); - placeholders.RegisterPlaceholder(plugin, keys.Hour, dataKey, Hour); - placeholders.RegisterPlaceholder(plugin, keys.Minute, dataKey, Minute); - placeholders.RegisterPlaceholder(plugin, keys.Second, dataKey, Second); - placeholders.RegisterPlaceholder(plugin, keys.Millisecond, dataKey, Millisecond); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, DateTimeKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Date, dataKey); + placeholders.RegisterPlaceholder(plugin, keys.Year, dataKey, Year); + placeholders.RegisterPlaceholder(plugin, keys.Month, dataKey, Month); + placeholders.RegisterPlaceholder(plugin, keys.Day, dataKey, Day); + placeholders.RegisterPlaceholder(plugin, keys.Hour, dataKey, Hour); + placeholders.RegisterPlaceholder(plugin, keys.Minute, dataKey, Minute); + placeholders.RegisterPlaceholder(plugin, keys.Second, dataKey, Second); + placeholders.RegisterPlaceholder(plugin, keys.Millisecond, dataKey, Millisecond); + } - private static void RegisterNowPlaceholders(Plugin plugin, DateTimeKeys keys) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Date, () => DateTime.Now); - placeholders.RegisterPlaceholder(plugin, keys.Year, () => DateTime.Now.Year); - placeholders.RegisterPlaceholder(plugin, keys.Month, () => DateTime.Now.Month); - placeholders.RegisterPlaceholder(plugin, keys.Day, () => DateTime.Now.Day); - placeholders.RegisterPlaceholder(plugin, keys.Hour, () => DateTime.Now.Hour); - placeholders.RegisterPlaceholder(plugin, keys.Minute, () => DateTime.Now.Minute); - placeholders.RegisterPlaceholder(plugin, keys.Second, () => DateTime.Now.Second); - placeholders.RegisterPlaceholder(plugin, keys.Millisecond, () => DateTime.Now.Millisecond); - } + private static void RegisterNowPlaceholders(Plugin plugin, DateTimeKeys keys) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Date, () => DateTime.Now); + placeholders.RegisterPlaceholder(plugin, keys.Year, () => DateTime.Now.Year); + placeholders.RegisterPlaceholder(plugin, keys.Month, () => DateTime.Now.Month); + placeholders.RegisterPlaceholder(plugin, keys.Day, () => DateTime.Now.Day); + placeholders.RegisterPlaceholder(plugin, keys.Hour, () => DateTime.Now.Hour); + placeholders.RegisterPlaceholder(plugin, keys.Minute, () => DateTime.Now.Minute); + placeholders.RegisterPlaceholder(plugin, keys.Second, () => DateTime.Now.Second); + placeholders.RegisterPlaceholder(plugin, keys.Millisecond, () => DateTime.Now.Millisecond); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/GuildPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/GuildPlaceholders.cs index 0d85009b0..4fcf2d05e 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/GuildPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/GuildPlaceholders.cs @@ -2,63 +2,62 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class GuildPlaceholders { /// - /// placeholders + /// placeholder /// - public static class GuildPlaceholders - { - /// - /// placeholder - /// - public static Snowflake Id(DiscordGuild guild) => guild.Id; + public static Snowflake Id(DiscordGuild guild) => guild.Id; - /// - /// placeholder - /// - public static string Name(DiscordGuild guild) => guild.Name; + /// + /// placeholder + /// + public static string Name(DiscordGuild guild) => guild.Name; - /// - /// placeholder - /// - public static string Description(DiscordGuild guild) => guild.Description; + /// + /// placeholder + /// + public static string Description(DiscordGuild guild) => guild.Description; - /// - /// placeholder - /// - public static string Icon(DiscordGuild guild) => guild.IconUrl; + /// + /// placeholder + /// + public static string Icon(DiscordGuild guild) => guild.IconUrl; - /// - /// placeholder - /// - public static string Banner(DiscordGuild guild) => guild.BannerUrl; + /// + /// placeholder + /// + public static string Banner(DiscordGuild guild) => guild.BannerUrl; - /// - /// count placeholder - /// - public static int MemberCount(DiscordGuild guild) => guild.Members.Count; + /// + /// count placeholder + /// + public static int MemberCount(DiscordGuild guild) => guild.Members.Count; - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Guild, new PlaceholderDataKey(nameof(DiscordGuild))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Guild, new PlaceholderDataKey(nameof(DiscordGuild))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, GuildKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); - placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); - placeholders.RegisterPlaceholder(plugin, keys.Description, dataKey, Description); - placeholders.RegisterPlaceholder(plugin, keys.Icon, dataKey, Icon); - placeholders.RegisterPlaceholder(plugin, keys.Banner, dataKey, Banner); - placeholders.RegisterPlaceholder(plugin, keys.MemberCount, dataKey, MemberCount); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, GuildKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); + placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); + placeholders.RegisterPlaceholder(plugin, keys.Description, dataKey, Description); + placeholders.RegisterPlaceholder(plugin, keys.Icon, dataKey, Icon); + placeholders.RegisterPlaceholder(plugin, keys.Banner, dataKey, Banner); + placeholders.RegisterPlaceholder(plugin, keys.MemberCount, dataKey, MemberCount); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/InteractionPlaceholder.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/InteractionPlaceholder.cs index b53ea1ec5..06875a722 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/InteractionPlaceholder.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/InteractionPlaceholder.cs @@ -2,33 +2,32 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class InteractionPlaceholders { /// - /// placeholders + /// placeholder /// - public static class InteractionPlaceholders - { - /// - /// placeholder - /// - public static string Lang(PlaceholderState state, DiscordInteraction interaction) => interaction.GetLangMessage(state.Data.Get(), state.Format); + public static string Lang(PlaceholderState state, DiscordInteraction interaction) => interaction.GetLangMessage(state.Data.Get(), state.Format); - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Interaction, new PlaceholderDataKey(nameof(DiscordInteraction))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Interaction, new PlaceholderDataKey(nameof(DiscordInteraction))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, InteractionKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Lang, dataKey, Lang); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, InteractionKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Lang, dataKey, Lang); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/IpPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/IpPlaceholders.cs index 7e4c8ef6b..41f2c306e 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/IpPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/IpPlaceholders.cs @@ -4,59 +4,58 @@ using Oxide.Ext.Discord.Plugins; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// IP Address Placeholders +/// +public static class IpPlaceholders { + private static readonly Hash FlagCache = new(); + /// - /// IP Address Placeholders + /// IP Country Name placeholder /// - public static class IpPlaceholders - { - private static readonly Hash FlagCache = new Hash(); - - /// - /// IP Country Name placeholder - /// - public static string CountryName(string ip) => DiscordIpData.Instance.GetCountryName(ip); + public static string CountryName(string ip) => DiscordIpData.Instance.GetCountryName(ip); - /// - /// IP Country Code placeholder - /// - public static string CountryCode(string ip) => DiscordIpData.Instance.GetCountryCode(ip); + /// + /// IP Country Code placeholder + /// + public static string CountryCode(string ip) => DiscordIpData.Instance.GetCountryCode(ip); - /// - /// IP Country Emoji placeholder - /// - public static string CountryEmoji(string ip) + /// + /// IP Country Emoji placeholder + /// + public static string CountryEmoji(string ip) + { + string country = CountryCode(ip) ?? string.Empty; + if (FlagCache.TryGetValue(country, out string flag)) { - string country = CountryCode(ip) ?? string.Empty; - if (FlagCache.TryGetValue(country, out string flag)) - { - return flag; - } - - flag = !string.IsNullOrEmpty(country) ? $":flag_{country}:" : DiscordConfig.Instance.Ip.UnknownCountryEmoji; - FlagCache[country] = flag; return flag; } - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Ip, new PlaceholderDataKey("ip")); - } + flag = !string.IsNullOrEmpty(country) ? $":flag_{country}:" : DiscordConfig.Instance.Ip.UnknownCountryEmoji; + FlagCache[country] = flag; + return flag; + } + + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Ip, new PlaceholderDataKey("ip")); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, IpKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Ip, dataKey); - placeholders.RegisterPlaceholder(plugin, keys.CountryName, dataKey, CountryName); - placeholders.RegisterPlaceholder(plugin, keys.CountryCode, dataKey, CountryCode); - placeholders.RegisterPlaceholder(plugin, keys.CountryEmoji, dataKey, CountryEmoji); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, IpKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Ip, dataKey); + placeholders.RegisterPlaceholder(plugin, keys.CountryName, dataKey, CountryName); + placeholders.RegisterPlaceholder(plugin, keys.CountryCode, dataKey, CountryCode); + placeholders.RegisterPlaceholder(plugin, keys.CountryEmoji, dataKey, CountryEmoji); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/MemberPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/MemberPlaceholders.cs index 6e5ab8c87..2b1016c8e 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/MemberPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/MemberPlaceholders.cs @@ -2,45 +2,44 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class MemberPlaceholders { /// - /// placeholders + /// placeholder /// - public static class MemberPlaceholders - { - /// - /// placeholder - /// - public static Snowflake Id(GuildMember member) => member.Id; + public static Snowflake Id(GuildMember member) => member.Id; - /// - /// placeholder - /// - public static string Name(GuildMember member) => member.DisplayName; + /// + /// placeholder + /// + public static string Name(GuildMember member) => member.DisplayName; - /// - /// placeholder - /// - public static string Mention(GuildMember member) => member.User.Mention; + /// + /// placeholder + /// + public static string Mention(GuildMember member) => member.User.Mention; - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Member, new PlaceholderDataKey(nameof(GuildMember))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Member, new PlaceholderDataKey(nameof(GuildMember))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, MemberKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); - placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); - placeholders.RegisterPlaceholder(plugin, keys.Mention, dataKey, Mention); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, MemberKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); + placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); + placeholders.RegisterPlaceholder(plugin, keys.Mention, dataKey, Mention); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/MessagePlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/MessagePlaceholders.cs index 417ebf0f3..84956d0ad 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/MessagePlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/MessagePlaceholders.cs @@ -2,45 +2,44 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class MessagePlaceholders { /// - /// placeholders + /// placeholder /// - public static class MessagePlaceholders - { - /// - /// placeholder - /// - public static Snowflake Id(PlaceholderState state, DiscordMessage message) => message.Id; + public static Snowflake Id(PlaceholderState state, DiscordMessage message) => message.Id; - /// - /// placeholder - /// - public static Snowflake ChannelId(PlaceholderState state, DiscordMessage message) => message.ChannelId; + /// + /// placeholder + /// + public static Snowflake ChannelId(PlaceholderState state, DiscordMessage message) => message.ChannelId; - /// - /// placeholder - /// - public static string Content(PlaceholderState state, DiscordMessage message) => message.Content; + /// + /// placeholder + /// + public static string Content(PlaceholderState state, DiscordMessage message) => message.Content; - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Message, new PlaceholderDataKey(nameof(DiscordMessage))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Message, new PlaceholderDataKey(nameof(DiscordMessage))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, MessageKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); - placeholders.RegisterPlaceholder(plugin, keys.ChannelId, dataKey, ChannelId); - placeholders.RegisterPlaceholder(plugin, keys.Content, dataKey, Content); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, MessageKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); + placeholders.RegisterPlaceholder(plugin, keys.ChannelId, dataKey, ChannelId); + placeholders.RegisterPlaceholder(plugin, keys.Content, dataKey, Content); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/PlayerPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/PlayerPlaceholders.cs index 908b770e1..eafadea49 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/PlayerPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/PlayerPlaceholders.cs @@ -6,179 +6,174 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class PlayerPlaceholders { + internal static readonly PlaceholderDataKey TargetPlayerKey = new("TargetPlayer"); + /// - /// placeholders + /// placeholder /// - public static class PlayerPlaceholders - { - internal static readonly PlaceholderDataKey TargetPlayerKey = new PlaceholderDataKey("TargetPlayer"); - - /// - /// placeholder - /// - public static string Id(IPlayer player) => player.Id; + public static string Id(IPlayer player) => player.Id; - /// - /// placeholder - /// - public static string Name(PlaceholderState state, IPlayer player) + /// + /// placeholder + /// + public static string Name(PlaceholderState state, IPlayer player) + { + string format = state.Format; + if (string.IsNullOrEmpty(format) || !Enum.TryParse(format, true, out PlayerDisplayNameMode mode)) { - string format = state.Format; - if (string.IsNullOrEmpty(format) || !Enum.TryParse(format, true, out PlayerDisplayNameMode mode)) - { - return player.Name; - } - - switch (mode) - { - case PlayerDisplayNameMode.Clan: - return PlayerNameFormatter.ClanName.Format(player); - case PlayerDisplayNameMode.PlayerId: - return PlayerNameFormatter.PlayerId.Format(player); - case PlayerDisplayNameMode.All: - return PlayerNameFormatter.All.Format(player); - default: - return PlayerNameFormatter.Default.Format(player); - } + return player.Name; } - /// - /// placeholder - /// - public static bool Connected(IPlayer player) => player.IsConnected; + return mode switch + { + PlayerDisplayNameMode.Clan => PlayerNameFormatter.ClanName.Format(player), + PlayerDisplayNameMode.PlayerId => PlayerNameFormatter.PlayerId.Format(player), + PlayerDisplayNameMode.All => PlayerNameFormatter.All.Format(player), + _ => PlayerNameFormatter.Default.Format(player) + }; + } + + /// + /// placeholder + /// + public static bool Connected(IPlayer player) => player.IsConnected; - /// - /// placeholder - /// - public static float Health(IPlayer player) => player.Object != null ? player.Health : 0; + /// + /// placeholder + /// + public static float Health(IPlayer player) => player.Object != null ? player.Health : 0; - /// - /// placeholder - /// - public static float MaxHealth(IPlayer player) => player.Object != null ? player.MaxHealth : 0; + /// + /// placeholder + /// + public static float MaxHealth(IPlayer player) => player.Object != null ? player.MaxHealth : 0; - /// - /// placeholder - /// - public static GenericPosition Position(IPlayer player) => player.Object != null ? player.Position() : new GenericPosition(); + /// + /// placeholder + /// + public static GenericPosition Position(IPlayer player) => player.Object != null ? player.Position() : new GenericPosition(); - /// - /// placeholder - /// - public static int Ping(IPlayer player) => player.Ping; + /// + /// placeholder + /// + public static int Ping(IPlayer player) => player.Ping; - /// - /// Player Permissions Placeholder - /// - public static string[] Permissions(IPlayer player) => OxideLibrary.Instance.Permission.GetUserPermissions(player.Id); + /// + /// Player Permissions Placeholder + /// + public static string[] Permissions(IPlayer player) => OxideLibrary.Instance.Permission.GetUserPermissions(player.Id); - /// - /// Player Groups Placeholder - /// - /// - /// - public static string[] Groups(IPlayer player) => OxideLibrary.Instance.Permission.GetUserGroups(player.Id); + /// + /// Player Groups Placeholder + /// + /// + /// + public static string[] Groups(IPlayer player) => OxideLibrary.Instance.Permission.GetUserGroups(player.Id); - /// - /// Player Address Placeholder - /// - /// - /// - public static string Address(IPlayer player) => player.Address; + /// + /// Player Address Placeholder + /// + /// + /// + public static string Address(IPlayer player) => player.Address; - /// - /// Player Country Name Placeholder - /// - /// - /// - public static string CountryName(IPlayer player) => IpPlaceholders.CountryName(player.Address); + /// + /// Player Country Name Placeholder + /// + /// + /// + public static string CountryName(IPlayer player) => IpPlaceholders.CountryName(player.Address); - /// - /// Player Country Name Placeholder - /// - /// - /// - public static string CountryCode(IPlayer player) => IpPlaceholders.CountryCode(player.Address); + /// + /// Player Country Name Placeholder + /// + /// + /// + public static string CountryCode(IPlayer player) => IpPlaceholders.CountryCode(player.Address); - /// - /// Player Flag Placeholder - /// - /// - /// - public static string CountryEmoji(IPlayer player) => IpPlaceholders.CountryEmoji(player.Address); + /// + /// Player Flag Placeholder + /// + /// + /// + public static string CountryEmoji(IPlayer player) => IpPlaceholders.CountryEmoji(player.Address); - /// - /// Player Groups Placeholder - /// - /// - /// - public static string ClanTag(IPlayer player) => DiscordExtensionCore.Instance.GetClanTag(player); + /// + /// Player Groups Placeholder + /// + /// + /// + public static string ClanTag(IPlayer player) => DiscordExtensionCore.Instance.GetClanTag(player); - /// - /// Steam Profile Url Placeholder - /// - public static string SteamProfileUrl(IPlayer player) => $"https://steamcommunity.com/profiles/{player.Id}"; + /// + /// Steam Profile Url Placeholder + /// + public static string SteamProfileUrl(IPlayer player) => $"https://steamcommunity.com/profiles/{player.Id}"; - /// - /// Steam Avatar Url Placeholder - /// - public static string SteamAvatarUrl(IPlayer player) => DiscordExtensionCore.Instance.GetPlayerAvatarUrl(player.Id); + /// + /// Steam Avatar Url Placeholder + /// + public static string SteamAvatarUrl(IPlayer player) => DiscordExtensionCore.Instance.GetPlayerAvatarUrl(player.Id); - /// - /// Battle metrics Steam ID Url Placeholder - /// - public static string BattleMetricsSteamIdUrl(IPlayer player) => $"https://www.battlemetrics.com/rcon/players?filter[search]={player.Id}"; + /// + /// Battle metrics Steam ID Url Placeholder + /// + public static string BattleMetricsSteamIdUrl(IPlayer player) => $"https://www.battlemetrics.com/rcon/players?filter[search]={player.Id}"; - /// - /// Battle metrics Place Name Url Placeholder - /// - public static string BattleMetricsNameUrl(IPlayer player) => $"https://www.battlemetrics.com/rcon/players?filter[search]={player.Name}"; - /// - /// Battle metrics Place Name Url Placeholder - /// - public static string ServerArmorUrl(IPlayer player) => $"https://io.serverarmour.com/profile/{player.Id}"; + /// + /// Battle metrics Place Name Url Placeholder + /// + public static string BattleMetricsNameUrl(IPlayer player) => $"https://www.battlemetrics.com/rcon/players?filter[search]={player.Name}"; + /// + /// Battle metrics Place Name Url Placeholder + /// + public static string ServerArmorUrl(IPlayer player) => $"https://io.serverarmour.com/profile/{player.Id}"; - /// - /// placeholder - /// - public static bool IsLinked(PlaceholderState state, IPlayer player) => player.IsLinked(); + /// + /// placeholder + /// + public static bool IsLinked(PlaceholderState state, IPlayer player) => player.IsLinked(); - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Player, new PlaceholderDataKey(nameof(IPlayer))); - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.PlayerTarget, TargetPlayerKey); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Player, new PlaceholderDataKey(nameof(IPlayer))); + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.PlayerTarget, TargetPlayerKey); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, PlayerKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); - placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); - placeholders.RegisterPlaceholder(plugin, keys.Connected, dataKey, Connected); - placeholders.RegisterPlaceholder(plugin, keys.Permissions, dataKey, Permissions); - placeholders.RegisterPlaceholder(plugin, keys.Groups, dataKey, Groups); - placeholders.RegisterPlaceholder(plugin, keys.Health, dataKey, Health); - placeholders.RegisterPlaceholder(plugin, keys.MaxHealth, dataKey, MaxHealth); - placeholders.RegisterPlaceholder(plugin, keys.Position, dataKey, Position); - placeholders.RegisterPlaceholder(plugin, keys.Ping, dataKey, Ping); - placeholders.RegisterPlaceholder(plugin, keys.Address, dataKey, CountryName); - placeholders.RegisterPlaceholder(plugin, keys.Country, dataKey, CountryCode); - placeholders.RegisterPlaceholder(plugin, keys.CountryEmoji, dataKey, CountryEmoji); - placeholders.RegisterPlaceholder(plugin, keys.ClanTag, dataKey, ClanTag); - placeholders.RegisterPlaceholder(plugin, keys.SteamProfile, dataKey, SteamProfileUrl); - placeholders.RegisterPlaceholder(plugin, keys.SteamAvatar, dataKey, SteamAvatarUrl); - placeholders.RegisterPlaceholder(plugin, keys.BattleMetricsPlayerId, dataKey, BattleMetricsSteamIdUrl); - placeholders.RegisterPlaceholder(plugin, keys.BattleMetricsName, dataKey, BattleMetricsNameUrl); - placeholders.RegisterPlaceholder(plugin, keys.ServerArmorProfile, dataKey, ServerArmorUrl); - placeholders.RegisterPlaceholder(plugin, keys.IsLinked, dataKey, IsLinked); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, PlayerKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); + placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); + placeholders.RegisterPlaceholder(plugin, keys.Connected, dataKey, Connected); + placeholders.RegisterPlaceholder(plugin, keys.Permissions, dataKey, Permissions); + placeholders.RegisterPlaceholder(plugin, keys.Groups, dataKey, Groups); + placeholders.RegisterPlaceholder(plugin, keys.Health, dataKey, Health); + placeholders.RegisterPlaceholder(plugin, keys.MaxHealth, dataKey, MaxHealth); + placeholders.RegisterPlaceholder(plugin, keys.Position, dataKey, Position); + placeholders.RegisterPlaceholder(plugin, keys.Ping, dataKey, Ping); + placeholders.RegisterPlaceholder(plugin, keys.Address, dataKey, CountryName); + placeholders.RegisterPlaceholder(plugin, keys.Country, dataKey, CountryCode); + placeholders.RegisterPlaceholder(plugin, keys.CountryEmoji, dataKey, CountryEmoji); + placeholders.RegisterPlaceholder(plugin, keys.ClanTag, dataKey, ClanTag); + placeholders.RegisterPlaceholder(plugin, keys.SteamProfile, dataKey, SteamProfileUrl); + placeholders.RegisterPlaceholder(plugin, keys.SteamAvatar, dataKey, SteamAvatarUrl); + placeholders.RegisterPlaceholder(plugin, keys.BattleMetricsPlayerId, dataKey, BattleMetricsSteamIdUrl); + placeholders.RegisterPlaceholder(plugin, keys.BattleMetricsName, dataKey, BattleMetricsNameUrl); + placeholders.RegisterPlaceholder(plugin, keys.ServerArmorProfile, dataKey, ServerArmorUrl); + placeholders.RegisterPlaceholder(plugin, keys.IsLinked, dataKey, IsLinked); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/PluginPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/PluginPlaceholders.cs index 5ef6df67e..9a5011b96 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/PluginPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/PluginPlaceholders.cs @@ -5,81 +5,80 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class PluginPlaceholders { /// - /// placeholders + /// placeholder /// - public static class PluginPlaceholders - { - /// - /// placeholder - /// - public static string Name(Plugin plugin) => plugin.Name; + public static string Name(Plugin plugin) => plugin.Name; - /// - /// placeholder - /// - public static string Title(Plugin plugin) => plugin.Title; + /// + /// placeholder + /// + public static string Title(Plugin plugin) => plugin.Title; - /// - /// placeholder - /// - public static string Author(Plugin plugin) => plugin.Author; + /// + /// placeholder + /// + public static string Author(Plugin plugin) => plugin.Author; - /// - /// placeholder - /// - public static string Version(Plugin plugin) => plugin.Version.ToString(); + /// + /// placeholder + /// + public static string Version(Plugin plugin) => plugin.Version.ToString(); - /// - /// placeholder - /// - public static string Description(Plugin plugin) => plugin.Description; + /// + /// placeholder + /// + public static string Description(Plugin plugin) => plugin.Description; - /// - /// placeholder - /// - public static string FullName(Plugin plugin) => plugin.FullName(); + /// + /// placeholder + /// + public static string FullName(Plugin plugin) => plugin.FullName(); - /// - /// placeholder - /// + /// + /// placeholder + /// - public static TimeSpan HookTime(Plugin plugin) => + public static TimeSpan HookTime(Plugin plugin) => #if CARBON plugin.TotalHookTime; #else - TimeSpan.FromSeconds(plugin.TotalHookTime); + TimeSpan.FromSeconds(plugin.TotalHookTime); #endif - /// - /// Lang message for a plugin - /// - public static string LangMessage(PlaceholderState state, Plugin plugin) => OxideLibrary.Instance.Lang.GetMessage(state.Format, plugin, state.Data.Get()?.Id); + /// + /// Lang message for a plugin + /// + public static string LangMessage(PlaceholderState state, Plugin plugin) => OxideLibrary.Instance.Lang.GetMessage(state.Format, plugin, state.Data.Get()?.Id); - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Plugin, new PlaceholderDataKey(nameof(Plugin))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Plugin, new PlaceholderDataKey(nameof(Plugin))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, PluginKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); - placeholders.RegisterPlaceholder(plugin, keys.Title, dataKey, Title); - placeholders.RegisterPlaceholder(plugin, keys.Author, dataKey, Author); - placeholders.RegisterPlaceholder(plugin, keys.Version, dataKey, Version); - placeholders.RegisterPlaceholder(plugin, keys.Description, dataKey, Description); - placeholders.RegisterPlaceholder(plugin, keys.Fullname, dataKey, FullName); - placeholders.RegisterPlaceholder(plugin, keys.HookTime, dataKey, HookTime); - placeholders.RegisterPlaceholder(plugin, keys.Lang, dataKey, LangMessage); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, PluginKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); + placeholders.RegisterPlaceholder(plugin, keys.Title, dataKey, Title); + placeholders.RegisterPlaceholder(plugin, keys.Author, dataKey, Author); + placeholders.RegisterPlaceholder(plugin, keys.Version, dataKey, Version); + placeholders.RegisterPlaceholder(plugin, keys.Description, dataKey, Description); + placeholders.RegisterPlaceholder(plugin, keys.Fullname, dataKey, FullName); + placeholders.RegisterPlaceholder(plugin, keys.HookTime, dataKey, HookTime); + placeholders.RegisterPlaceholder(plugin, keys.Lang, dataKey, LangMessage); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/ResponseErrorPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/ResponseErrorPlaceholders.cs index fc26b53fc..c3abc90a2 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/ResponseErrorPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/ResponseErrorPlaceholders.cs @@ -2,39 +2,38 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class ResponseErrorPlaceholders { /// - /// placeholders + /// placeholder /// - public static class ResponseErrorPlaceholders - { - /// - /// placeholder - /// - public static DiscordHttpStatusCode HttpCode(ResponseError error) => error.HttpStatusCode; + public static DiscordHttpStatusCode HttpCode(ResponseError error) => error.HttpStatusCode; - /// - /// placeholder - /// - public static string Message(ResponseError error) => error.DiscordError?.Message ?? error.ResponseMessage; + /// + /// placeholder + /// + public static string Message(ResponseError error) => error.DiscordError?.Message ?? error.ResponseMessage; - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.ResponseError, new PlaceholderDataKey(nameof(ResponseError))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.ResponseError, new PlaceholderDataKey(nameof(ResponseError))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, ResponseErrorKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Code, dataKey, HttpCode); - placeholders.RegisterPlaceholder(plugin, keys.Message, dataKey, Message); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, ResponseErrorKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Code, dataKey, HttpCode); + placeholders.RegisterPlaceholder(plugin, keys.Message, dataKey, Message); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/RolePlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/RolePlaceholders.cs index b18e7f79f..87224ff46 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/RolePlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/RolePlaceholders.cs @@ -2,51 +2,50 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class RolePlaceholders { /// - /// placeholders + /// placeholder /// - public static class RolePlaceholders - { - /// - /// placeholder - /// - public static Snowflake Id(DiscordRole role) => role.Id; + public static Snowflake Id(DiscordRole role) => role.Id; - /// - /// placeholder - /// - public static string Name(DiscordRole role) => role.Name; + /// + /// placeholder + /// + public static string Name(DiscordRole role) => role.Name; - /// - /// placeholder - /// - public static string Mention(DiscordRole role) => role.Mention; + /// + /// placeholder + /// + public static string Mention(DiscordRole role) => role.Mention; - /// - /// placeholder - /// - public static string Icon(DiscordRole role) => role.Icon; + /// + /// placeholder + /// + public static string Icon(DiscordRole role) => role.Icon; - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Role, new PlaceholderDataKey(nameof(DiscordRole))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Role, new PlaceholderDataKey(nameof(DiscordRole))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, RoleKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); - placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); - placeholders.RegisterPlaceholder(plugin, keys.Mention, dataKey, Mention); - placeholders.RegisterPlaceholder(plugin, keys.Icon, dataKey, Icon); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, RoleKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); + placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); + placeholders.RegisterPlaceholder(plugin, keys.Mention, dataKey, Mention); + placeholders.RegisterPlaceholder(plugin, keys.Icon, dataKey, Icon); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/ServerPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/ServerPlaceholders.cs index f5be02df5..a278ad1b7 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/ServerPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/ServerPlaceholders.cs @@ -6,81 +6,80 @@ using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class ServerPlaceholders { /// - /// placeholders + /// placeholder /// - public static class ServerPlaceholders - { - /// - /// placeholder - /// - public static string Name(IServer server) => server.Name; + public static string Name(IServer server) => server.Name; - /// - /// placeholder - /// - public static int Players(IServer server) => server.Players; + /// + /// placeholder + /// + public static int Players(IServer server) => server.Players; - /// - /// placeholder - /// - public static int MaxPlayers(IServer server) => server.MaxPlayers; + /// + /// placeholder + /// + public static int MaxPlayers(IServer server) => server.MaxPlayers; - /// - /// placeholder - /// - public static int TotalPlayers(IServer server) => OxideLibrary.Instance.Covalence.Players.All.Count(); + /// + /// placeholder + /// + public static int TotalPlayers(IServer server) => OxideLibrary.Instance.Covalence.Players.All.Count(); - /// - /// placeholder - /// - public static string Version(IServer server) => server.Version; + /// + /// placeholder + /// + public static string Version(IServer server) => server.Version; - /// - /// placeholder - /// - public static string Protocol(IServer server) => server.Protocol; + /// + /// placeholder + /// + public static string Protocol(IServer server) => server.Protocol; - /// - /// placeholder - /// - public static IPAddress Address(IServer server) => server.Address; + /// + /// placeholder + /// + public static IPAddress Address(IServer server) => server.Address; - /// - /// placeholder - /// - public static ushort Port(IServer server) => server.Port; + /// + /// placeholder + /// + public static ushort Port(IServer server) => server.Port; - /// - /// placeholder - /// - public static DateTime Time(IServer server) => server.Time; + /// + /// placeholder + /// + public static DateTime Time(IServer server) => server.Time; - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Server, new PlaceholderDataKey(nameof(IServer))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Server, new PlaceholderDataKey(nameof(IServer))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, ServerKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); - placeholders.RegisterPlaceholder(plugin, keys.Players, dataKey, Players); - placeholders.RegisterPlaceholder(plugin, keys.MaxPlayers, dataKey, MaxPlayers); - placeholders.RegisterPlaceholder(plugin, keys.TotalPlayers, dataKey, TotalPlayers); - placeholders.RegisterPlaceholder(plugin, keys.Version, dataKey, Version); - placeholders.RegisterPlaceholder(plugin, keys.Protocol, dataKey, Protocol); - placeholders.RegisterPlaceholder(plugin, keys.Address, dataKey, Address); - placeholders.RegisterPlaceholder(plugin, keys.Port, dataKey, Port); - placeholders.RegisterPlaceholder(plugin, keys.Time, dataKey, Time); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, ServerKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Name, dataKey, Name); + placeholders.RegisterPlaceholder(plugin, keys.Players, dataKey, Players); + placeholders.RegisterPlaceholder(plugin, keys.MaxPlayers, dataKey, MaxPlayers); + placeholders.RegisterPlaceholder(plugin, keys.TotalPlayers, dataKey, TotalPlayers); + placeholders.RegisterPlaceholder(plugin, keys.Version, dataKey, Version); + placeholders.RegisterPlaceholder(plugin, keys.Protocol, dataKey, Protocol); + placeholders.RegisterPlaceholder(plugin, keys.Address, dataKey, Address); + placeholders.RegisterPlaceholder(plugin, keys.Port, dataKey, Port); + placeholders.RegisterPlaceholder(plugin, keys.Time, dataKey, Time); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/SnowflakePlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/SnowflakePlaceholders.cs index ff469e0bf..4a10d0984 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/SnowflakePlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/SnowflakePlaceholders.cs @@ -3,34 +3,33 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class SnowflakePlaceholders { /// - /// placeholders + /// placeholder /// - public static class SnowflakePlaceholders - { - /// - /// placeholder - /// - public static DateTimeOffset Created(Snowflake id) => id.GetCreationDate(); + public static DateTimeOffset Created(Snowflake id) => id.GetCreationDate(); - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Snowflake, new PlaceholderDataKey(nameof(Snowflake))); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Snowflake, new PlaceholderDataKey(nameof(Snowflake))); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, SnowflakeKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey); - placeholders.RegisterPlaceholder(plugin, keys.Created, dataKey, Created); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, SnowflakeKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey); + placeholders.RegisterPlaceholder(plugin, keys.Created, dataKey, Created); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/TimespanPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/TimespanPlaceholders.cs index e2a812e7b..702948a0b 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/TimespanPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/TimespanPlaceholders.cs @@ -1,133 +1,134 @@ using System; -using System.Text; using Oxide.Core.Plugins; using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Plugins; +using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class TimeSpanPlaceholders { + internal static readonly PlaceholderDataKey TimeSpanKey = new("timespan"); + /// - /// placeholders + /// placeholder /// - public static class TimeSpanPlaceholders - { - internal static readonly PlaceholderDataKey TimeSpanKey = new PlaceholderDataKey("timespan"); - - /// - /// placeholder - /// - public static int Days(TimeSpan time) => time.Days; + public static int Days(TimeSpan time) => time.Days; - /// - /// Formats Timespan into a text string placeholder - /// Text is localized if used with DiscordInteraction or IPlayer - /// Ex: 1 days 2 hours 3 minutes 4 seconds - /// Ex: 2 hour 0 minutes 53 seconds - /// - public static string Formatted(PlaceholderState state, TimeSpan time) + /// + /// Formats Timespan into a text string placeholder + /// Text is localized if used with DiscordInteraction or IPlayer + /// Ex: 1 days 2 hours 3 minutes 4 seconds + /// Ex: 2 hour 0 minutes 53 seconds + /// + public static string Formatted(PlaceholderState state, TimeSpan time) + { + DiscordInteraction interaction = state.Data.Get(); + if (time < TimeSpan.Zero) { - DiscordInteraction interaction = state.Data.Get(); - if (time < TimeSpan.Zero) - { - return interaction.GetLangMessage(DiscordExtensionCore.Instance, LangKeys.TimeSpan.Infinity); - } + return interaction?.GetLangMessage(DiscordExtensionCore.Instance, LangKeys.TimeSpan.Infinity) ?? DiscordLocales.Instance.GetLangMessage(DiscordExtensionCore.Instance, null, LangKeys.TimeSpan.Infinity); + } - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); + ValueStringBuilder sb = new(); - AppendTime(interaction, sb, time.TotalDays, time.Days, LangKeys.TimeSpan.Day, LangKeys.TimeSpan.Days); - AppendTime(interaction, sb, time.TotalHours, time.Hours, LangKeys.TimeSpan.Hour, LangKeys.TimeSpan.Hours); - AppendTime(interaction, sb, time.TotalMinutes, time.Minutes, LangKeys.TimeSpan.Minute, LangKeys.TimeSpan.Minutes); - AppendTime(interaction, sb, time.TotalSeconds, time.Seconds, LangKeys.TimeSpan.Second, LangKeys.TimeSpan.Seconds); + AppendTime(interaction, sb, time.TotalDays, time.Days, LangKeys.TimeSpan.Day, LangKeys.TimeSpan.Days); + AppendTime(interaction, sb, time.TotalHours, time.Hours, LangKeys.TimeSpan.Hour, LangKeys.TimeSpan.Hours); + AppendTime(interaction, sb, time.TotalMinutes, time.Minutes, LangKeys.TimeSpan.Minute, LangKeys.TimeSpan.Minutes); + AppendTime(interaction, sb, time.TotalSeconds, time.Seconds, LangKeys.TimeSpan.Second, LangKeys.TimeSpan.Seconds); - return DiscordPool.Internal.ToStringAndFree(sb); - } + return sb.ToString(); + } - private static void AppendTime(DiscordInteraction interaction, StringBuilder sb, double total, int value, string singular, string plural) + private static void AppendTime(DiscordInteraction interaction, ValueStringBuilder sb, double total, int value, string singular, string plural) + { + if (total >= 1) { - if (total >= 1) + if (sb.Length != 0) { - if (sb.Length != 0) - { - sb.Append(' '); - } - - sb.Append(value.ToString()); sb.Append(' '); - sb.Append(interaction.GetLangMessage(DiscordExtensionCore.Instance, value == 1 ? singular : plural)); } + + string langKey = value == 1 ? singular : plural; + + sb.Append(value.ToString()); + sb.Append(' '); + sb.Append(interaction?.GetLangMessage(DiscordExtensionCore.Instance, langKey) ?? DiscordLocales.Instance.GetLangMessage(DiscordExtensionCore.Instance, null, langKey)); } + } - /// - /// placeholder - /// - public static int Hours(TimeSpan time) => time.Hours; + /// + /// placeholder + /// + public static int Hours(TimeSpan time) => time.Hours; - /// - /// placeholder - /// - public static int Minutes(TimeSpan time) => time.Minutes; + /// + /// placeholder + /// + public static int Minutes(TimeSpan time) => time.Minutes; - /// - /// placeholder - /// - public static int Seconds(TimeSpan time) => time.Seconds; + /// + /// placeholder + /// + public static int Seconds(TimeSpan time) => time.Seconds; - /// - /// placeholder - /// - public static int Milliseconds(TimeSpan time) => time.Milliseconds; + /// + /// placeholder + /// + public static int Milliseconds(TimeSpan time) => time.Milliseconds; - /// - /// placeholder - /// - public static double TotalDays(TimeSpan time) => time.TotalDays; + /// + /// placeholder + /// + public static double TotalDays(TimeSpan time) => time.TotalDays; - /// - /// placeholder - /// - public static double TotalHours(TimeSpan time) => time.TotalHours; + /// + /// placeholder + /// + public static double TotalHours(TimeSpan time) => time.TotalHours; - /// - /// placeholder - /// - public static double TotalMinutes(TimeSpan time) => time.TotalMinutes; + /// + /// placeholder + /// + public static double TotalMinutes(TimeSpan time) => time.TotalMinutes; - /// - /// placeholder - /// - public static double TotalSeconds(TimeSpan time) => time.TotalSeconds; + /// + /// placeholder + /// + public static double TotalSeconds(TimeSpan time) => time.TotalSeconds; - /// - /// placeholder - /// - public static double TotalMilliseconds(TimeSpan time) => time.TotalMilliseconds; + /// + /// placeholder + /// + public static double TotalMilliseconds(TimeSpan time) => time.TotalMilliseconds; - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Timespan, TimeSpanKey); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Timespan, TimeSpanKey); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, TimespanKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Time, dataKey); - placeholders.RegisterPlaceholder(plugin, keys.Formatted, dataKey, Formatted); - placeholders.RegisterPlaceholder(plugin, keys.Days, dataKey, Days); - placeholders.RegisterPlaceholder(plugin, keys.Hours, dataKey, Hours); - placeholders.RegisterPlaceholder(plugin, keys.Minutes, dataKey, Minutes); - placeholders.RegisterPlaceholder(plugin, keys.Seconds, dataKey, Seconds); - placeholders.RegisterPlaceholder(plugin, keys.Milliseconds, dataKey, Milliseconds); - placeholders.RegisterPlaceholder(plugin, keys.TotalDays, dataKey, TotalDays); - placeholders.RegisterPlaceholder(plugin, keys.TotalHours, dataKey, TotalHours); - placeholders.RegisterPlaceholder(plugin, keys.TotalMinutes, dataKey, TotalMinutes); - placeholders.RegisterPlaceholder(plugin, keys.TotalSeconds, dataKey, TotalSeconds); - placeholders.RegisterPlaceholder(plugin, keys.TotalMilliseconds, dataKey, TotalMilliseconds); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, TimespanKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Time, dataKey); + placeholders.RegisterPlaceholder(plugin, keys.Formatted, dataKey, Formatted); + placeholders.RegisterPlaceholder(plugin, keys.Days, dataKey, Days); + placeholders.RegisterPlaceholder(plugin, keys.Hours, dataKey, Hours); + placeholders.RegisterPlaceholder(plugin, keys.Minutes, dataKey, Minutes); + placeholders.RegisterPlaceholder(plugin, keys.Seconds, dataKey, Seconds); + placeholders.RegisterPlaceholder(plugin, keys.Milliseconds, dataKey, Milliseconds); + placeholders.RegisterPlaceholder(plugin, keys.TotalDays, dataKey, TotalDays); + placeholders.RegisterPlaceholder(plugin, keys.TotalHours, dataKey, TotalHours); + placeholders.RegisterPlaceholder(plugin, keys.TotalMinutes, dataKey, TotalMinutes); + placeholders.RegisterPlaceholder(plugin, keys.TotalSeconds, dataKey, TotalSeconds); + placeholders.RegisterPlaceholder(plugin, keys.TotalMilliseconds, dataKey, TotalMilliseconds); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/TimestampPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/TimestampPlaceholders.cs index 2e58d94a7..0dfd1afd0 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/TimestampPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/TimestampPlaceholders.cs @@ -3,91 +3,90 @@ using Oxide.Ext.Discord.Helpers; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Timestamp placeholders +/// +public static class TimestampPlaceholders { + internal static readonly PlaceholderDataKey TimestampKey = new("Timestamp"); + /// - /// Timestamp placeholders + /// placeholder /// - public static class TimestampPlaceholders - { - internal static readonly PlaceholderDataKey TimestampKey = new PlaceholderDataKey("Timestamp"); - - /// - /// placeholder - /// - public static string Timestamp(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp); + public static string Timestamp(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp); - /// - /// placeholder - /// - public static string ShortTime(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.ShortTime); + /// + /// placeholder + /// + public static string ShortTime(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.ShortTime); - /// - /// placeholder - /// - public static string Longtime(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.LongTime); + /// + /// placeholder + /// + public static string Longtime(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.LongTime); - /// - /// placeholder - /// - public static string ShortDate(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.ShortDate); + /// + /// placeholder + /// + public static string ShortDate(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.ShortDate); - /// - /// placeholder - /// - public static string LongDate(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.LongDate); + /// + /// placeholder + /// + public static string LongDate(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.LongDate); - /// - /// placeholder - /// - public static string ShortDateTime(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp); + /// + /// placeholder + /// + public static string ShortDateTime(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp); - /// - /// placeholder - /// - public static string LongDateTime(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.LongDateTime); + /// + /// placeholder + /// + public static string LongDateTime(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.LongDateTime); - /// - /// placeholder - /// - public static string RelativeTime(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.RelativeTime); + /// + /// placeholder + /// + public static string RelativeTime(long timestamp) => DiscordFormatting.UnixTimestamp(timestamp, TimestampStyles.RelativeTime); - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Timestamp, TimestampKey); - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.TimestampNow); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Timestamp, TimestampKey); + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.TimestampNow); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, TimestampKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Time, dataKey, Timestamp); - placeholders.RegisterPlaceholder(plugin, keys.ShortTime, dataKey, ShortTime); - placeholders.RegisterPlaceholder(plugin, keys.LongTime, dataKey, Longtime); - placeholders.RegisterPlaceholder(plugin, keys.ShortDate, dataKey, ShortDate); - placeholders.RegisterPlaceholder(plugin, keys.LongDate, dataKey, LongDate); - placeholders.RegisterPlaceholder(plugin, keys.ShortDateTime, dataKey, ShortDateTime); - placeholders.RegisterPlaceholder(plugin, keys.LongDateTime, dataKey, LongDateTime); - placeholders.RegisterPlaceholder(plugin, keys.RelativeTime, dataKey, RelativeTime); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, TimestampKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Time, dataKey, Timestamp); + placeholders.RegisterPlaceholder(plugin, keys.ShortTime, dataKey, ShortTime); + placeholders.RegisterPlaceholder(plugin, keys.LongTime, dataKey, Longtime); + placeholders.RegisterPlaceholder(plugin, keys.ShortDate, dataKey, ShortDate); + placeholders.RegisterPlaceholder(plugin, keys.LongDate, dataKey, LongDate); + placeholders.RegisterPlaceholder(plugin, keys.ShortDateTime, dataKey, ShortDateTime); + placeholders.RegisterPlaceholder(plugin, keys.LongDateTime, dataKey, LongDateTime); + placeholders.RegisterPlaceholder(plugin, keys.RelativeTime, dataKey, RelativeTime); + } - private static void RegisterPlaceholders(Plugin plugin, TimestampKeys keys) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Time, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow)); - placeholders.RegisterPlaceholder(plugin, keys.ShortTime, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.ShortTime)); - placeholders.RegisterPlaceholder(plugin, keys.LongTime, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.LongTime)); - placeholders.RegisterPlaceholder(plugin, keys.ShortDate, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.ShortDate)); - placeholders.RegisterPlaceholder(plugin, keys.LongDate, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.LongDate)); - placeholders.RegisterPlaceholder(plugin, keys.ShortDateTime, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.ShortDateTime)); - placeholders.RegisterPlaceholder(plugin, keys.LongDateTime, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.LongDateTime)); - placeholders.RegisterPlaceholder(plugin, keys.RelativeTime, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.RelativeTime)); - } + private static void RegisterPlaceholders(Plugin plugin, TimestampKeys keys) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Time, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow)); + placeholders.RegisterPlaceholder(plugin, keys.ShortTime, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.ShortTime)); + placeholders.RegisterPlaceholder(plugin, keys.LongTime, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.LongTime)); + placeholders.RegisterPlaceholder(plugin, keys.ShortDate, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.ShortDate)); + placeholders.RegisterPlaceholder(plugin, keys.LongDate, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.LongDate)); + placeholders.RegisterPlaceholder(plugin, keys.ShortDateTime, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.ShortDateTime)); + placeholders.RegisterPlaceholder(plugin, keys.LongDateTime, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.LongDateTime)); + placeholders.RegisterPlaceholder(plugin, keys.RelativeTime, () => DiscordFormatting.UnixTimestamp(DateTimeOffset.UtcNow, TimestampStyles.RelativeTime)); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Default/UserPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Default/UserPlaceholders.cs index b1830b6fb..4888cd12d 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Default/UserPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Default/UserPlaceholders.cs @@ -3,80 +3,79 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// placeholders +/// +public static class UserPlaceholders { + internal static readonly PlaceholderDataKey TargetUserKey = new("TargetUser"); + internal static readonly PlaceholderDataKey BotUserKey = new("BotUser"); + /// - /// placeholders + /// placeholder /// - public static class UserPlaceholders - { - internal static readonly PlaceholderDataKey TargetUserKey = new PlaceholderDataKey("TargetUser"); - internal static readonly PlaceholderDataKey BotUserKey = new PlaceholderDataKey("BotUser"); + public static Snowflake Id(DiscordUser user) => user.Id; - /// - /// placeholder - /// - public static Snowflake Id(DiscordUser user) => user.Id; - - /// - /// placeholder - /// - public static string UserName(DiscordUser user) => user.Username; + /// + /// placeholder + /// + public static string UserName(DiscordUser user) => user.Username; - /// - /// placeholder - /// - public static string Discriminator(DiscordUser user) => user.Discriminator; + /// + /// placeholder + /// + public static string Discriminator(DiscordUser user) => user.Discriminator; - /// - /// placeholder - /// - public static string FullName(DiscordUser user) => user.FullUserName; + /// + /// placeholder + /// + public static string FullName(DiscordUser user) => user.FullUserName; - /// - /// placeholder - /// - public static string AvatarUrl(DiscordUser user) => user.GetAvatarUrl; + /// + /// placeholder + /// + public static string AvatarUrl(DiscordUser user) => user.GetAvatarUrl; - /// - /// placeholder - /// - public static string BannerUrl(DiscordUser user) => user.GetBannerUrl; + /// + /// placeholder + /// + public static string BannerUrl(DiscordUser user) => user.GetBannerUrl; - /// - /// placeholder - /// - public static string Mention(DiscordUser user) => user.Mention; + /// + /// placeholder + /// + public static string Mention(DiscordUser user) => user.Mention; - /// - /// placeholder - /// - public static bool IsLinked(DiscordUser user) => user.IsLinked(); + /// + /// placeholder + /// + public static bool IsLinked(DiscordUser user) => user.IsLinked(); - internal static void RegisterPlaceholders() - { - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.User, new PlaceholderDataKey(nameof(DiscordUser))); - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.UserTarget, TargetUserKey); - RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Bot, BotUserKey); - } + internal static void RegisterPlaceholders() + { + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.User, new PlaceholderDataKey(nameof(DiscordUser))); + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.UserTarget, TargetUserKey); + RegisterPlaceholders(DiscordExtensionCore.Instance, DefaultKeys.Bot, BotUserKey); + } - /// - /// Registers placeholders for the given plugin. - /// - /// Plugin to register placeholders for - /// Prefix to use for the placeholders - /// Data key in - public static void RegisterPlaceholders(Plugin plugin, UserKeys keys, PlaceholderDataKey dataKey) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); - placeholders.RegisterPlaceholder(plugin, keys.Username, dataKey, UserName); - placeholders.RegisterPlaceholder(plugin, keys.Discriminator, dataKey, Discriminator); - placeholders.RegisterPlaceholder(plugin, keys.Fullname, dataKey, FullName); - placeholders.RegisterPlaceholder(plugin, keys.AvatarUrl, dataKey, AvatarUrl); - placeholders.RegisterPlaceholder(plugin, keys.BannerUrl, dataKey, BannerUrl); - placeholders.RegisterPlaceholder(plugin, keys.Mention, dataKey, Mention); - placeholders.RegisterPlaceholder(plugin, keys.IsLinked, dataKey, IsLinked); - } + /// + /// Registers placeholders for the given plugin. + /// + /// Plugin to register placeholders for + /// Prefix to use for the placeholders + /// Data key in + public static void RegisterPlaceholders(Plugin plugin, UserKeys keys, PlaceholderDataKey dataKey) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + placeholders.RegisterPlaceholder(plugin, keys.Id, dataKey, Id); + placeholders.RegisterPlaceholder(plugin, keys.Username, dataKey, UserName); + placeholders.RegisterPlaceholder(plugin, keys.Discriminator, dataKey, Discriminator); + placeholders.RegisterPlaceholder(plugin, keys.Fullname, dataKey, FullName); + placeholders.RegisterPlaceholder(plugin, keys.AvatarUrl, dataKey, AvatarUrl); + placeholders.RegisterPlaceholder(plugin, keys.BannerUrl, dataKey, BannerUrl); + placeholders.RegisterPlaceholder(plugin, keys.Mention, dataKey, Mention); + placeholders.RegisterPlaceholder(plugin, keys.IsLinked, dataKey, IsLinked); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/DiscordPlaceholders.cs b/Oxide.Ext.Discord/Libraries/Placeholders/DiscordPlaceholders.cs index 3056e09fc..c3ffb44f8 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/DiscordPlaceholders.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/DiscordPlaceholders.cs @@ -14,341 +14,340 @@ using Oxide.Ext.Discord.Plugins; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Discord Placeholders Library +/// +public class DiscordPlaceholders : BaseDiscordLibrary { + private readonly Regex _placeholderRegex = new("""{([^\d][^:{}"]+)(?::([^{}"]+))*?}""", RegexOptions.Compiled, TimeSpan.FromSeconds(1)); + private readonly Hash _placeholders = new(); + private readonly Hash _internalPlaceholders = new(); + private readonly ILogger _logger; + + internal DiscordPlaceholders(ILogger logger) + { + _logger = logger; + } + + internal void RegisterPlaceholders() + { + ChannelPlaceholders.RegisterPlaceholders(); + DateTimePlaceholders.RegisterPlaceholders(); + GuildPlaceholders.RegisterPlaceholders(); + InteractionPlaceholders.RegisterPlaceholders(); + IpPlaceholders.RegisterPlaceholders(); + ServerPlaceholders.RegisterPlaceholders(); + MemberPlaceholders.RegisterPlaceholders(); + MessagePlaceholders.RegisterPlaceholders(); + PlayerPlaceholders.RegisterPlaceholders(); + PluginPlaceholders.RegisterPlaceholders(); + RolePlaceholders.RegisterPlaceholders(); + TimestampPlaceholders.RegisterPlaceholders(); + UserPlaceholders.RegisterPlaceholders(); + ApplicationCommandPlaceholders.RegisterPlaceholders(); + ResponseErrorPlaceholders.RegisterPlaceholders(); + SnowflakePlaceholders.RegisterPlaceholders(); + TimeSpanPlaceholders.RegisterPlaceholders(); + } + + internal IEnumerable> GetPlaceholders() + { + return _placeholders; + } + /// - /// Discord Placeholders Library + /// Returns true if the text contains placeholders /// - public class DiscordPlaceholders : BaseDiscordLibrary + /// Text to check for placeholders + /// + public bool HasPlaceholders(string text) { - private readonly Regex _placeholderRegex = new Regex(@"{([^\d][^:{}""]+)(?::([^{}""]+))*?}", RegexOptions.Compiled, TimeSpan.FromSeconds(1)); - private readonly Hash _placeholders = new Hash(); - private readonly Hash _internalPlaceholders = new Hash(); - private readonly ILogger _logger; + if (string.IsNullOrEmpty(text)) + { + return false; + } + + MatchCollection matches = _placeholderRegex.Matches(text); + return matches.Count != 0; + } - internal DiscordPlaceholders(ILogger logger) + /// + /// Returns placeholders found in the given text + /// + /// Text to get placeholders for + /// + public IEnumerable GetPlaceholders(string text) + { + if (string.IsNullOrEmpty(text)) { - _logger = logger; + yield break; } - - internal void RegisterPlaceholders() + + MatchCollection matches = _placeholderRegex.Matches(text); + foreach (Match match in matches) { - ChannelPlaceholders.RegisterPlaceholders(); - DateTimePlaceholders.RegisterPlaceholders(); - GuildPlaceholders.RegisterPlaceholders(); - InteractionPlaceholders.RegisterPlaceholders(); - IpPlaceholders.RegisterPlaceholders(); - ServerPlaceholders.RegisterPlaceholders(); - MemberPlaceholders.RegisterPlaceholders(); - MessagePlaceholders.RegisterPlaceholders(); - PlayerPlaceholders.RegisterPlaceholders(); - PluginPlaceholders.RegisterPlaceholders(); - RolePlaceholders.RegisterPlaceholders(); - TimestampPlaceholders.RegisterPlaceholders(); - UserPlaceholders.RegisterPlaceholders(); - ApplicationCommandPlaceholders.RegisterPlaceholders(); - ResponseErrorPlaceholders.RegisterPlaceholders(); - SnowflakePlaceholders.RegisterPlaceholders(); - TimeSpanPlaceholders.RegisterPlaceholders(); + yield return match.Groups[1].Value; } + } - internal IEnumerable> GetPlaceholders() + /// + /// Process placeholders for the given text. + /// + /// Text to process placeholders for + /// Placeholder Data for the placeholders + /// String with placeholders replaced. If no placeholders are found, the original string is returned + public string ProcessPlaceholders(string text, PlaceholderData data) + { + if (data == null) { - return _placeholders; + return text; } - - /// - /// Returns true if the text contains placeholders - /// - /// Text to check for placeholders - /// - public bool HasPlaceholders(string text) - { - if (string.IsNullOrEmpty(text)) - { - return false; - } - MatchCollection matches = _placeholderRegex.Matches(text); - return matches.Count != 0; - } - - /// - /// Returns placeholders found in the given text - /// - /// Text to get placeholders for - /// - public IEnumerable GetPlaceholders(string text) + if (string.IsNullOrEmpty(text)) { - if (string.IsNullOrEmpty(text)) - { - yield break; - } - - MatchCollection matches = _placeholderRegex.Matches(text); - foreach (Match match in matches) - { - yield return match.Groups[1].Value; - } + data.AutoDispose(); + return text; } - - /// - /// Process placeholders for the given text. - /// - /// Text to process placeholders for - /// Placeholder Data for the placeholders - /// string with placeholders replaced. If no placeholders are found the original string is returned - public string ProcessPlaceholders(string text, PlaceholderData data) - { - if (data == null) - { - return text; - } - if (string.IsNullOrEmpty(text)) - { - data.AutoDispose(); - return text; - } - - if (data == null) throw new ArgumentNullException(nameof(data)); + if (data == null) throw new ArgumentNullException(nameof(data)); - MatchCollection matches = _placeholderRegex.Matches(text); - if (matches.Count != 0) + MatchCollection matches = _placeholderRegex.Matches(text); + if (matches.Count != 0) + { + StringBuilder builder = DiscordPool.Internal.GetStringBuilder(); + builder.Append(text); + PlaceholderState state = PlaceholderState.Create(data); + bool hasNonMatchingPlaceholder = false; + for (int index = matches.Count - 1; index >= 0; index--) { - StringBuilder builder = DiscordPool.Internal.GetStringBuilder(); - builder.Append(text); - PlaceholderState state = PlaceholderState.Create(data); - bool hasNonMatchingPlaceholder = false; - for (int index = matches.Count - 1; index >= 0; index--) + Match match = matches[index]; + state.UpdateState(match); + IPlaceholder placeholder = _placeholders[state.Key]; + if (placeholder == null) { - Match match = matches[index]; - state.UpdateState(match); - IPlaceholder placeholder = _placeholders[state.Key]; - if (placeholder == null) - { - hasNonMatchingPlaceholder = true; - continue; - } - - placeholder.Invoke(builder, state); + hasNonMatchingPlaceholder = true; + continue; } - if (hasNonMatchingPlaceholder) - { - DiscordExtensionCore.Instance.GetReplacer()?.Invoke(data.Get(), builder, true); - } - - text = DiscordPool.Internal.ToStringAndFree(builder); - state.Dispose(); + placeholder.Invoke(builder, state); } - data.AutoDispose(); - - return text; + if (hasNonMatchingPlaceholder) + { + DiscordExtensionCore.Instance.GetReplacer()?.Invoke(data.Get(), builder, true); + } + + text = DiscordPool.Internal.ToStringAndFree(builder); + state.Dispose(); } - /// - /// Returns a pooled for the given plugin. - /// If you wish to manually pool call the method. - /// If you wish to clone call the method. - /// - /// - public PlaceholderData CreateData(Plugin plugin) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + data.AutoDispose(); + + return text; + } + + /// + /// Returns a pooled for the given plugin. + /// If you wish to manually pool call the method. + /// If you wish to clone call the method. + /// + /// + public PlaceholderData CreateData(Plugin plugin) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - PlaceholderData data = DiscordPool.Instance.GetOrCreate(plugin).GetPlaceholderData(); - data.AddServer(OxideLibrary.Instance.Covalence.Server); - data.AddPlugin(plugin); + PlaceholderData data = DiscordPool.Instance.GetOrCreate(plugin).GetPlaceholderData(); + data.AddServer(OxideLibrary.Instance.Covalence.Server); + data.AddPlugin(plugin); - DiscordUser bot = DiscordClientFactory.Instance.GetClient(plugin)?.Bot?.BotUser; - if (bot != null) - { - data.AddBotUser(bot); - } - - return data; + DiscordUser bot = DiscordClientFactory.Instance.GetClient(plugin)?.Bot?.BotUser; + if (bot != null) + { + data.AddBotUser(bot); } - /// - /// Registers a placeholder static value placeholder. - /// Static placeholder value can not be changed. - /// - /// Plugin this placeholder is for - /// Placeholder key - /// Static string value - /// - public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, string value) - { - InvalidPlaceholderException.ThrowIfInvalid(key); - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (value == null) throw new ArgumentNullException(nameof(value)); + return data; + } + + /// + /// Registers a placeholder static value placeholder. + /// Static placeholder value can not be changed. + /// + /// Plugin this placeholder is for + /// Placeholder key + /// Static string value + /// + public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, string value) + { + InvalidPlaceholderException.ThrowIfInvalid(key); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (value == null) throw new ArgumentNullException(nameof(value)); - StaticPlaceholder holder = new StaticPlaceholder(plugin, value); - IPlaceholder existing = _placeholders[key]; - if (existing != null && !existing.IsExtensionPlaceholder && !existing.IsForPlugin(plugin)) - { - _logger.Warning("Plugin {0} has replaced placeholder '{1}' previously registered by plugin {2}", plugin.FullName(), key.Placeholder, existing.PluginName); - } - _placeholders[key] = holder; + StaticPlaceholder holder = new(plugin, value); + IPlaceholder existing = _placeholders[key]; + if (existing is {IsExtensionPlaceholder: false} && !existing.IsForPlugin(plugin)) + { + _logger.Warning("Plugin {0} has replaced placeholder '{1}' previously registered by plugin {2}", plugin.FullName(), key.Placeholder, existing.PluginName); } + _placeholders[key] = holder; + } - /// - /// Registers a placeholder that will call the callback function when the placeholder is called. - /// This function will return TResult data for the placeholder - /// - /// Plugin this placeholder is for - /// Placeholder key - /// Callback Method for the placeholder - /// - public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, Func callback) - { - InvalidPlaceholderException.ThrowIfInvalid(key); - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (callback == null) throw new ArgumentNullException(nameof(callback)); - - Placeholder holder = new Placeholder(plugin, callback); - IPlaceholder existing = _placeholders[key]; - if (existing != null && !existing.IsExtensionPlaceholder && !existing.IsForPlugin(plugin)) - { - _logger.Warning("Plugin {0} has replaced placeholder '{1}' previously registered by plugin {2}", plugin.FullName(), key.Placeholder, existing.PluginName); - } + /// + /// Registers a placeholder that will call the callback function when the placeholder is called. + /// This function will return TResult data for the placeholder + /// + /// Plugin this placeholder is for + /// Placeholder key + /// Callback Method for the placeholder + /// + public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, Func callback) + { + InvalidPlaceholderException.ThrowIfInvalid(key); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (callback == null) throw new ArgumentNullException(nameof(callback)); - _placeholders[key] = holder; - } - - /// - /// Registers a placeholder that will take a datakey from and use that as the placeholder value - /// - /// Plugin this placeholder is for - /// Placeholder key - /// - /// Type that is registered in the PlaceholderData - /// Thrown if placeholder or plugin is null - public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, PlaceholderDataKey dataKey) + Placeholder holder = new(plugin, callback); + IPlaceholder existing = _placeholders[key]; + if (existing is {IsExtensionPlaceholder: false} && !existing.IsForPlugin(plugin)) { - InvalidPlaceholderException.ThrowIfInvalid(key); - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + _logger.Warning("Plugin {0} has replaced placeholder '{1}' previously registered by plugin {2}", plugin.FullName(), key.Placeholder, existing.PluginName); + } + + _placeholders[key] = holder; + } - Placeholder holder = new Placeholder(dataKey, plugin, data => data); - if (!holder.IsExtensionPlaceholder && !_internalPlaceholders.ContainsKey(key) && !key.Placeholder.StartsWith(plugin.Name, StringComparison.OrdinalIgnoreCase)) - { - _logger.Error("Plugin placeholder {0} must be prefixed with the plugin name {1} unless overriding a Discord Extension provided placeholder.", key.Placeholder, plugin.Name.ToLower()); - return; - } + /// + /// Registers a placeholder that will take a datakey from and use that as the placeholder value + /// + /// Plugin this placeholder is for + /// Placeholder key + /// + /// Type that is registered in the PlaceholderData + /// Thrown if placeholder or plugin is null + public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, PlaceholderDataKey dataKey) + { + InvalidPlaceholderException.ThrowIfInvalid(key); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - _placeholders[key] = holder; - if (holder.IsExtensionPlaceholder) - { - _internalPlaceholders[key] = holder; - } + Placeholder holder = new(dataKey, plugin, data => data); + if (!holder.IsExtensionPlaceholder && !_internalPlaceholders.ContainsKey(key) && !key.Placeholder.StartsWith(plugin.Name, StringComparison.OrdinalIgnoreCase)) + { + _logger.Error("Plugin placeholder {0} must be prefixed with the plugin name {1} unless overriding a Discord Extension provided placeholder.", key.Placeholder, plugin.Name.ToLower()); + return; } - /// - /// Registers a placeholder that will pull type T from . The datakey for TData will be the typeof(TData).Name - /// TData will be passed into the callback function and will expect a TResult to be returned from that function. - /// - /// Plugin this placeholder is for - /// Placeholder key - /// Callback Method for the placeholder - /// Type of the data key - /// The return type of the placeholder callback - /// - public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, Func callback) + _placeholders[key] = holder; + if (holder.IsExtensionPlaceholder) { - RegisterPlaceholder(plugin, key, new PlaceholderDataKey(typeof(TData).Name), callback); + _internalPlaceholders[key] = holder; } + } + + /// + /// Registers a placeholder that will pull type T from . The datakey for TData will be the typeof(TData).Name + /// TData will be passed into the callback function and will expect a TResult to be returned from that function. + /// + /// Plugin this placeholder is for + /// Placeholder key + /// Callback Method for the placeholder + /// Type of the data key + /// The return type of the placeholder callback + /// + public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, Func callback) + { + RegisterPlaceholder(plugin, key, new PlaceholderDataKey(typeof(TData).Name), callback); + } - /// - /// Registers a placeholder that will pull type T from . The datakey for T will come from the datakey argument - /// Type T will be passed into the callback function and will expect a TResult to be returned from that function. - /// - /// Plugin this placeholder is for - /// Placeholder Key - /// The name of the data key in PlaceholderData - /// Callback Method for the placeholder - /// Type of the data key - /// The return type of the placeholder callback - /// - public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, PlaceholderDataKey dataKey, Func callback) - { - InvalidPlaceholderException.ThrowIfInvalid(key); - if (!dataKey.IsValid) throw new ArgumentNullException(nameof(dataKey)); - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (callback == null) throw new ArgumentNullException(nameof(callback)); + /// + /// Registers a placeholder that will pull type T from . The datakey for T will come from the datakey argument + /// Type T will be passed into the callback function and will expect a TResult to be returned from that function. + /// + /// Plugin this placeholder is for + /// Placeholder Key + /// The name of the data key in PlaceholderData + /// Callback Method for the placeholder + /// Type of the data key + /// The return type of the placeholder callback + /// + public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, PlaceholderDataKey dataKey, Func callback) + { + InvalidPlaceholderException.ThrowIfInvalid(key); + if (!dataKey.IsValid) throw new ArgumentNullException(nameof(dataKey)); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (callback == null) throw new ArgumentNullException(nameof(callback)); - Placeholder holder = new Placeholder(dataKey, plugin, callback); - if (!holder.IsExtensionPlaceholder && !_internalPlaceholders.ContainsKey(key) && !key.Placeholder.StartsWith(plugin.Name, StringComparison.OrdinalIgnoreCase)) - { - _logger.Error("Plugin placeholder {0} must be prefixed with the plugin name {1} unless overriding a Discord Extension provided placeholder.", key.Placeholder, plugin.Name.ToLower()); - return; - } - - _placeholders[key] = holder; - if (holder.IsExtensionPlaceholder) - { - _internalPlaceholders[key] = holder; - } + Placeholder holder = new(dataKey, plugin, callback); + if (!holder.IsExtensionPlaceholder && !_internalPlaceholders.ContainsKey(key) && !key.Placeholder.StartsWith(plugin.Name, StringComparison.OrdinalIgnoreCase)) + { + _logger.Error("Plugin placeholder {0} must be prefixed with the plugin name {1} unless overriding a Discord Extension provided placeholder.", key.Placeholder, plugin.Name.ToLower()); + return; } - - /// - /// Registers a placeholder that will pull type T from . The datakey for T will be the T.GetType().Name - /// Type T will be passed into the callback function along with the current and will expect a TResult to be returned from that function. - /// - /// Plugin this placeholder is for - /// Placeholder key - /// Callback Method for the placeholder - /// Type of the data key - /// The return type of the placeholder callback - /// - public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, Func callback) + + _placeholders[key] = holder; + if (holder.IsExtensionPlaceholder) { - RegisterPlaceholder(plugin, key, new PlaceholderDataKey(typeof(TData).Name), callback); + _internalPlaceholders[key] = holder; } + } - /// - /// Registers a placeholder that will pull type T from . The datakey for T will come from the datakey argument - /// Type T will be passed into the callback function along with the current and will expect a TResult to be returned from that function. - /// - /// Plugin this placeholder is for - /// Placeholder key - /// The name of the data key in PlaceholderData - /// Callback Method for the placeholder - /// Type of the data key - /// The return type of the placeholder callback - /// - public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, PlaceholderDataKey dataKey, Func callback) - { - InvalidPlaceholderException.ThrowIfInvalid(key); - if (!dataKey.IsValid) throw new ArgumentNullException(nameof(dataKey)); - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (callback == null) throw new ArgumentNullException(nameof(callback)); + /// + /// Registers a placeholder that will pull type T from . The datakey for T will be the T.GetType().Name + /// Type T will be passed into the callback function along with the current and will expect a TResult to be returned from that function. + /// + /// Plugin this placeholder is for + /// Placeholder key + /// Callback Method for the placeholder + /// Type of the data key + /// The return type of the placeholder callback + /// + public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, Func callback) + { + RegisterPlaceholder(plugin, key, new PlaceholderDataKey(typeof(TData).Name), callback); + } + + /// + /// Registers a placeholder that will pull type T from . The datakey for T will come from the datakey argument + /// Type T will be passed into the callback function along with the current and will expect a TResult to be returned from that function. + /// + /// Plugin this placeholder is for + /// Placeholder key + /// The name of the data key in PlaceholderData + /// Callback Method for the placeholder + /// Type of the data key + /// The return type of the placeholder callback + /// + public void RegisterPlaceholder(Plugin plugin, PlaceholderKey key, PlaceholderDataKey dataKey, Func callback) + { + InvalidPlaceholderException.ThrowIfInvalid(key); + if (!dataKey.IsValid) throw new ArgumentNullException(nameof(dataKey)); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (callback == null) throw new ArgumentNullException(nameof(callback)); - Placeholder holder = new Placeholder(dataKey, plugin, callback); - if (!holder.IsExtensionPlaceholder && !_internalPlaceholders.ContainsKey(key) && !key.Placeholder.StartsWith(plugin.Name, StringComparison.OrdinalIgnoreCase)) - { - _logger.Error("Plugin placeholder {0} must be prefixed with the plugin name {1} unless overriding a Discord Extension provided placeholder.", key.Placeholder, plugin.Name.ToLower()); - return; - } + Placeholder holder = new(dataKey, plugin, callback); + if (!holder.IsExtensionPlaceholder && !_internalPlaceholders.ContainsKey(key) && !key.Placeholder.StartsWith(plugin.Name, StringComparison.OrdinalIgnoreCase)) + { + _logger.Error("Plugin placeholder {0} must be prefixed with the plugin name {1} unless overriding a Discord Extension provided placeholder.", key.Placeholder, plugin.Name.ToLower()); + return; + } - _placeholders[key] = holder; - if (holder.IsExtensionPlaceholder) - { - _internalPlaceholders[key] = holder; - } + _placeholders[key] = holder; + if (holder.IsExtensionPlaceholder) + { + _internalPlaceholders[key] = holder; } + } - /// - protected override void OnPluginUnloaded(Plugin plugin) + /// + protected override void OnPluginUnloaded(Plugin plugin) + { + _placeholders.RemoveAll(p => p.IsForPlugin(plugin)); + foreach (KeyValuePair placeholder in _internalPlaceholders) { - _placeholders.RemoveAll(p => p.IsForPlugin(plugin)); - foreach (KeyValuePair placeholder in _internalPlaceholders) + if (!_placeholders.ContainsKey(placeholder.Key)) { - if (!_placeholders.ContainsKey(placeholder.Key)) - { - _placeholders[placeholder.Key] = placeholder.Value; - } + _placeholders[placeholder.Key] = placeholder.Value; } } } diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/AppCommandKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/AppCommandKeys.cs index 2ae478d15..a618ab2d1 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/AppCommandKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/AppCommandKeys.cs @@ -1,42 +1,41 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class AppCommandKeys { /// - /// Placeholder Keys for + /// for /// - public class AppCommandKeys - { - /// - /// for - /// - public readonly PlaceholderKey Id; + public readonly PlaceholderKey Id; - /// - /// for - /// - public readonly PlaceholderKey Name; + /// + /// for + /// + public readonly PlaceholderKey Name; - /// - /// for - /// - public readonly PlaceholderKey Mention; + /// + /// for + /// + public readonly PlaceholderKey Mention; - /// - /// for - /// - public readonly PlaceholderKey MentionCustom; + /// + /// for + /// + public readonly PlaceholderKey MentionCustom; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public AppCommandKeys(string prefix) - { - Id = new PlaceholderKey(prefix, "id"); - Name = new PlaceholderKey(prefix, "name"); - Mention = new PlaceholderKey(prefix, "mention"); - MentionCustom = new PlaceholderKey(prefix, "custom"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public AppCommandKeys(string prefix) + { + Id = new PlaceholderKey(prefix, "id"); + Name = new PlaceholderKey(prefix, "name"); + Mention = new PlaceholderKey(prefix, "mention"); + MentionCustom = new PlaceholderKey(prefix, "custom"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ChannelKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ChannelKeys.cs index 057bbac18..a92c1a083 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ChannelKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ChannelKeys.cs @@ -1,48 +1,47 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class ChannelKeys { /// - /// Placeholder Keys for + /// for /// - public class ChannelKeys - { - /// - /// for - /// - public readonly PlaceholderKey Id; + public readonly PlaceholderKey Id; - /// - /// for - /// - public readonly PlaceholderKey Name; + /// + /// for + /// + public readonly PlaceholderKey Name; - /// - /// for - /// - public readonly PlaceholderKey Icon; + /// + /// for + /// + public readonly PlaceholderKey Icon; - /// - /// for - /// - public readonly PlaceholderKey Topic; + /// + /// for + /// + public readonly PlaceholderKey Topic; - /// - /// for - /// - public readonly PlaceholderKey Mention; + /// + /// for + /// + public readonly PlaceholderKey Mention; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public ChannelKeys(string prefix) - { - Id = new PlaceholderKey(prefix, "id"); - Name = new PlaceholderKey(prefix, "name"); - Icon = new PlaceholderKey(prefix, "icon"); - Topic = new PlaceholderKey(prefix, "topic"); - Mention = new PlaceholderKey(prefix, "mention"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public ChannelKeys(string prefix) + { + Id = new PlaceholderKey(prefix, "id"); + Name = new PlaceholderKey(prefix, "name"); + Icon = new PlaceholderKey(prefix, "icon"); + Topic = new PlaceholderKey(prefix, "topic"); + Mention = new PlaceholderKey(prefix, "mention"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/DateTimeKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/DateTimeKeys.cs index 3ba3b2a46..181795acb 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/DateTimeKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/DateTimeKeys.cs @@ -1,66 +1,65 @@ using System; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class DateTimeKeys { /// - /// Placeholder Keys for + /// for /// - public class DateTimeKeys - { - /// - /// for - /// - public readonly PlaceholderKey Date; + public readonly PlaceholderKey Date; - /// - /// for - /// - public readonly PlaceholderKey Year; + /// + /// for + /// + public readonly PlaceholderKey Year; - /// - /// for - /// - public readonly PlaceholderKey Month; + /// + /// for + /// + public readonly PlaceholderKey Month; - /// - /// for - /// - public readonly PlaceholderKey Day; + /// + /// for + /// + public readonly PlaceholderKey Day; - /// - /// for - /// - public readonly PlaceholderKey Hour; + /// + /// for + /// + public readonly PlaceholderKey Hour; - /// - /// for - /// - public readonly PlaceholderKey Minute; + /// + /// for + /// + public readonly PlaceholderKey Minute; - /// - /// for - /// - public readonly PlaceholderKey Second; + /// + /// for + /// + public readonly PlaceholderKey Second; - /// - /// for - /// - public readonly PlaceholderKey Millisecond; + /// + /// for + /// + public readonly PlaceholderKey Millisecond; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public DateTimeKeys(string prefix) - { - Date = new PlaceholderKey(prefix, "date"); - Year = new PlaceholderKey(prefix, "year"); - Month = new PlaceholderKey(prefix, "month"); - Day = new PlaceholderKey(prefix, "day"); - Hour = new PlaceholderKey(prefix, "hour"); - Minute = new PlaceholderKey(prefix, "minute"); - Second = new PlaceholderKey(prefix, "second"); - Millisecond = new PlaceholderKey(prefix, "millisecond"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public DateTimeKeys(string prefix) + { + Date = new PlaceholderKey(prefix, "date"); + Year = new PlaceholderKey(prefix, "year"); + Month = new PlaceholderKey(prefix, "month"); + Day = new PlaceholderKey(prefix, "day"); + Hour = new PlaceholderKey(prefix, "hour"); + Minute = new PlaceholderKey(prefix, "minute"); + Second = new PlaceholderKey(prefix, "second"); + Millisecond = new PlaceholderKey(prefix, "millisecond"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/DefaultKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/DefaultKeys.cs index 6c104e6f3..86cd405f2 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/DefaultKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/DefaultKeys.cs @@ -2,121 +2,120 @@ using Oxide.Core.Libraries.Covalence; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Default Discord Extension provided Placeholder Keys +/// +public static class DefaultKeys { /// - /// Default Discord Extension provided Placeholder Keys - /// - public static class DefaultKeys - { - /// - /// Placeholder Keys - /// - public static readonly AppCommandKeys AppCommand = new AppCommandKeys("command"); - - /// - /// Placeholder Keys - /// - public static readonly ChannelKeys Channel = new ChannelKeys("channel"); - - /// - /// Placeholder Keys - /// - public static readonly DateTimeKeys DateTime = new DateTimeKeys("datetime"); - - /// - /// Placeholder Keys - /// - public static readonly DateTimeKeys DateTimeNow = new DateTimeKeys("datetime.now"); - - /// - /// Placeholder Keys - /// - public static readonly GuildKeys Guild = new GuildKeys("guild"); - - /// - /// Placeholder Keys - /// - public static readonly InteractionKeys Interaction = new InteractionKeys("interaction"); - - /// - /// IP address placeholders - /// - public static readonly IpKeys Ip = new IpKeys("ip"); - - /// - /// Placeholder Keys - /// - public static readonly MemberKeys Member = new MemberKeys("member"); - - /// - /// Placeholder Keys - /// - public static readonly MessageKeys Message = new MessageKeys("message"); - - /// - /// Placeholder Keys - /// - public static readonly PlayerKeys Player = new PlayerKeys("player"); - - /// - /// Target Placeholder Keys - /// - public static readonly PlayerKeys PlayerTarget = new PlayerKeys("target.player"); - - /// - /// Placeholder Keys - /// - public static readonly PluginKeys Plugin = new PluginKeys("plugin"); - - /// - /// Placeholder Keys - /// - public static readonly ResponseErrorKeys ResponseError = new ResponseErrorKeys("response.error"); - - /// - /// Placeholder Keys - /// - public static readonly RoleKeys Role = new RoleKeys("role"); - - /// - /// Placeholder Keys - /// - public static readonly ServerKeys Server = new ServerKeys("server"); - - /// - /// Placeholder Keys - /// - public static readonly SnowflakeKeys Snowflake = new SnowflakeKeys("snowflake"); - - /// - /// Placeholder Keys - /// - public static readonly TimespanKeys Timespan = new TimespanKeys("timespan"); - - /// - /// Timestamp Placeholder Keys - /// - public static readonly TimestampKeys Timestamp = new TimestampKeys("timestamp"); - - /// - /// Timestamp Now Placeholder Keys - /// - public static readonly TimestampKeys TimestampNow = new TimestampKeys("timestamp.now"); - - /// - /// Placeholder Keys - /// - public static readonly UserKeys User = new UserKeys("user"); - - /// - /// Bot User Placeholder Keys - /// - public static readonly UserKeys Bot = new UserKeys("bot"); - - /// - /// Target Placeholder Keys - /// - public static readonly UserKeys UserTarget = new UserKeys("target.user"); - } + /// Placeholder Keys + /// + public static readonly AppCommandKeys AppCommand = new("command"); + + /// + /// Placeholder Keys + /// + public static readonly ChannelKeys Channel = new("channel"); + + /// + /// Placeholder Keys + /// + public static readonly DateTimeKeys DateTime = new("datetime"); + + /// + /// Placeholder Keys + /// + public static readonly DateTimeKeys DateTimeNow = new("datetime.now"); + + /// + /// Placeholder Keys + /// + public static readonly GuildKeys Guild = new("guild"); + + /// + /// Placeholder Keys + /// + public static readonly InteractionKeys Interaction = new("interaction"); + + /// + /// IP address placeholders + /// + public static readonly IpKeys Ip = new("ip"); + + /// + /// Placeholder Keys + /// + public static readonly MemberKeys Member = new("member"); + + /// + /// Placeholder Keys + /// + public static readonly MessageKeys Message = new("message"); + + /// + /// Placeholder Keys + /// + public static readonly PlayerKeys Player = new("player"); + + /// + /// Target Placeholder Keys + /// + public static readonly PlayerKeys PlayerTarget = new("target.player"); + + /// + /// Placeholder Keys + /// + public static readonly PluginKeys Plugin = new("plugin"); + + /// + /// Placeholder Keys + /// + public static readonly ResponseErrorKeys ResponseError = new("response.error"); + + /// + /// Placeholder Keys + /// + public static readonly RoleKeys Role = new("role"); + + /// + /// Placeholder Keys + /// + public static readonly ServerKeys Server = new("server"); + + /// + /// Placeholder Keys + /// + public static readonly SnowflakeKeys Snowflake = new("snowflake"); + + /// + /// Placeholder Keys + /// + public static readonly TimespanKeys Timespan = new("timespan"); + + /// + /// Timestamp Placeholder Keys + /// + public static readonly TimestampKeys Timestamp = new("timestamp"); + + /// + /// Timestamp Now Placeholder Keys + /// + public static readonly TimestampKeys TimestampNow = new("timestamp.now"); + + /// + /// Placeholder Keys + /// + public static readonly UserKeys User = new("user"); + + /// + /// Bot User Placeholder Keys + /// + public static readonly UserKeys Bot = new("bot"); + + /// + /// Target Placeholder Keys + /// + public static readonly UserKeys UserTarget = new("target.user"); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/GuildKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/GuildKeys.cs index 825679c34..a6de3023d 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/GuildKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/GuildKeys.cs @@ -1,54 +1,53 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class GuildKeys { /// - /// Placeholder Keys for + /// for /// - public class GuildKeys - { - /// - /// for - /// - public readonly PlaceholderKey Id; + public readonly PlaceholderKey Id; - /// - /// for - /// - public readonly PlaceholderKey Name; + /// + /// for + /// + public readonly PlaceholderKey Name; - /// - /// for - /// - public readonly PlaceholderKey Description; + /// + /// for + /// + public readonly PlaceholderKey Description; - /// - /// for - /// - public readonly PlaceholderKey Icon; + /// + /// for + /// + public readonly PlaceholderKey Icon; - /// - /// for - /// - public readonly PlaceholderKey Banner; + /// + /// for + /// + public readonly PlaceholderKey Banner; - /// - /// for - /// - public readonly PlaceholderKey MemberCount; + /// + /// for + /// + public readonly PlaceholderKey MemberCount; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public GuildKeys(string prefix) - { - Id = new PlaceholderKey(prefix, "id"); - Name = new PlaceholderKey(prefix, "name"); - Description = new PlaceholderKey(prefix, "description"); - Icon = new PlaceholderKey(prefix, "icon"); - Banner = new PlaceholderKey(prefix, "banner"); - MemberCount = new PlaceholderKey(prefix, "members.count"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public GuildKeys(string prefix) + { + Id = new PlaceholderKey(prefix, "id"); + Name = new PlaceholderKey(prefix, "name"); + Description = new PlaceholderKey(prefix, "description"); + Icon = new PlaceholderKey(prefix, "icon"); + Banner = new PlaceholderKey(prefix, "banner"); + MemberCount = new PlaceholderKey(prefix, "members.count"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/InteractionKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/InteractionKeys.cs index 3ae81997c..cc195988b 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/InteractionKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/InteractionKeys.cs @@ -1,24 +1,23 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class InteractionKeys { /// - /// Placeholder Keys for + /// for /// - public class InteractionKeys - { - /// - /// for - /// - public readonly PlaceholderKey Lang; + public readonly PlaceholderKey Lang; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public InteractionKeys(string prefix) - { - Lang = new PlaceholderKey(prefix, "lang"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public InteractionKeys(string prefix) + { + Lang = new PlaceholderKey(prefix, "lang"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/IpKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/IpKeys.cs index a03eccb1e..60e8b42bd 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/IpKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/IpKeys.cs @@ -1,40 +1,39 @@ -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class IpKeys { /// - /// Placeholder Keys for + /// IP placeholder /// - public class IpKeys - { - /// - /// IP placeholder - /// - public readonly PlaceholderKey Ip; + public readonly PlaceholderKey Ip; - /// - /// Ip Country Name Placeholder - /// - public readonly PlaceholderKey CountryName; + /// + /// Ip Country Name Placeholder + /// + public readonly PlaceholderKey CountryName; - /// - /// IP Country Code Placeholder - /// - public readonly PlaceholderKey CountryCode; + /// + /// IP Country Code Placeholder + /// + public readonly PlaceholderKey CountryCode; - /// - /// IP Country Emoji Placeholder - /// - public readonly PlaceholderKey CountryEmoji; + /// + /// IP Country Emoji Placeholder + /// + public readonly PlaceholderKey CountryEmoji; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public IpKeys(string prefix) - { - Ip = new PlaceholderKey(prefix, "ip"); - CountryName = new PlaceholderKey(prefix, "country.name"); - CountryCode = new PlaceholderKey(prefix, "country.code"); - CountryEmoji = new PlaceholderKey(prefix, "country.emoji"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public IpKeys(string prefix) + { + Ip = new PlaceholderKey(prefix, "ip"); + CountryName = new PlaceholderKey(prefix, "country.name"); + CountryCode = new PlaceholderKey(prefix, "country.code"); + CountryEmoji = new PlaceholderKey(prefix, "country.emoji"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/MemberKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/MemberKeys.cs index d0cbb83f5..7d9af9b84 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/MemberKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/MemberKeys.cs @@ -1,36 +1,35 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class MemberKeys { /// - /// Placeholder Keys for + /// for /// - public class MemberKeys - { - /// - /// for - /// - public readonly PlaceholderKey Id; + public readonly PlaceholderKey Id; - /// - /// for - /// - public readonly PlaceholderKey Name; + /// + /// for + /// + public readonly PlaceholderKey Name; - /// - /// for - /// - public readonly PlaceholderKey Mention; + /// + /// for + /// + public readonly PlaceholderKey Mention; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public MemberKeys(string prefix) - { - Id = new PlaceholderKey(prefix, "id"); - Name = new PlaceholderKey(prefix, "name"); - Mention = new PlaceholderKey(prefix, "mention"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public MemberKeys(string prefix) + { + Id = new PlaceholderKey(prefix, "id"); + Name = new PlaceholderKey(prefix, "name"); + Mention = new PlaceholderKey(prefix, "mention"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/MessageKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/MessageKeys.cs index 6edadb8f0..d80cddf05 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/MessageKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/MessageKeys.cs @@ -1,36 +1,35 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class MessageKeys { /// - /// Placeholder Keys for + /// for /// - public class MessageKeys - { - /// - /// for - /// - public readonly PlaceholderKey Id; + public readonly PlaceholderKey Id; - /// - /// for - /// - public readonly PlaceholderKey ChannelId; + /// + /// for + /// + public readonly PlaceholderKey ChannelId; - /// - /// for - /// - public readonly PlaceholderKey Content; + /// + /// for + /// + public readonly PlaceholderKey Content; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public MessageKeys(string prefix) - { - Id = new PlaceholderKey(prefix, "id"); - ChannelId = new PlaceholderKey(prefix, "channel.id"); - Content = new PlaceholderKey(prefix, "content"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public MessageKeys(string prefix) + { + Id = new PlaceholderKey(prefix, "id"); + ChannelId = new PlaceholderKey(prefix, "channel.id"); + Content = new PlaceholderKey(prefix, "content"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/PlayerKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/PlayerKeys.cs index 15a893c60..d68f75368 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/PlayerKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/PlayerKeys.cs @@ -1,161 +1,160 @@ using Oxide.Core.Libraries.Covalence; using Oxide.Ext.Discord.Extensions; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class PlayerKeys { /// - /// Placeholder Keys for + /// for + /// + public readonly PlaceholderKey Id; + + /// + /// for + /// + public readonly PlaceholderKey Name; + + /// + /// for with clan formatting + /// + public readonly PlaceholderKey NameClan; + + /// + /// for with Player ID formatting + /// + public readonly PlaceholderKey NamePlayerId; + + /// + /// for with clan and player ID formatting. + /// + public readonly PlaceholderKey NameAll; + + /// + /// for + /// + public readonly PlaceholderKey Connected; + + /// + /// for permissions + /// + public readonly PlaceholderKey Permissions; + + /// + /// for groups + /// + public readonly PlaceholderKey Groups; + + /// + /// for + /// + public readonly PlaceholderKey Health; + + /// + /// for + /// + public readonly PlaceholderKey MaxHealth; + + /// + /// for + /// + public readonly PlaceholderKey Position; + + /// + /// for + /// + public readonly PlaceholderKey Ping; + + /// + /// for + /// + public readonly PlaceholderKey Address; + + /// + /// for Country + /// Requires Placeholder API plugin in order to use + /// + public readonly PlaceholderKey Country; + + /// + /// for Country Code + /// Requires Placeholder API plugin in order to use + /// + public readonly PlaceholderKey CountryCode; + + /// + /// for Country Emoji + /// Requires Placeholder API plugin in order to use + /// + public readonly PlaceholderKey CountryEmoji; + + /// + /// for Clan Tag + /// Requires Clans plugin in order to use + /// + public readonly PlaceholderKey ClanTag; + + /// + /// for Steam Profile + /// + public readonly PlaceholderKey SteamProfile; + + /// + /// for Steam Avatar Image Url + /// + public readonly PlaceholderKey SteamAvatar; + + /// + /// for BattleMetrics search by player id Url + /// + public readonly PlaceholderKey BattleMetricsPlayerId; + + /// + /// for BattleMetrics search by player name Url + /// + public readonly PlaceholderKey BattleMetricsName; + + /// + /// for Server Armor Profile Url + /// + public readonly PlaceholderKey ServerArmorProfile; + + /// + /// for + /// + public readonly PlaceholderKey IsLinked; + + /// + /// Constructor /// - public class PlayerKeys + /// Placeholder Key Prefix + public PlayerKeys(string prefix) { - /// - /// for - /// - public readonly PlaceholderKey Id; - - /// - /// for - /// - public readonly PlaceholderKey Name; - - /// - /// for with clan formatting - /// - public readonly PlaceholderKey NameClan; - - /// - /// for with Player ID formatting - /// - public readonly PlaceholderKey NamePlayerId; - - /// - /// for with clan and player ID formatting. - /// - public readonly PlaceholderKey NameAll; - - /// - /// for - /// - public readonly PlaceholderKey Connected; - - /// - /// for permissions - /// - public readonly PlaceholderKey Permissions; - - /// - /// for groups - /// - public readonly PlaceholderKey Groups; - - /// - /// for - /// - public readonly PlaceholderKey Health; - - /// - /// for - /// - public readonly PlaceholderKey MaxHealth; - - /// - /// for - /// - public readonly PlaceholderKey Position; - - /// - /// for - /// - public readonly PlaceholderKey Ping; - - /// - /// for - /// - public readonly PlaceholderKey Address; - - /// - /// for Country - /// Requires Placeholder API plugin in order to use - /// - public readonly PlaceholderKey Country; - - /// - /// for Country Code - /// Requires Placeholder API plugin in order to use - /// - public readonly PlaceholderKey CountryCode; - - /// - /// for Country Emoji - /// Requires Placeholder API plugin in order to use - /// - public readonly PlaceholderKey CountryEmoji; - - /// - /// for Clan Tag - /// Requires Clans plugin in order to use - /// - public readonly PlaceholderKey ClanTag; - - /// - /// for Steam Profile - /// - public readonly PlaceholderKey SteamProfile; - - /// - /// for Steam Avatar Image Url - /// - public readonly PlaceholderKey SteamAvatar; - - /// - /// for BattleMetrics search by player id Url - /// - public readonly PlaceholderKey BattleMetricsPlayerId; - - /// - /// for BattleMetrics search by player name Url - /// - public readonly PlaceholderKey BattleMetricsName; - - /// - /// for Server Armor Profile Url - /// - public readonly PlaceholderKey ServerArmorProfile; - - /// - /// for - /// - public readonly PlaceholderKey IsLinked; - - /// - /// Constructor - /// - /// Placeholder Key Prefix - public PlayerKeys(string prefix) - { - Id = new PlaceholderKey(prefix, "id"); - Name = new PlaceholderKey(prefix, "name"); - NameClan = new PlaceholderKey(prefix, "name", "clan"); - NamePlayerId = new PlaceholderKey(prefix, "name", "playerid"); - NameAll = new PlaceholderKey(prefix, "name", "all"); - Connected = new PlaceholderKey(prefix, "connected"); - Permissions = new PlaceholderKey(prefix, "permissions"); - Groups = new PlaceholderKey(prefix, "groups"); - Health = new PlaceholderKey(prefix, "health"); - MaxHealth = new PlaceholderKey(prefix, "health.max"); - Position = new PlaceholderKey(prefix, "position"); - Ping = new PlaceholderKey(prefix, "ping"); - Address = new PlaceholderKey(prefix, "address"); - Country = new PlaceholderKey(prefix, "country"); - CountryCode = new PlaceholderKey(prefix, "country.code"); - CountryEmoji = new PlaceholderKey(prefix, "country.emoji"); - ClanTag = new PlaceholderKey(prefix, "clan.tag"); - SteamProfile = new PlaceholderKey(prefix, "steam.profile"); - SteamAvatar = new PlaceholderKey(prefix, "steam.avatar"); - BattleMetricsPlayerId = new PlaceholderKey(prefix, "battlemetrics.steamid"); - BattleMetricsName = new PlaceholderKey(prefix, "battlemetrics.name"); - ServerArmorProfile = new PlaceholderKey(prefix, "serverarmor.profile"); - IsLinked = new PlaceholderKey(prefix, "islinked"); - } + Id = new PlaceholderKey(prefix, "id"); + Name = new PlaceholderKey(prefix, "name"); + NameClan = new PlaceholderKey(prefix, "name", "clan"); + NamePlayerId = new PlaceholderKey(prefix, "name", "playerid"); + NameAll = new PlaceholderKey(prefix, "name", "all"); + Connected = new PlaceholderKey(prefix, "connected"); + Permissions = new PlaceholderKey(prefix, "permissions"); + Groups = new PlaceholderKey(prefix, "groups"); + Health = new PlaceholderKey(prefix, "health"); + MaxHealth = new PlaceholderKey(prefix, "health.max"); + Position = new PlaceholderKey(prefix, "position"); + Ping = new PlaceholderKey(prefix, "ping"); + Address = new PlaceholderKey(prefix, "address"); + Country = new PlaceholderKey(prefix, "country"); + CountryCode = new PlaceholderKey(prefix, "country.code"); + CountryEmoji = new PlaceholderKey(prefix, "country.emoji"); + ClanTag = new PlaceholderKey(prefix, "clan.tag"); + SteamProfile = new PlaceholderKey(prefix, "steam.profile"); + SteamAvatar = new PlaceholderKey(prefix, "steam.avatar"); + BattleMetricsPlayerId = new PlaceholderKey(prefix, "battlemetrics.steamid"); + BattleMetricsName = new PlaceholderKey(prefix, "battlemetrics.name"); + ServerArmorProfile = new PlaceholderKey(prefix, "serverarmor.profile"); + IsLinked = new PlaceholderKey(prefix, "islinked"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/PluginKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/PluginKeys.cs index 3f0b4dd2e..5cdbceb65 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/PluginKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/PluginKeys.cs @@ -1,67 +1,66 @@ using Oxide.Core.Plugins; using Oxide.Ext.Discord.Extensions; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class PluginKeys { /// - /// Placeholder Keys for + /// for /// - public class PluginKeys - { - /// - /// for - /// - public readonly PlaceholderKey Name; + public readonly PlaceholderKey Name; - /// - /// for - /// - public readonly PlaceholderKey Title; + /// + /// for + /// + public readonly PlaceholderKey Title; - /// - /// for - /// - public readonly PlaceholderKey Author; + /// + /// for + /// + public readonly PlaceholderKey Author; - /// - /// for - /// - public readonly PlaceholderKey Version; + /// + /// for + /// + public readonly PlaceholderKey Version; - /// - /// for - /// - public readonly PlaceholderKey Description; + /// + /// for + /// + public readonly PlaceholderKey Description; - /// - /// for - /// - public readonly PlaceholderKey Fullname; + /// + /// for + /// + public readonly PlaceholderKey Fullname; - /// - /// for - /// - public readonly PlaceholderKey HookTime; + /// + /// for + /// + public readonly PlaceholderKey HookTime; - /// - /// for - /// - public readonly PlaceholderKey Lang; + /// + /// for + /// + public readonly PlaceholderKey Lang; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public PluginKeys(string prefix) - { - Name = new PlaceholderKey(prefix, "name"); - Title = new PlaceholderKey(prefix, "title"); - Author = new PlaceholderKey(prefix, "author"); - Version = new PlaceholderKey(prefix, "version"); - Description = new PlaceholderKey(prefix, "description"); - Fullname = new PlaceholderKey(prefix, "fullname"); - HookTime = new PlaceholderKey(prefix, "hooktime"); - Lang = new PlaceholderKey(prefix, "lang"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public PluginKeys(string prefix) + { + Name = new PlaceholderKey(prefix, "name"); + Title = new PlaceholderKey(prefix, "title"); + Author = new PlaceholderKey(prefix, "author"); + Version = new PlaceholderKey(prefix, "version"); + Description = new PlaceholderKey(prefix, "description"); + Fullname = new PlaceholderKey(prefix, "fullname"); + HookTime = new PlaceholderKey(prefix, "hooktime"); + Lang = new PlaceholderKey(prefix, "lang"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ResponseErrorKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ResponseErrorKeys.cs index 025fa4d70..46d7a8fc0 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ResponseErrorKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ResponseErrorKeys.cs @@ -1,30 +1,29 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class ResponseErrorKeys { /// - /// Placeholder Keys for + /// for /// - public class ResponseErrorKeys - { - /// - /// for - /// - public readonly PlaceholderKey Code; + public readonly PlaceholderKey Code; - /// - /// for - /// - public readonly PlaceholderKey Message; + /// + /// for + /// + public readonly PlaceholderKey Message; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public ResponseErrorKeys(string prefix) - { - Code = new PlaceholderKey(prefix, "code"); - Message = new PlaceholderKey(prefix, "message"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public ResponseErrorKeys(string prefix) + { + Code = new PlaceholderKey(prefix, "code"); + Message = new PlaceholderKey(prefix, "message"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/RoleKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/RoleKeys.cs index 4a5c1503f..72842d1a0 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/RoleKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/RoleKeys.cs @@ -1,42 +1,41 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class RoleKeys { /// - /// Placeholder Keys for + /// for /// - public class RoleKeys - { - /// - /// for - /// - public readonly PlaceholderKey Id; + public readonly PlaceholderKey Id; - /// - /// for - /// - public readonly PlaceholderKey Name; + /// + /// for + /// + public readonly PlaceholderKey Name; - /// - /// for - /// - public readonly PlaceholderKey Mention; + /// + /// for + /// + public readonly PlaceholderKey Mention; - /// - /// for - /// - public readonly PlaceholderKey Icon; + /// + /// for + /// + public readonly PlaceholderKey Icon; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public RoleKeys(string prefix) - { - Id = new PlaceholderKey(prefix, "id"); - Name = new PlaceholderKey(prefix, "name"); - Mention = new PlaceholderKey(prefix, "mention"); - Icon = new PlaceholderKey(prefix, "icon"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public RoleKeys(string prefix) + { + Id = new PlaceholderKey(prefix, "id"); + Name = new PlaceholderKey(prefix, "name"); + Mention = new PlaceholderKey(prefix, "mention"); + Icon = new PlaceholderKey(prefix, "icon"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ServerKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ServerKeys.cs index f119ba861..5ed6b15f3 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ServerKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/ServerKeys.cs @@ -1,72 +1,71 @@ using Oxide.Core.Libraries.Covalence; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class ServerKeys { /// - /// Placeholder Keys for + /// for /// - public class ServerKeys - { - /// - /// for - /// - public readonly PlaceholderKey Name; + public readonly PlaceholderKey Name; - /// - /// for - /// - public readonly PlaceholderKey Players; + /// + /// for + /// + public readonly PlaceholderKey Players; - /// - /// for - /// - public readonly PlaceholderKey MaxPlayers; + /// + /// for + /// + public readonly PlaceholderKey MaxPlayers; - /// - /// for Total Players - /// - public readonly PlaceholderKey TotalPlayers; + /// + /// for Total Players + /// + public readonly PlaceholderKey TotalPlayers; - /// - /// for - /// - public readonly PlaceholderKey Version; + /// + /// for + /// + public readonly PlaceholderKey Version; - /// - /// for - /// - public readonly PlaceholderKey Protocol; + /// + /// for + /// + public readonly PlaceholderKey Protocol; - /// - /// for - /// - public readonly PlaceholderKey Address; + /// + /// for + /// + public readonly PlaceholderKey Address; - /// - /// for - /// - public readonly PlaceholderKey Port; + /// + /// for + /// + public readonly PlaceholderKey Port; - /// - /// for - /// - public readonly PlaceholderKey Time; + /// + /// for + /// + public readonly PlaceholderKey Time; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public ServerKeys(string prefix) - { - Name = new PlaceholderKey(prefix, "name"); - Players = new PlaceholderKey(prefix, "players"); - MaxPlayers = new PlaceholderKey(prefix, "players.max"); - TotalPlayers = new PlaceholderKey(prefix, "players.total"); - Version = new PlaceholderKey(prefix, "version"); - Protocol = new PlaceholderKey(prefix, "protocol"); - Address = new PlaceholderKey(prefix, "address"); - Port = new PlaceholderKey(prefix, "port"); - Time = new PlaceholderKey(prefix, "time"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public ServerKeys(string prefix) + { + Name = new PlaceholderKey(prefix, "name"); + Players = new PlaceholderKey(prefix, "players"); + MaxPlayers = new PlaceholderKey(prefix, "players.max"); + TotalPlayers = new PlaceholderKey(prefix, "players.total"); + Version = new PlaceholderKey(prefix, "version"); + Protocol = new PlaceholderKey(prefix, "protocol"); + Address = new PlaceholderKey(prefix, "address"); + Port = new PlaceholderKey(prefix, "port"); + Time = new PlaceholderKey(prefix, "time"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/SnowflakeKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/SnowflakeKeys.cs index 32b9bed36..cbd55768f 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/SnowflakeKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/SnowflakeKeys.cs @@ -1,30 +1,29 @@ using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class SnowflakeKeys { /// - /// Placeholder Keys for + /// for /// - public class SnowflakeKeys - { - /// - /// for - /// - public readonly PlaceholderKey Id; + public readonly PlaceholderKey Id; - /// - /// for - /// - public readonly PlaceholderKey Created; + /// + /// for + /// + public readonly PlaceholderKey Created; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public SnowflakeKeys(string prefix) - { - Id = new PlaceholderKey(prefix, "id"); - Created = new PlaceholderKey(prefix, "created"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public SnowflakeKeys(string prefix) + { + Id = new PlaceholderKey(prefix, "id"); + Created = new PlaceholderKey(prefix, "created"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/TimespanKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/TimespanKeys.cs index fe18badec..6234f49a1 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/TimespanKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/TimespanKeys.cs @@ -1,90 +1,89 @@ using System; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class TimespanKeys { /// - /// Placeholder Keys for + /// for /// - public class TimespanKeys - { - /// - /// for - /// - public readonly PlaceholderKey Time; + public readonly PlaceholderKey Time; - /// - /// for - /// - public readonly PlaceholderKey Formatted; + /// + /// for + /// + public readonly PlaceholderKey Formatted; - /// - /// for - /// - public readonly PlaceholderKey Days; + /// + /// for + /// + public readonly PlaceholderKey Days; - /// - /// for - /// - public readonly PlaceholderKey Hours; + /// + /// for + /// + public readonly PlaceholderKey Hours; - /// - /// for - /// - public readonly PlaceholderKey Minutes; + /// + /// for + /// + public readonly PlaceholderKey Minutes; - /// - /// for - /// - public readonly PlaceholderKey Seconds; + /// + /// for + /// + public readonly PlaceholderKey Seconds; - /// - /// for - /// - public readonly PlaceholderKey Milliseconds; + /// + /// for + /// + public readonly PlaceholderKey Milliseconds; - /// - /// for - /// - public readonly PlaceholderKey TotalDays; + /// + /// for + /// + public readonly PlaceholderKey TotalDays; - /// - /// for - /// - public readonly PlaceholderKey TotalHours; + /// + /// for + /// + public readonly PlaceholderKey TotalHours; - /// - /// for - /// - public readonly PlaceholderKey TotalMinutes; + /// + /// for + /// + public readonly PlaceholderKey TotalMinutes; - /// - /// for - /// - public readonly PlaceholderKey TotalSeconds; + /// + /// for + /// + public readonly PlaceholderKey TotalSeconds; - /// - /// for - /// - public readonly PlaceholderKey TotalMilliseconds; + /// + /// for + /// + public readonly PlaceholderKey TotalMilliseconds; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public TimespanKeys(string prefix) - { - Time = new PlaceholderKey(prefix, "time"); - Formatted = new PlaceholderKey(prefix, "formatted"); - Days = new PlaceholderKey(prefix, "days"); - Hours = new PlaceholderKey(prefix, "hours"); - Minutes = new PlaceholderKey(prefix, "minutes"); - Seconds = new PlaceholderKey(prefix, "seconds"); - Milliseconds = new PlaceholderKey(prefix, "milliseconds"); - TotalDays = new PlaceholderKey(prefix, "total.days"); - TotalHours = new PlaceholderKey(prefix, "total.hours"); - TotalMinutes = new PlaceholderKey(prefix, "total.minutes"); - TotalSeconds = new PlaceholderKey(prefix, "total.seconds"); - TotalMilliseconds = new PlaceholderKey(prefix, "total.milliseconds"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public TimespanKeys(string prefix) + { + Time = new PlaceholderKey(prefix, "time"); + Formatted = new PlaceholderKey(prefix, "formatted"); + Days = new PlaceholderKey(prefix, "days"); + Hours = new PlaceholderKey(prefix, "hours"); + Minutes = new PlaceholderKey(prefix, "minutes"); + Seconds = new PlaceholderKey(prefix, "seconds"); + Milliseconds = new PlaceholderKey(prefix, "milliseconds"); + TotalDays = new PlaceholderKey(prefix, "total.days"); + TotalHours = new PlaceholderKey(prefix, "total.hours"); + TotalMinutes = new PlaceholderKey(prefix, "total.minutes"); + TotalSeconds = new PlaceholderKey(prefix, "total.seconds"); + TotalMilliseconds = new PlaceholderKey(prefix, "total.milliseconds"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/TimestampKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/TimestampKeys.cs index 59b9b389b..a28aa4134 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/TimestampKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/TimestampKeys.cs @@ -1,66 +1,65 @@ using Oxide.Ext.Discord.Helpers; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class TimestampKeys { /// - /// Placeholder Keys for + /// for /// - public class TimestampKeys - { - /// - /// for - /// - public readonly PlaceholderKey Time; + public readonly PlaceholderKey Time; - /// - /// for formatted as - /// - public readonly PlaceholderKey ShortTime; + /// + /// for formatted as + /// + public readonly PlaceholderKey ShortTime; - /// - /// for formatted as - /// - public readonly PlaceholderKey LongTime; + /// + /// for formatted as + /// + public readonly PlaceholderKey LongTime; - /// - /// for formatted as - /// - public readonly PlaceholderKey ShortDate; + /// + /// for formatted as + /// + public readonly PlaceholderKey ShortDate; - /// - /// for formatted as - /// - public readonly PlaceholderKey LongDate; + /// + /// for formatted as + /// + public readonly PlaceholderKey LongDate; - /// - /// for formatted as - /// - public readonly PlaceholderKey ShortDateTime; + /// + /// for formatted as + /// + public readonly PlaceholderKey ShortDateTime; - /// - /// for formatted as - /// - public readonly PlaceholderKey LongDateTime; + /// + /// for formatted as + /// + public readonly PlaceholderKey LongDateTime; - /// - /// for formatted as - /// - public readonly PlaceholderKey RelativeTime; + /// + /// for formatted as + /// + public readonly PlaceholderKey RelativeTime; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public TimestampKeys(string prefix) - { - Time = new PlaceholderKey(prefix); - ShortTime = new PlaceholderKey(prefix, "shorttime"); - LongTime = new PlaceholderKey(prefix, "longtime"); - ShortDate = new PlaceholderKey(prefix, "shortdate"); - LongDate = new PlaceholderKey(prefix, "longdate"); - ShortDateTime = new PlaceholderKey(prefix, "shortdatetime"); - LongDateTime = new PlaceholderKey(prefix, "longdatetime"); - RelativeTime = new PlaceholderKey(prefix, "relativetime"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public TimestampKeys(string prefix) + { + Time = new PlaceholderKey(prefix); + ShortTime = new PlaceholderKey(prefix, "shorttime"); + LongTime = new PlaceholderKey(prefix, "longtime"); + ShortDate = new PlaceholderKey(prefix, "shortdate"); + LongDate = new PlaceholderKey(prefix, "longdate"); + ShortDateTime = new PlaceholderKey(prefix, "shortdatetime"); + LongDateTime = new PlaceholderKey(prefix, "longdatetime"); + RelativeTime = new PlaceholderKey(prefix, "relativetime"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/UserKeys.cs b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/UserKeys.cs index 3816cc58c..4fae9a261 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/Keys/UserKeys.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/Keys/UserKeys.cs @@ -1,67 +1,66 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Extensions; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Keys for +/// +public class UserKeys { /// - /// Placeholder Keys for + /// for /// - public class UserKeys - { - /// - /// for - /// - public readonly PlaceholderKey Id; + public readonly PlaceholderKey Id; - /// - /// for - /// - public readonly PlaceholderKey Username; + /// + /// for + /// + public readonly PlaceholderKey Username; - /// - /// for - /// - public readonly PlaceholderKey Discriminator; + /// + /// for + /// + public readonly PlaceholderKey Discriminator; - /// - /// for - /// - public readonly PlaceholderKey Fullname; + /// + /// for + /// + public readonly PlaceholderKey Fullname; - /// - /// for - /// - public readonly PlaceholderKey AvatarUrl; + /// + /// for + /// + public readonly PlaceholderKey AvatarUrl; - /// - /// for - /// - public readonly PlaceholderKey BannerUrl; + /// + /// for + /// + public readonly PlaceholderKey BannerUrl; - /// - /// for - /// - public readonly PlaceholderKey Mention; + /// + /// for + /// + public readonly PlaceholderKey Mention; - /// - /// for - /// - public readonly PlaceholderKey IsLinked; + /// + /// for + /// + public readonly PlaceholderKey IsLinked; - /// - /// Constructor - /// - /// Placeholder Key Prefix - public UserKeys(string prefix) - { - Id = new PlaceholderKey(prefix, "id"); - Username = new PlaceholderKey(prefix, "username"); - Discriminator = new PlaceholderKey(prefix, "discriminator"); - Fullname = new PlaceholderKey(prefix, "fullname"); - AvatarUrl = new PlaceholderKey(prefix, "avatar.url"); - BannerUrl = new PlaceholderKey(prefix, "banner.url"); - Mention = new PlaceholderKey(prefix, "mention"); - IsLinked = new PlaceholderKey(prefix, "islinked"); - } + /// + /// Constructor + /// + /// Placeholder Key Prefix + public UserKeys(string prefix) + { + Id = new PlaceholderKey(prefix, "id"); + Username = new PlaceholderKey(prefix, "username"); + Discriminator = new PlaceholderKey(prefix, "discriminator"); + Fullname = new PlaceholderKey(prefix, "fullname"); + AvatarUrl = new PlaceholderKey(prefix, "avatar.url"); + BannerUrl = new PlaceholderKey(prefix, "banner.url"); + Mention = new PlaceholderKey(prefix, "mention"); + IsLinked = new PlaceholderKey(prefix, "islinked"); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderData.cs b/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderData.cs index 4f58d0194..6d98b57a2 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderData.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderData.cs @@ -11,436 +11,434 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Placeholder Data for placeholders +/// +public class PlaceholderData : BasePoolable { + private readonly Hash _data = new(); + private readonly List _boxed = new(); + private bool AutoPool { get; set; } = true; + private int _processDepth; + + internal PlaceholderData() { } + + internal void AddServer(IServer server) => Add(new PlaceholderDataKey(nameof(IServer)), server); + /// - /// Placeholder Data for placeholders + /// Add a /// - public class PlaceholderData : BasePoolable - { - private readonly Hash _data = new Hash(); - private readonly List _boxed = new List(); - private bool AutoPool { get; set; } = true; - private int _processDepth; + /// Application Command to add + /// This + public PlaceholderData AddCommand(DiscordApplicationCommand command) => Add(new PlaceholderDataKey(nameof(DiscordApplicationCommand)), command); - internal PlaceholderData() { } + /// + /// Add a by and GuildId + /// + /// Discord Client for the guild + /// Guild ID of the guild + /// This + public PlaceholderData AddGuild(DiscordClient client, Snowflake? guildId) => AddGuild(client.Bot?.GetGuild(guildId)); - internal void AddServer(IServer server) => Add(new PlaceholderDataKey(nameof(IServer)), server); - - /// - /// Add a - /// - /// Application Command to add - /// This - public PlaceholderData AddCommand(DiscordApplicationCommand command) => Add(new PlaceholderDataKey(nameof(DiscordApplicationCommand)), command); - - /// - /// Add a by and GuildId - /// - /// Discord Client for the guild - /// Guild ID of the guild - /// This - public PlaceholderData AddGuild(DiscordClient client, Snowflake? guildId) => AddGuild(client.Bot?.GetGuild(guildId)); - - /// - /// Add a - /// - /// Guild to add - /// This - public PlaceholderData AddGuild(DiscordGuild guild) => Add(new PlaceholderDataKey(nameof(DiscordGuild)), guild); + /// + /// Add a + /// + /// Guild to add + /// This + public PlaceholderData AddGuild(DiscordGuild guild) => Add(new PlaceholderDataKey(nameof(DiscordGuild)), guild); - /// - /// Removes guild placeholder data - /// - /// This - public PlaceholderData RemoveGuild() => Remove(new PlaceholderDataKey(nameof(DiscordGuild))); - - /// - /// Add a - /// - /// Message to add - /// This - public PlaceholderData AddMessage(DiscordMessage message) + /// + /// Removes guild placeholder data + /// + /// This + public PlaceholderData RemoveGuild() => Remove(new PlaceholderDataKey(nameof(DiscordGuild))); + + /// + /// Add a + /// + /// Message to add + /// This + public PlaceholderData AddMessage(DiscordMessage message) + { + if (message != null) { - if (message != null) - { - AddGuildMember(message.Member); - AddUser(message.Author); - Add(new PlaceholderDataKey(nameof(DiscordMessage)), message); - } - - return this; + AddGuildMember(message.Member); + AddUser(message.Author); + Add(new PlaceholderDataKey(nameof(DiscordMessage)), message); } + + return this; + } - /// - /// Removes message placeholder data - /// - /// This - public PlaceholderData RemoveMessage() => Remove(new PlaceholderDataKey(nameof(DiscordMessage))); - - /// - /// Add a by , GuildId, and UserId - /// - /// DiscordClient for the guild - /// Guild ID for the guild - /// Member UserId in the guild - /// This - public PlaceholderData AddGuildMember(DiscordClient client, Snowflake guildId, Snowflake memberId) => AddGuildMember(client.Bot?.GetGuild(guildId).Members[memberId]); - - /// - /// Add a - /// - /// Member to add - /// - public PlaceholderData AddGuildMember(GuildMember member) - { - if (member != null) - { - AddUser(member.User); - Add(new PlaceholderDataKey(nameof(GuildMember)), member); - } + /// + /// Removes message placeholder data + /// + /// This + public PlaceholderData RemoveMessage() => Remove(new PlaceholderDataKey(nameof(DiscordMessage))); - return this; + /// + /// Add a by , GuildId, and UserId + /// + /// DiscordClient for the guild + /// Guild ID for the guild + /// Member UserId in the guild + /// This + public PlaceholderData AddGuildMember(DiscordClient client, Snowflake guildId, Snowflake memberId) => AddGuildMember(client.Bot?.GetGuild(guildId).Members[memberId]); + + /// + /// Add a + /// + /// Member to add + /// + public PlaceholderData AddGuildMember(GuildMember member) + { + if (member != null) + { + AddUser(member.User); + Add(new PlaceholderDataKey(nameof(GuildMember)), member); } + + return this; + } - /// - /// Removes guild member data - /// - /// This - public PlaceholderData RemoveGuildMember() => Remove(new PlaceholderDataKey(nameof(GuildMember))); - - /// - /// Adds a - /// - /// User to add - /// This - public PlaceholderData AddUser(DiscordUser user) - { - if (user != null) - { - AddPlayer(user.Player); - Add(new PlaceholderDataKey(nameof(DiscordUser)), user); - } + /// + /// Removes guild member data + /// + /// This + public PlaceholderData RemoveGuildMember() => Remove(new PlaceholderDataKey(nameof(GuildMember))); - return this; + /// + /// Adds a + /// + /// User to add + /// This + public PlaceholderData AddUser(DiscordUser user) + { + if (user != null) + { + AddPlayer(user.Player); + Add(new PlaceholderDataKey(nameof(DiscordUser)), user); } + + return this; + } - /// - /// Adds a - /// - /// User to add - /// This - internal PlaceholderData AddBotUser(DiscordUser user) + /// + /// Adds a + /// + /// User to add + /// This + internal PlaceholderData AddBotUser(DiscordUser user) + { + if (user != null) { - if (user != null) - { - Add(UserPlaceholders.BotUserKey, user); - } - - return this; + Add(UserPlaceholders.BotUserKey, user); } + + return this; + } - /// - /// Adds a - /// - /// User to add - /// This - public PlaceholderData AddUserTarget(DiscordUser user) + /// + /// Adds a + /// + /// User to add + /// This + public PlaceholderData AddUserTarget(DiscordUser user) + { + if (user != null) { - if (user != null) - { - AddTarget(user.Player); - Add(UserPlaceholders.TargetUserKey, user); - } - - return this; + AddTarget(user.Player); + Add(UserPlaceholders.TargetUserKey, user); } + + return this; + } - /// - /// Removes user placeholder data - /// - /// This - public PlaceholderData RemoveUser() => Remove(new PlaceholderDataKey(nameof(DiscordUser))); - - /// - /// Adds a by , GuildId, and RoleId - /// - /// Client for the guild - /// Guild ID of the guild - /// Role ID of the role - /// This - public PlaceholderData AddRole(DiscordClient client, Snowflake guildId, Snowflake roleId) => AddRole(client.Bot?.GetGuild(guildId)?.Roles[roleId]); - - /// - /// Adds a - /// - /// Role to add - /// This - public PlaceholderData AddRole(DiscordRole role) => Add(new PlaceholderDataKey(nameof(DiscordRole)), role); + /// + /// Removes user placeholder data + /// + /// This + public PlaceholderData RemoveUser() => Remove(new PlaceholderDataKey(nameof(DiscordUser))); + + /// + /// Adds a by , GuildId, and RoleId + /// + /// Client for the guild + /// Guild ID of the guild + /// Role ID of the role + /// This + public PlaceholderData AddRole(DiscordClient client, Snowflake guildId, Snowflake roleId) => AddRole(client.Bot?.GetGuild(guildId)?.Roles[roleId]); + + /// + /// Adds a + /// + /// Role to add + /// This + public PlaceholderData AddRole(DiscordRole role) => Add(new PlaceholderDataKey(nameof(DiscordRole)), role); - /// - /// Removes role placeholder data - /// - /// This - public PlaceholderData RemoveRole() => Remove(new PlaceholderDataKey(nameof(DiscordRole))); - - /// - /// Adds a by , ChannelId, and Optional GuildId - /// - /// Client for the channel - /// Channel ID of the channel - /// Guild ID of the channel if channel is in a guild - /// This - public PlaceholderData AddChannel(DiscordClient client, Snowflake channelId, Snowflake? guildId = null) => AddChannel(client.Bot?.GetChannel(channelId, guildId)); - - /// - /// Adds a - /// - /// Channel to add - /// This - public PlaceholderData AddChannel(DiscordChannel channel) => Add(new PlaceholderDataKey(nameof(DiscordChannel)), channel); + /// + /// Removes role placeholder data + /// + /// This + public PlaceholderData RemoveRole() => Remove(new PlaceholderDataKey(nameof(DiscordRole))); + + /// + /// Adds a by , ChannelId, and Optional GuildId + /// + /// Client for the channel + /// Channel ID of the channel + /// Guild ID of the channel if channel is in a guild + /// This + public PlaceholderData AddChannel(DiscordClient client, Snowflake channelId, Snowflake? guildId = null) => AddChannel(client.Bot?.GetChannel(channelId, guildId)); + + /// + /// Adds a + /// + /// Channel to add + /// This + public PlaceholderData AddChannel(DiscordChannel channel) => Add(new PlaceholderDataKey(nameof(DiscordChannel)), channel); - /// - /// Removes channel placeholder data - /// - /// This - public PlaceholderData RemoveChannel() => Remove(new PlaceholderDataKey(nameof(DiscordChannel))); + /// + /// Removes channel placeholder data + /// + /// This + public PlaceholderData RemoveChannel() => Remove(new PlaceholderDataKey(nameof(DiscordChannel))); - /// - /// Adds a - /// - /// Interaction to add - /// This - public PlaceholderData AddInteraction(DiscordInteraction interaction) + /// + /// Adds a + /// + /// Interaction to add + /// This + public PlaceholderData AddInteraction(DiscordInteraction interaction) + { + if (interaction != null) { - if (interaction != null) - { - AddMessage(interaction.Message); - AddGuildMember(interaction.Member); - AddUser(interaction.User); - AddChannel(interaction.Channel); - Add(new PlaceholderDataKey(nameof(DiscordInteraction)), interaction); - } - - return this; + AddMessage(interaction.Message); + AddGuildMember(interaction.Member); + AddUser(interaction.User); + AddChannel(interaction.Channel); + Add(new PlaceholderDataKey(nameof(DiscordInteraction)), interaction); } - /// - /// Adds a - /// - /// player to add - /// This - public PlaceholderData AddPlayer(IPlayer player) => Add(new PlaceholderDataKey(nameof(IPlayer)), player); - - /// - /// Removes player placeholder data - /// - /// This - public PlaceholderData RemovePlayer() => Remove(new PlaceholderDataKey(nameof(IPlayer))); - - /// - /// Adds a target - /// - /// player to add - /// This - public PlaceholderData AddTarget(IPlayer player) => Add(PlayerPlaceholders.TargetPlayerKey, player); - - /// - /// Adds a - /// - /// Plugin to add - /// This - public PlaceholderData AddPlugin(Plugin plugin) => Add(new PlaceholderDataKey(nameof(Plugin)), plugin); - - /// - /// Adds a Unix Timestamp - /// - /// Unix timestamp - /// This - public PlaceholderData AddTimestamp(DateTimeOffset timestamp) => AddTimestamp(timestamp.ToUnixTimeSeconds()); + return this; + } + + /// + /// Adds a + /// + /// player to add + /// This + public PlaceholderData AddPlayer(IPlayer player) => Add(new PlaceholderDataKey(nameof(IPlayer)), player); + + /// + /// Removes player placeholder data + /// + /// This + public PlaceholderData RemovePlayer() => Remove(new PlaceholderDataKey(nameof(IPlayer))); + + /// + /// Adds a target + /// + /// player to add + /// This + public PlaceholderData AddTarget(IPlayer player) => Add(PlayerPlaceholders.TargetPlayerKey, player); + + /// + /// Adds a + /// + /// Plugin to add + /// This + public PlaceholderData AddPlugin(Plugin plugin) => Add(new PlaceholderDataKey(nameof(Plugin)), plugin); + + /// + /// Adds a Unix Timestamp + /// + /// Unix timestamp + /// This + public PlaceholderData AddTimestamp(DateTimeOffset timestamp) => AddTimestamp(timestamp.ToUnixTimeSeconds()); - /// - /// Adds a Unix Timestamp - /// - /// Unix timestamp - /// This - public PlaceholderData AddTimestamp(long timestamp) => Add(TimestampPlaceholders.TimestampKey, timestamp); + /// + /// Adds a Unix Timestamp + /// + /// Unix timestamp + /// This + public PlaceholderData AddTimestamp(long timestamp) => Add(TimestampPlaceholders.TimestampKey, timestamp); - /// - /// Adds a - /// - /// Timespan - /// This - public PlaceholderData AddTimeSpan(TimeSpan timespan) => Add(TimeSpanPlaceholders.TimeSpanKey, timespan); - - /// - /// Adds a - /// - /// ID - /// This - public PlaceholderData AddSnowflake(Snowflake id) => Add(new PlaceholderDataKey(nameof(Snowflake)), id); + /// + /// Adds a + /// + /// Timespan + /// This + public PlaceholderData AddTimeSpan(TimeSpan timespan) => Add(TimeSpanPlaceholders.TimeSpanKey, timespan); + + /// + /// Adds a + /// + /// ID + /// This + public PlaceholderData AddSnowflake(Snowflake id) => Add(new PlaceholderDataKey(nameof(Snowflake)), id); - /// - /// Adds a - /// - /// RequestError to add - /// This - public PlaceholderData AddRequestError(ResponseError error) => Add(new PlaceholderDataKey(nameof(ResponseError)), error); + /// + /// Adds a + /// + /// RequestError to add + /// This + public PlaceholderData AddRequestError(ResponseError error) => Add(new PlaceholderDataKey(nameof(ResponseError)), error); - /// - /// Adds a IP - /// - /// - /// - public PlaceholderData AddIp(string ip) => Add(new PlaceholderDataKey("ip"), ip); + /// + /// Adds an IP + /// + /// + /// + public PlaceholderData AddIp(string ip) => Add(new PlaceholderDataKey("ip"), ip); - /// - /// Adds the data with the given name - /// - /// Name of the data key - /// Object to add - /// This - public PlaceholderData Add(PlaceholderDataKey name, T obj) - { - InvalidPlaceholderDataException.ThrowIfInvalid(name); - - if (typeof(T).IsValueType()) - { - AddBoxed(name, DiscordPool.Internal.GetBoxed(obj)); - return this; - } + /// + /// Adds the data with the given name + /// + /// Name of the data key + /// Object to add + /// This + public PlaceholderData Add(PlaceholderDataKey name, T obj) + { + InvalidPlaceholderDataException.ThrowIfInvalid(name); - object value = obj; - if (value != null) - { - _data[name] = value; - } - + if (typeof(T).IsValueType()) + { + AddBoxed(name, DiscordPool.Internal.GetBoxed(obj)); return this; } - - private void AddBoxed(PlaceholderDataKey name, IBoxed boxed) + + object value = obj; + if (value != null) { - _data[name] = boxed; - _boxed.Add(boxed); + _data[name] = value; } - /// - /// Removes placeholder data key with the given name - /// - /// This - public PlaceholderData Remove(PlaceholderDataKey name) + return this; + } + + private void AddBoxed(PlaceholderDataKey name, IBoxed boxed) + { + _data[name] = boxed; + _boxed.Add(boxed); + } + + /// + /// Removes placeholder data key with the given name + /// + /// This + public PlaceholderData Remove(PlaceholderDataKey name) + { + if (_data.Remove(name, out object value)) { - if (_data.TryGetValue(name, out object value)) + if (value is IBoxed boxed) { - _data.Remove(name); - if (value is IBoxed boxed) - { - boxed.Dispose(); - } + boxed.Dispose(); } - - return this; } + + return this; + } - /// - /// Returns the object with the given type of {T} - /// The key name used is nameof(T) - /// - /// Type to return - /// {T} - public T Get() - { - return Get(new PlaceholderDataKey(typeof(T).Name)); - } + /// + /// Returns the object with the given type of {T} + /// The key name used is nameof(T) + /// + /// Type to return + /// {T} + public T Get() + { + return Get(new PlaceholderDataKey(typeof(T).Name)); + } - /// - /// Returns the object with the given type of T - /// If the object is not found the default(T) is returned - /// - /// Name of the data key - /// Type to return - /// {T} - public T Get(PlaceholderDataKey name) + /// + /// Returns the object with the given type of T + /// If the object is not found the default(T) is returned + /// + /// Name of the data key + /// Type to return + /// {T} + public T Get(PlaceholderDataKey name) + { + InvalidPlaceholderDataException.ThrowIfInvalid(name); + if (_data.TryGetValue(name, out object obj)) { - InvalidPlaceholderDataException.ThrowIfInvalid(name); - if (_data.TryGetValue(name, out object obj)) + if (obj is T value) + { + return value; + } + if (obj is Boxed boxed) { - if (obj is T value) - { - return value; - } - if (obj is Boxed boxed) - { - return boxed.Value; - } - - DiscordExtension.GlobalLogger.Warning($"{nameof(PlaceholderData)}.{nameof(Get)} Failed to Convert Type: {{0}} to Type: {{1}}", obj.GetType().GetRealTypeName(), typeof(T)); + return boxed.Value; } - return default(T); + DiscordExtension.GlobalLogger.Warning($"{nameof(PlaceholderData)}.{nameof(Get)} Failed to Convert Type: {{0}} to Type: {{1}}", obj.GetType().GetRealTypeName(), typeof(T)); } - /// - /// Returns comma seperated string of all the registered key - /// Useful for debugging placeholders - /// - /// - public string GetKeys() - { - return string.Join(", ", _data.Keys.Select(k => k.Key)); - } + return default; + } - /// - /// Disable automatic pooling and handle manually by plugin - /// - public void ManualPool() - { - AutoPool = false; - } + /// + /// Returns comma seperated string of all the registered key + /// Useful for debugging placeholders + /// + /// + public string GetKeys() + { + return string.Join(", ", _data.Keys.Select(k => k.Key)); + } - internal void IncrementDepth() => _processDepth++; - internal void DecrementDepth() => _processDepth--; + /// + /// Disable automatic pooling and handle manually by plugin + /// + public void ManualPool() + { + AutoPool = false; + } + + internal void IncrementDepth() => _processDepth++; + internal void DecrementDepth() => _processDepth--; - /// - /// Clones the current placeholder data into a new - /// - /// - public PlaceholderData Clone() + /// + /// Clones the current placeholder data into a new + /// + /// + public PlaceholderData Clone() + { + PlaceholderData clone = PluginPool.GetPlaceholderData(); + foreach (KeyValuePair data in _data) { - PlaceholderData clone = PluginPool.GetPlaceholderData(); - foreach (KeyValuePair data in _data) + if (data.Value is IBoxed boxed) + { + clone.AddBoxed(data.Key, boxed.Copy()); + } + else { - if (data.Value is IBoxed boxed) - { - clone.AddBoxed(data.Key, boxed.Copy()); - } - else - { - clone.Add(data.Key, data.Value); - } + clone.Add(data.Key, data.Value); } - return clone; } + return clone; + } - /// - protected override void EnterPool() + /// + protected override void EnterPool() + { + for (int index = 0; index < _boxed.Count; index++) { - for (int index = 0; index < _boxed.Count; index++) - { - _boxed[index].Dispose(); - } - AutoPool = true; - _data.Clear(); - _boxed.Clear(); + _boxed[index].Dispose(); } + AutoPool = true; + _data.Clear(); + _boxed.Clear(); + } - internal void AutoDispose() + internal void AutoDispose() + { + if (AutoPool && _processDepth == 0) { - if (AutoPool && _processDepth == 0) - { - Dispose(); - } + Dispose(); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderDataKey.cs b/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderDataKey.cs index 536e016ea..6bf6acb95 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderDataKey.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderDataKey.cs @@ -1,39 +1,27 @@ -using System; +namespace Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Libraries +/// +/// Represents a Placeholder Data Key +/// This is the key used to store a value into Placeholder Data +/// +public readonly record struct PlaceholderDataKey { /// - /// Represents a Placeholder Data Key - /// This is the key used to store a value into Placeholder Data + /// Value of the key /// - public struct PlaceholderDataKey : IEquatable - { - /// - /// Value of the key - /// - public readonly string Key; - - /// - /// If the is a valid value - /// - public bool IsValid => !string.IsNullOrEmpty(Key); + public readonly string Key; - /// - /// Constructor - /// - /// Value of the key - public PlaceholderDataKey(string key) - { - Key = key; - } - - /// - public bool Equals(PlaceholderDataKey other) => Key == other.Key; - - /// - public override bool Equals(object obj) => obj is PlaceholderDataKey other && Equals(other); + /// + /// If the is a valid value + /// + public bool IsValid => !string.IsNullOrEmpty(Key); - /// - public override int GetHashCode() => (Key != null ? Key.GetHashCode() : 0); + /// + /// Constructor + /// + /// Value of the key + public PlaceholderDataKey(string key) + { + Key = key; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderFormatting.cs b/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderFormatting.cs index acdfc700e..ecae8df11 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderFormatting.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderFormatting.cs @@ -8,378 +8,377 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Extensions; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Formatting Helpers for Placeholders +/// +internal static class PlaceholderFormatting { + private static readonly Regex GenericPositionRegex = new(@"([xyz])(?::?([\d\.]*))", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly ThreadLocal Buffer = new(() => new char[128]); + /// - /// Formatting Helpers for Placeholders + /// Replace the with the string value /// - internal static class PlaceholderFormatting + /// for the placeholder + /// for the placeholder + /// Placeholder value to replace + private static void Replace(StringBuilder builder, PlaceholderState state, ReadOnlySpan value) { - private static readonly Regex GenericPositionRegex = new Regex(@"([xyz])(?::?([\d\.]*))", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly ThreadLocal Buffer = new ThreadLocal(() => new char[128]); + builder.Replace(value, state.Index, state.Length); + } - /// - /// Replace the with the the string value - /// - /// for the placeholder - /// for the placeholder - /// Placeholder value to replace - private static void Replace(StringBuilder builder, PlaceholderState state, ReadOnlySpan value) + private static void Replace(StringBuilder builder, PlaceholderState state, IReadOnlyList values) + { + builder.Remove(state.Index, state.Length); + if (values == null || values.Count == 0) { - builder.Replace(value, state.Index, state.Length); + return; } - private static void Replace(StringBuilder builder, PlaceholderState state, IReadOnlyList values) + string separator = !string.IsNullOrEmpty(state.Format) ? state.Format : ", "; + for (int index = 0; index < values.Count; index++) { - builder.Remove(state.Index, state.Length); - if (values == null || values.Count == 0) + if (index != 0) { - return; + builder.Append(separator); } + builder.Append(values[index]); + } + } - string separator = !string.IsNullOrEmpty(state.Format) ? state.Format : ", "; - for (int index = 0; index < values.Count; index++) - { - if (index != 0) - { - builder.Append(separator); - } - builder.Append(values[index]); - } + private static void Replace(StringBuilder builder, PlaceholderState state, IReadOnlyList values) + { + builder.Remove(state.Index, state.Length); + if (values == null || values.Count == 0) + { + return; } - private static void Replace(StringBuilder builder, PlaceholderState state, IReadOnlyList values) + string separator = !string.IsNullOrEmpty(state.Format) ? state.Format : ", "; + for (int index = 0; index < values.Count; index++) { - builder.Remove(state.Index, state.Length); - if (values == null || values.Count == 0) + if (index != 0) { - return; + builder.Append(separator); } + builder.Append(values[index]); + } + } - string separator = !string.IsNullOrEmpty(state.Format) ? state.Format : ", "; - for (int index = 0; index < values.Count; index++) - { - if (index != 0) - { - builder.Append(separator); - } - builder.Append(values[index]); - } + /// + /// Replace the with the the string value + /// + /// for the placeholder + /// for the placeholder + /// Snowflake value to replace + private static void Replace(StringBuilder builder, PlaceholderState state, bool value) + { + if (string.IsNullOrEmpty(state.Format)) + { + Replace(builder, state, value ? "true" : "false"); + return; } - /// - /// Replace the with the the string value - /// - /// for the placeholder - /// for the placeholder - /// Snowflake value to replace - private static void Replace(StringBuilder builder, PlaceholderState state, bool value) + int split = state.Format.IndexOf(','); + if (split == -1) { - if (string.IsNullOrEmpty(state.Format)) - { - Replace(builder, state, value ? "true" : "false"); - return; - } + Replace(builder, state, value ? "true" : "false"); + return; + } - int split = state.Format.IndexOf(','); - if (split == -1) - { - Replace(builder, state, value ? "true" : "false"); - return; - } + ReadOnlySpan span = state.Format; + if (value) + { + span = span.Slice(0, split); + } + else + { + span = span.Slice(split + 1, span.Length - split - 1); + } - ReadOnlySpan span = state.Format; - if (value) - { - span = span.Slice(0, split); - } - else - { - span = span.Slice(split + 1, span.Length - split - 1); - } + Replace(builder, state, span); + } - Replace(builder, state, span); - } + /// + /// Replace the with the the value + /// + /// for the placeholder + /// for the placeholder + /// Snowflake value to replace + private static void Replace(StringBuilder builder, PlaceholderState state, Snowflake value) + { + Replace(builder, state, value.Id); + } - /// - /// Replace the with the the value - /// - /// for the placeholder - /// for the placeholder - /// Snowflake value to replace - private static void Replace(StringBuilder builder, PlaceholderState state, Snowflake value) + private static void Replace(StringBuilder builder, PlaceholderState state, byte value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Replace(builder, state, value.Id); + Replace(builder, state, span.Slice(0, written)); } - - private static void Replace(StringBuilder builder, PlaceholderState state, byte value) + else { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, sbyte value) + private static void Replace(StringBuilder builder, PlaceholderState state, sbyte value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); } + else + { + Replace(builder, state, value as IFormattable); + } + } - private static void Replace(StringBuilder builder, PlaceholderState state, short value) + private static void Replace(StringBuilder builder, PlaceholderState state, short value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, ushort value) + private static void Replace(StringBuilder builder, PlaceholderState state, ushort value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, int value) + private static void Replace(StringBuilder builder, PlaceholderState state, int value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, uint value) + private static void Replace(StringBuilder builder, PlaceholderState state, uint value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, long value) + private static void Replace(StringBuilder builder, PlaceholderState state, long value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } - + Replace(builder, state, span.Slice(0, written)); } + else + { + Replace(builder, state, value as IFormattable); + } + + } - private static void Replace(StringBuilder builder, PlaceholderState state, ulong value) + private static void Replace(StringBuilder builder, PlaceholderState state, ulong value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, float value) + private static void Replace(StringBuilder builder, PlaceholderState state, float value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, double value) + private static void Replace(StringBuilder builder, PlaceholderState state, double value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, decimal value) + private static void Replace(StringBuilder builder, PlaceholderState state, decimal value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, DateTime value) + private static void Replace(StringBuilder builder, PlaceholderState state, DateTime value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, DateTimeOffset value) + private static void Replace(StringBuilder builder, PlaceholderState state, DateTimeOffset value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - private static void Replace(StringBuilder builder, PlaceholderState state, TimeSpan value) + private static void Replace(StringBuilder builder, PlaceholderState state, TimeSpan value) + { + Span span = Buffer.Value.AsSpan(); + if (value.TryFormat(span, out int written, state.Format)) { - Span span = Buffer.Value.AsSpan(); - if (value.TryFormat(span, out int written, state.Format)) - { - Replace(builder, state, span.Slice(0, written)); - } - else - { - Replace(builder, state, value as IFormattable); - } + Replace(builder, state, span.Slice(0, written)); + } + else + { + Replace(builder, state, value as IFormattable); } + } - /// - /// Replace the with the the string value - /// - /// for the placeholder - /// for the placeholder - /// value to use with formatting - private static void Replace(StringBuilder builder, PlaceholderState state, IFormattable value) + /// + /// Replace the with the the string value + /// + /// for the placeholder + /// for the placeholder + /// value to use with formatting + private static void Replace(StringBuilder builder, PlaceholderState state, IFormattable value) + { + if (string.IsNullOrEmpty(state.Format)) { - if (string.IsNullOrEmpty(state.Format)) - { - Replace(builder, state, value.ToString(null, CultureInfo.CurrentCulture)); - return; - } + Replace(builder, state, value.ToString(null, CultureInfo.CurrentCulture)); + return; + } - Replace(builder, state, value.ToString(state.Format, CultureInfo.CurrentCulture)); + Replace(builder, state, value.ToString(state.Format, CultureInfo.CurrentCulture)); + } + + /// + /// Replace the with the formatted position + /// + /// for the placeholder + /// for the placeholder + /// position to format and replace + private static void Replace(StringBuilder builder, PlaceholderState placeholderState, GenericPosition position) + { + if (string.IsNullOrEmpty(placeholderState.Format)) + { + Replace(builder, placeholderState, $"{position.X} {position.Y} {position.Z}".AsSpan()); + return; } - /// - /// Replace the with the formatted position - /// - /// for the placeholder - /// for the placeholder - /// position to format and replace - private static void Replace(StringBuilder builder, PlaceholderState placeholderState, GenericPosition position) + StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); + PlaceholderState positionState = PlaceholderState.Create(placeholderState.Data); + sb.Append(placeholderState.Format); + MatchCollection matches = GenericPositionRegex.Matches(placeholderState.Format); + for (int index = matches.Count - 1; index >= 0; index--) { - if (string.IsNullOrEmpty(placeholderState.Format)) - { - Replace(builder, placeholderState, $"{position.X} {position.Y} {position.Z}".AsSpan()); - return; + Match match = matches[index]; + positionState.UpdateState(match); + switch (match.Groups[1].Value) + { + case "x": + Replace(sb, positionState, position.X); + break; + case "y": + Replace(sb, positionState, position.Y); + break; + case "z": + Replace(sb, positionState, position.Z); + break; } + } - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); - PlaceholderState positionState = PlaceholderState.Create(placeholderState.Data); - sb.Append(placeholderState.Format); - MatchCollection matches = GenericPositionRegex.Matches(placeholderState.Format); - for (int index = matches.Count - 1; index >= 0; index--) - { - Match match = matches[index]; - positionState.UpdateState(match); - switch (match.Groups[1].Value) - { - case "x": - Replace(sb, positionState, position.X); - break; - case "y": - Replace(sb, positionState, position.Y); - break; - case "z": - Replace(sb, positionState, position.Z); - break; - } - } + Replace(builder, placeholderState, sb.ToString()); + DiscordPool.Internal.FreeStringBuilder(sb); + positionState.Dispose(); + } - Replace(builder, placeholderState, sb.ToString()); - DiscordPool.Internal.FreeStringBuilder(sb); - positionState.Dispose(); - } - - public static Action CreatePlaceholderCallback() - { - Type type = typeof(TResult); - if (type == typeof(string)) return (builder, state, value) => Replace(builder, state, value as string); - if (type == typeof(bool)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(byte)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(sbyte)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(short)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(ushort)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(int)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(uint)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(long)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(ulong)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(float)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(double)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(decimal)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(DateTime)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(DateTimeOffset)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(TimeSpan)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(Snowflake)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (type == typeof(TemplateKey)) return (builder, state, value) => Replace(builder, state, value.Cast().Name); - if (type == typeof(GenericPosition)) return (builder, state, value) => Replace(builder, state, value.Cast()); - if (typeof(IFormattable).IsAssignableFrom(type)) return (builder, state, value) => Replace(builder, state, value as IFormattable); - if (typeof(IReadOnlyList).IsAssignableFrom(type)) return (builder, state, value) => Replace(builder, state, value as IReadOnlyList); - if (typeof(IReadOnlyList).IsAssignableFrom(type)) return (builder, state, value) => Replace(builder, state, value as IReadOnlyList); - - return (builder, state, value) => Replace(builder, state, value.ToString()); - } + public static Action CreatePlaceholderCallback() + { + Type type = typeof(TResult); + if (type == typeof(string)) return (builder, state, value) => Replace(builder, state, value as string); + if (type == typeof(bool)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(byte)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(sbyte)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(short)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(ushort)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(int)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(uint)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(long)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(ulong)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(float)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(double)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(decimal)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(DateTime)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(DateTimeOffset)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(TimeSpan)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(Snowflake)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (type == typeof(TemplateKey)) return (builder, state, value) => Replace(builder, state, value.Cast().Name); + if (type == typeof(GenericPosition)) return (builder, state, value) => Replace(builder, state, value.Cast()); + if (typeof(IFormattable).IsAssignableFrom(type)) return (builder, state, value) => Replace(builder, state, value as IFormattable); + if (typeof(IReadOnlyList).IsAssignableFrom(type)) return (builder, state, value) => Replace(builder, state, value as IReadOnlyList); + if (typeof(IReadOnlyList).IsAssignableFrom(type)) return (builder, state, value) => Replace(builder, state, value as IReadOnlyList); + + return (builder, state, value) => Replace(builder, state, value.ToString()); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderKey.cs b/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderKey.cs index a7c6e85a0..d06b44bd4 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderKey.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderKey.cs @@ -1,77 +1,69 @@ using System; +using System.Diagnostics.Contracts; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a Placeholder Key. This is the key for placeholder usage and lookup +/// +public readonly record struct PlaceholderKey : IComparable, IDiscordKey { /// - /// Represents a Placeholder Key. This is the key for placeholder usage and lookup + /// Placeholder Key /// - public struct PlaceholderKey : IEquatable, IComparable, IDiscordKey - { - /// - /// Placeholder Key - /// - public readonly string Placeholder; + public readonly string Placeholder; - /// - /// If Is a Valid Key - /// - public bool IsValid => !string.IsNullOrEmpty(Placeholder); + /// + /// If Is a Valid Key + /// + public bool IsValid => !string.IsNullOrEmpty(Placeholder); - /// - /// Constructor - /// - /// Placeholder Value - public PlaceholderKey(string placeholder) - { - Placeholder = placeholder; - } + /// + /// Constructor + /// + /// Placeholder Value + public PlaceholderKey(string placeholder) + { + Placeholder = placeholder; + } - /// - /// Constructor - /// - /// - /// Prefix for the placeholder Key. - /// Pass in the nameof the plugin type for the Placeholder key - /// nameof(DiscordExtension) - /// - /// Placeholder Value - /// Format to be applied (Optional) - public PlaceholderKey(string prefix, string key, string format = null) - { - Placeholder = string.IsNullOrEmpty(format) ? $"{prefix.ToLower()}.{key}" : $"{prefix.ToLower()}.{key}:{format}"; - } + /// + /// Constructor + /// + /// + /// Prefix for the placeholder Key. + /// Pass in the nameof the plugin type for the Placeholder key + /// nameof(DiscordExtension) + /// + /// Placeholder Value + /// Format to be applied (Optional) + public PlaceholderKey(string prefix, string key, string format = null) + { + Placeholder = string.IsNullOrEmpty(format) ? $"{prefix.ToLower()}.{key}" : $"{prefix.ToLower()}.{key}:{format}"; + } - /// - /// Applies a format to a given - /// - /// Format to be applied - /// string placeholder containing the placeholder with the given format - public string WithFormat(string format) => $"{{{Placeholder}:{format}}}"; - - /// - /// Returns the PlaceholderKey formatted as a usable placeholder in text - /// - /// - public override string ToString() => $"{{{Placeholder}}}"; - - /// - public bool Equals(PlaceholderKey other) => Placeholder == other.Placeholder; - - /// - public override bool Equals(object obj) => obj is PlaceholderKey other && Equals(other); + /// + /// Applies a format to a given + /// + /// Format to be applied + /// string placeholder containing the placeholder with the given format + [Pure] + public string WithFormat(string format) => $"{{{Placeholder}:{format}}}"; - /// - public override int GetHashCode() => Placeholder != null ? Placeholder.GetHashCode() : 0; + /// + /// Returns the PlaceholderKey formatted as a usable placeholder in text + /// + /// + public override string ToString() => $"{{{Placeholder}}}"; - /// - public int CompareTo(PlaceholderKey other) => string.Compare(Placeholder, other.Placeholder, StringComparison.OrdinalIgnoreCase); + /// + public int CompareTo(PlaceholderKey other) => string.Compare(Placeholder, other.Placeholder, StringComparison.OrdinalIgnoreCase); - /// - /// Implicitly converts to by calling the method. - /// - /// - /// - public static implicit operator string(PlaceholderKey key) => key.ToString(); - } + /// + /// Implicitly converts to by calling the method. + /// + /// + /// + public static implicit operator string(PlaceholderKey key) => key.ToString(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderState.cs b/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderState.cs index 3739ba434..f2b1cdf50 100644 --- a/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderState.cs +++ b/Oxide.Ext.Discord/Libraries/Placeholders/PlaceholderState.cs @@ -1,73 +1,72 @@ using System.Text.RegularExpressions; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents the current state for a matched placeholder +/// +public class PlaceholderState : BasePoolable { /// - /// Represents the current state for a matched placeholder + /// Placeholder Data for the state /// - public class PlaceholderState : BasePoolable - { - /// - /// Placeholder Data for the state - /// - public PlaceholderData Data { get; private set; } + public PlaceholderData Data { get; private set; } - /// - /// Key of the placeholder - /// - public PlaceholderKey Key { get; private set; } + /// + /// Key of the placeholder + /// + public PlaceholderKey Key { get; private set; } - /// - /// Format specified in the placeholder - /// - public string Format { get; private set; } + /// + /// Format specified in the placeholder + /// + public string Format { get; private set; } - /// - /// Index in the string of the placeholder - /// - internal ushort Index; + /// + /// Index in the string of the placeholder + /// + internal ushort Index; - /// - /// Length of the placeholder - /// - internal ushort Length; + /// + /// Length of the placeholder + /// + internal ushort Length; - /// - /// Creates a pooled - /// - /// Data to be used in the state - /// - internal static PlaceholderState Create(PlaceholderData data) - { - PlaceholderState state = DiscordPool.Internal.Get(); - state.Init(data); - return state; - } + /// + /// Creates a pooled + /// + /// Data to be used in the state + /// + internal static PlaceholderState Create(PlaceholderData data) + { + PlaceholderState state = DiscordPool.Internal.Get(); + state.Init(data); + return state; + } - private void Init(PlaceholderData data) - { - Data = data; - } + private void Init(PlaceholderData data) + { + Data = data; + } - internal void UpdateState(Match match) - { - GroupCollection groups = match.Groups; - Key = new PlaceholderKey(groups[1].Value); - Group formatGroup = groups[2]; - Format = formatGroup.Success ? formatGroup.Value : null; - Index = (ushort)match.Index; - Length = (ushort)match.Length; - } + internal void UpdateState(Match match) + { + GroupCollection groups = match.Groups; + Key = new PlaceholderKey(groups[1].Value); + Group formatGroup = groups[2]; + Format = formatGroup.Success ? formatGroup.Value : null; + Index = (ushort)match.Index; + Length = (ushort)match.Length; + } - /// - protected override void EnterPool() - { - Data = null; - Key = default(PlaceholderKey); - Format = null; - Index = default(ushort); - Length = default(ushort); - } + /// + protected override void EnterPool() + { + Data = null; + Key = default; + Format = null; + Index = default; + Length = default; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Pooling/DiscordPool.cs b/Oxide.Ext.Discord/Libraries/Pooling/DiscordPool.cs index f8255c870..33ee127fa 100644 --- a/Oxide.Ext.Discord/Libraries/Pooling/DiscordPool.cs +++ b/Oxide.Ext.Discord/Libraries/Pooling/DiscordPool.cs @@ -1,6 +1,6 @@ using System; using Oxide.Core.Plugins; -using Oxide.Ext.Discord.Connections; +using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; @@ -8,101 +8,100 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Discord Pool Library +/// +public class DiscordPool : BaseDiscordLibrary, IDebugLoggable { + private readonly Hash _pluginPools = new(); + internal static DiscordPluginPool Internal; + private readonly ILogger _logger; + + internal DiscordPool(ILogger logger) + { + _logger = logger; + } + /// - /// Discord Pool Library + /// Returns an existing for the given plugin or returns a new one /// - public class DiscordPool : BaseDiscordLibrary, IDebugLoggable + /// The pool the plugin is for + /// + /// Thrown if the plugin is null + public DiscordPluginPool GetOrCreate(Plugin plugin) { - private readonly Hash _pluginPools = new Hash(); - internal static DiscordPluginPool Internal; - private readonly ILogger _logger; + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + return CreatePoolInternal(plugin); + } - internal DiscordPool(ILogger logger) - { - _logger = logger; - } - - /// - /// Returns an existing for the given plugin or returns a new one - /// - /// The pool the plugin is for - /// - /// Thrown if the plugin is null - public DiscordPluginPool GetOrCreate(Plugin plugin) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - return CreatePoolInternal(plugin); - } + internal void CreateInternal(Plugin plugin) + { + Internal = CreatePoolInternal(plugin); + Internal.SetSettings(PoolSettings.CreateInternal()); + } - internal void CreateInternal(Plugin plugin) + private DiscordPluginPool CreatePoolInternal(Plugin plugin) + { + PluginId id = plugin.Id(); + DiscordPluginPool pool = _pluginPools[id]; + if (pool == null) { - Internal = CreatePoolInternal(plugin); - Internal.SetSettings(PoolSettings.CreateInternal()); + pool = new DiscordPluginPool(plugin); + _pluginPools[id] = pool; } - - private DiscordPluginPool CreatePoolInternal(Plugin plugin) - { - PluginId id = plugin.Id(); - DiscordPluginPool pool = _pluginPools[id]; - if (pool == null) - { - pool = new DiscordPluginPool(plugin); - _pluginPools[id] = pool; - } - return pool; - } + return pool; + } - /// - protected override void OnPluginLoaded(PluginSetup data, BotConnection connection) + /// + protected override void OnPluginLoaded(DiscordClient client) + { + // ReSharper disable once SuspiciousTypeConversion.Global + if (client.Plugin is IDiscordPool pool) { - // ReSharper disable once SuspiciousTypeConversion.Global - if (data.Plugin is IDiscordPool pool) - { - pool.Pool = GetOrCreate(data.Plugin); - } + pool.Pool = GetOrCreate(client.Plugin); } + } - /// - protected override void OnPluginUnloaded(Plugin plugin) + /// + protected override void OnPluginUnloaded(Plugin plugin) + { + PluginId id = plugin.Id(); + DiscordPluginPool pool = _pluginPools[id]; + if (pool != null) { - PluginId id = plugin.Id(); - DiscordPluginPool pool = _pluginPools[id]; - if (pool != null) - { - pool.OnPluginUnloaded(); - _pluginPools.Remove(id); - } + pool.OnPluginUnloaded(); + _pluginPools.Remove(id); } + } - internal void Clear() + internal void Clear() + { + foreach (DiscordPluginPool pool in _pluginPools.Values) { - foreach (DiscordPluginPool pool in _pluginPools.Values) - { - pool.Clear(); - } + pool.Clear(); } + } - internal void Wipe() + internal void Wipe() + { + foreach (DiscordPluginPool pool in _pluginPools.Values) { - foreach (DiscordPluginPool pool in _pluginPools.Values) - { - pool.Wipe(); - } + pool.Wipe(); } + } - /// - public void LogDebug(DebugLogger logger) + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendObject("Internal", Internal); + foreach (DiscordPluginPool pool in _pluginPools.Values) { - logger.AppendObject("Internal", Internal); - foreach (DiscordPluginPool pool in _pluginPools.Values) + if (pool != Internal) { - if (pool != Internal) - { - logger.AppendObject(pool.PluginName, pool); - } + logger.AppendObject(pool.PluginName, pool); } } } diff --git a/Oxide.Ext.Discord/Libraries/Subscription/DiscordSubscription.cs b/Oxide.Ext.Discord/Libraries/Subscription/DiscordSubscription.cs index b42481751..102854abe 100644 --- a/Oxide.Ext.Discord/Libraries/Subscription/DiscordSubscription.cs +++ b/Oxide.Ext.Discord/Libraries/Subscription/DiscordSubscription.cs @@ -9,102 +9,101 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a channel subscription for a plugin +/// +public class DiscordSubscription : IDebugLoggable { + private readonly Snowflake _channelId; + private readonly PluginId _pluginId; + private readonly DiscordClient _client; + private readonly Action _callback; + + private Plugin _plugin; + /// - /// Represents a channel subscription for a plugin + /// Constructor /// - public class DiscordSubscription : IDebugLoggable + /// Discord Client for the subscription + /// ID of the channel + /// Callback when the channel message is sent + public DiscordSubscription(DiscordClient client, Snowflake channelId, Action callback) { - private readonly Snowflake _channelId; - private readonly PluginId _pluginId; - private readonly DiscordClient _client; - private readonly Action _callback; - - private Plugin _plugin; + _client = client; + _plugin = client.Plugin; + _channelId = channelId; + _pluginId = _plugin.Id(); + _callback = callback; + } - /// - /// Constructor - /// - /// Discord Client for the subscription - /// ID of the channel - /// Callback when the channel message is sent - public DiscordSubscription(DiscordClient client, Snowflake channelId, Action callback) - { - _client = client; - _plugin = client.Plugin; - _channelId = channelId; - _pluginId = _plugin.Id(); - _callback = callback; - } + /// + /// Returns if a subscription can run. + /// They can only run for the client that they were created for. + /// + /// Client to compare against + /// True if same bot client; false otherwise + public bool CanRun(BotClient client) + { + return client != null && _client.Bot == client; + } - /// - /// Returns if a subscription can run. - /// They can only run for the client that they were created for. - /// - /// Client to compare against - /// True if same bot client; false otherwise - public bool CanRun(BotClient client) - { - return client != null && _client.Bot == client; - } + /// + /// Returns if this subscription is for this plugin + /// + /// Plugin to check + /// True if the subscription is for this plugin; False otherwise + public bool IsForPlugin(Plugin plugin) => plugin != null && plugin.Id() == _pluginId; - /// - /// Returns if this subscription is for this plugin - /// - /// Plugin to check - /// True if the subscription is for this plugin; False otherwise - public bool IsForPlugin(Plugin plugin) => plugin != null && plugin.Id() == _pluginId; + /// + /// Returns if this subscription is for the given channel + /// + /// Channel ID to check + /// True if the subscription is for this channel; False otherwise + public bool IsForChannel(Snowflake channelId) => _channelId == channelId; - /// - /// Returns if this subscription is for the given channel - /// - /// Channel ID to check - /// True if the subscription is for this channel; False otherwise - public bool IsForChannel(Snowflake channelId) => _channelId == channelId; + /// + /// Invokes the callback with the message + /// + /// Message that was sent in the given channel + public void Invoke(DiscordMessage message) + { + SubscriptionCallback.Start(_plugin, message, _callback); + } - /// - /// Invokes the callback with the message - /// - /// Message that was sent in the given channel - public void Invoke(DiscordMessage message) + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("Plugin", _plugin.FullName()); + logger.AppendMethod("Method", _callback.Method); + + DiscordGuild guild = _client?.Bot.Servers.Values.FirstOrDefault(g => g.Channels.ContainsKey(_channelId)); + if (guild == null) { - SubscriptionCallback.Start(_plugin, message, _callback); + logger.AppendField("Guild", "Unknown Guild"); + return; } - - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendField("Plugin", _plugin.FullName()); - logger.AppendMethod("Method", _callback.Method); - DiscordGuild guild = _client?.Bot.Servers.Values.FirstOrDefault(g => g.Channels.ContainsKey(_channelId)); - if (guild == null) - { - logger.AppendField("Guild", "Unknown Guild"); - return; - } - - DiscordChannel channel = guild.Channels[_channelId]; - if (channel == null) - { - logger.AppendField("Channel", "Unknown Channel"); - return; - } - - DiscordChannel parent = null; - if (channel.ParentId.HasValue) - { - parent = guild.Channels[channel.ParentId.Value]; - } - - logger.AppendChannelPath("Path", guild, channel, parent); - logger.AppendObject("Channel", channel); + DiscordChannel channel = guild.Channels[_channelId]; + if (channel == null) + { + logger.AppendField("Channel", "Unknown Channel"); + return; } - internal void OnRemoved() + DiscordChannel parent = null; + if (channel.ParentId.HasValue) { - _plugin = null; + parent = guild.Channels[channel.ParentId.Value]; } + + logger.AppendChannelPath("Path", guild, channel, parent); + logger.AppendObject("Channel", channel); + } + + internal void OnRemoved() + { + _plugin = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Subscription/DiscordSubscriptions.cs b/Oxide.Ext.Discord/Libraries/Subscription/DiscordSubscriptions.cs index c4a71ba9e..8739bf6ea 100644 --- a/Oxide.Ext.Discord/Libraries/Subscription/DiscordSubscriptions.cs +++ b/Oxide.Ext.Discord/Libraries/Subscription/DiscordSubscriptions.cs @@ -10,167 +10,166 @@ using Oxide.Ext.Discord.Logging; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents Discord Subscriptions Oxide Library +/// Allows for plugins to subscribe to discord channels +/// +public class DiscordSubscriptions : BaseDiscordLibrary, IDebugLoggable { + private readonly Hash> _subscriptions = new(); + + private readonly ILogger _logger; + /// - /// Represents Discord Subscriptions Oxide Library - /// Allows for plugins to subscribe to discord channels + /// DiscordSubscriptions Constructor /// - public class DiscordSubscriptions : BaseDiscordLibrary, IDebugLoggable + /// Logger + internal DiscordSubscriptions(ILogger logger) { - private readonly Hash> _subscriptions = new Hash>(); + _logger = logger; + } - private readonly ILogger _logger; + /// + /// Returns if any subscriptions have been registered + /// + /// True if there are any subscriptions; False otherwise + [LibraryFunction(nameof(HasSubscriptions))] + public bool HasSubscriptions() + { + return _subscriptions.Count != 0; + } - /// - /// DiscordSubscriptions Constructor - /// - /// Logger - internal DiscordSubscriptions(ILogger logger) - { - _logger = logger; - } + /// + /// Allows a plugin to add a subscription to a discord channel + /// + /// Client that is subscribing + /// Channel ID of the channel + /// Callback with the message that was created in the channel + /// Exception if plugin or message is null + /// Exception if Channel ID is not valid + [LibraryFunction(nameof(AddChannelSubscription))] + public void AddChannelSubscription(DiscordClient client, Snowflake channelId, Action message) + { + InvalidSnowflakeException.ThrowIfInvalid(channelId); + if (client == null) throw new ArgumentNullException(nameof(client)); + if (message == null) throw new ArgumentNullException(nameof(message)); + + Plugin plugin = client.Plugin; + _logger.Debug($"{nameof(DiscordSubscriptions)}.{nameof(AddChannelSubscription)} {{0}} added subscription to channel {{1}}", plugin.FullName(), channelId); - /// - /// Returns if any subscriptions have been registered - /// - /// True if there are any subscriptions; False otherwise - [LibraryFunction(nameof(HasSubscriptions))] - public bool HasSubscriptions() + List subs = _subscriptions[channelId]; + if (subs == null) { - return _subscriptions.Count != 0; + subs = new List(); + _subscriptions[channelId] = subs; } + + subs.RemoveAll(s => s.IsForPlugin(plugin)); + subs.Add(new DiscordSubscription(client, channelId, message)); + } - /// - /// Allows a plugin to add a subscription to a discord channel - /// - /// Client that is subscribing - /// Channel ID of the channel - /// Callback with the message that was created in the channel - /// Exception if plugin or message is null - /// Exception if Channel ID is not valid - [LibraryFunction(nameof(AddChannelSubscription))] - public void AddChannelSubscription(DiscordClient client, Snowflake channelId, Action message) + /// + /// Removes a subscribed channel for a plugin + /// + /// Plugin to remove the subscription for + /// Channel ID to remove + /// Exception if plugin is null + /// Exception if channel ID is not valid + [LibraryFunction(nameof(RemoveChannelSubscription))] + public void RemoveChannelSubscription(Plugin plugin, Snowflake channelId) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + InvalidSnowflakeException.ThrowIfInvalid(channelId); + + List subs = _subscriptions[channelId]; + if (subs == null) { - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - if (client == null) throw new ArgumentNullException(nameof(client)); - if (message == null) throw new ArgumentNullException(nameof(message)); - - Plugin plugin = client.Plugin; - _logger.Debug($"{nameof(DiscordSubscriptions)}.{nameof(AddChannelSubscription)} {{0}} added subscription to channel {{1}}", plugin.FullName(), channelId); + return; + } - List subs = _subscriptions[channelId]; - if (subs == null) - { - subs = new List(); - _subscriptions[channelId] = subs; - } + subs.RemoveAll(s => s.IsForPlugin(plugin) && s.IsForChannel(channelId)); + _logger.Debug($"{nameof(DiscordSubscriptions)}.{nameof(RemoveChannelSubscription)} {{0}} removed subscription to channel {{1}}", plugin.Id(), channelId); + } - subs.RemoveAll(s => s.IsForPlugin(plugin)); - subs.Add(new DiscordSubscription(client, channelId, message)); - } + /// + protected override void OnPluginUnloaded(Plugin plugin) + { + RemovePluginSubscriptions(plugin); + } - /// - /// Removes a subscribed channel for a plugin - /// - /// Plugin to remove the subscription for - /// Channel ID to remove - /// Exception if plugin is null - /// Exception if channel ID is not valid - [LibraryFunction(nameof(RemoveChannelSubscription))] - public void RemoveChannelSubscription(Plugin plugin, Snowflake channelId) + /// + /// Remove all subscriptions for a plugin + /// + /// Plugin to remove subscriptions for + /// Exception if plugin is null + public void RemovePluginSubscriptions(Plugin plugin) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + + List emptySubs = []; + foreach (KeyValuePair> hash in _subscriptions) { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - InvalidSnowflakeException.ThrowIfInvalid(channelId, nameof(channelId)); - - List subs = _subscriptions[channelId]; - if (subs == null) + RemoveChannelSubscription(plugin, hash.Key); + if (hash.Value.Count == 0) { - return; + emptySubs.Add(hash.Key); } - - subs.RemoveAll(s => s.IsForPlugin(plugin) && s.IsForChannel(channelId)); - _logger.Debug($"{nameof(DiscordSubscriptions)}.{nameof(RemoveChannelSubscription)} {{0}} removed subscription to channel {{1}}", plugin.Id(), channelId); } - /// - protected override void OnPluginUnloaded(Plugin plugin) - { - RemovePluginSubscriptions(plugin); - } - - /// - /// Remove all subscriptions for a plugin - /// - /// Plugin to remove subscriptions for - /// Exception if plugin is null - public void RemovePluginSubscriptions(Plugin plugin) + if (emptySubs.Count != 0) { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - - List emptySubs = new List(); - foreach (KeyValuePair> hash in _subscriptions) + for (int i = 0; i < emptySubs.Count; i++) { - RemoveChannelSubscription(plugin, hash.Key); - if (hash.Value.Count == 0) - { - emptySubs.Add(hash.Key); - } + Snowflake emptySub = emptySubs[i]; + _subscriptions.Remove(emptySub); } - - if (emptySubs.Count != 0) - { - for (int i = 0; i < emptySubs.Count; i++) - { - Snowflake emptySub = emptySubs[i]; - _subscriptions.Remove(emptySub); - } - } - - _logger.Debug($"{nameof(DiscordSubscriptions)}.{nameof(RemovePluginSubscriptions)} Removed subscriptions for plugin {{0}}", plugin.FullName()); } + + _logger.Debug($"{nameof(DiscordSubscriptions)}.{nameof(RemovePluginSubscriptions)} Removed subscriptions for plugin {{0}}", plugin.FullName()); + } - internal void HandleMessage(DiscordMessage message, DiscordChannel channel, BotClient client) - { - RunSubs(_subscriptions[message.ChannelId], message, client); + internal void HandleMessage(DiscordMessage message, DiscordChannel channel, BotClient client) + { + RunSubs(_subscriptions[message.ChannelId], message, client); - if (channel.ParentId != null) - { - RunSubs(_subscriptions[channel.ParentId.Value], message, client); - } + if (channel.ParentId != null) + { + RunSubs(_subscriptions[channel.ParentId.Value], message, client); } + } - private void RunSubs(List subs, DiscordMessage message, BotClient client) + private void RunSubs(List subs, DiscordMessage message, BotClient client) + { + if (subs == null) { - if (subs == null) - { - return; - } + return; + } - for (int index = 0; index < subs.Count; index++) + for (int index = 0; index < subs.Count; index++) + { + DiscordSubscription sub = subs[index]; + if (sub.CanRun(client)) { - DiscordSubscription sub = subs[index]; - if (sub.CanRun(client)) - { - sub.Invoke(message); - } + sub.Invoke(message); } } + } - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendList("Subscriptions", GetSubscriptions()); - } + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendList("Subscriptions", GetSubscriptions()); + } - private IEnumerable GetSubscriptions() + private IEnumerable GetSubscriptions() + { + foreach (List pluginSubscriptions in _subscriptions.Values) { - foreach (List pluginSubscriptions in _subscriptions.Values) + for (int index = 0; index < pluginSubscriptions.Count; index++) { - for (int index = 0; index < pluginSubscriptions.Count; index++) - { - yield return pluginSubscriptions[index]; - } + yield return pluginSubscriptions[index]; } } } diff --git a/Oxide.Ext.Discord/Libraries/Templates/AutoComplete/DiscordAutoCompleteChoiceTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/AutoComplete/DiscordAutoCompleteChoiceTemplate.cs index a09b0d8fe..dcc2ef5ac 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/AutoComplete/DiscordAutoCompleteChoiceTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/AutoComplete/DiscordAutoCompleteChoiceTemplate.cs @@ -2,41 +2,40 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Extensions; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Template for Discord Auto Completes +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordAutoCompleteChoiceTemplate { /// - /// Template for Discord Auto Completes + /// Choice Text (1-100 characters) /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordAutoCompleteChoiceTemplate - { - /// - /// Choice Text (1-100 characters) - /// - [JsonProperty("Choice Text")] - public string Name { get; set; } + [JsonProperty("Choice Text")] + public string Name { get; set; } - /// - /// Apply localizations to the auto complete choice - /// - /// DiscordLocale being applied - /// Choice to apply the template to - /// Placeholders for be applied - public void ApplyLocalization(DiscordLocale locale, CommandOptionChoice choice, PlaceholderData data = null) - { - string name = DiscordPlaceholders.Instance.ProcessPlaceholders(Name, data); - choice.NameLocalizations[locale.Id] = name.TrimIfLargerThan(100); - } + /// + /// Apply localizations to the auto complete choice + /// + /// DiscordLocale being applied + /// Choice to apply the template to + /// Placeholders for be applied + public void ApplyLocalization(DiscordLocale locale, CommandOptionChoice choice, PlaceholderData data = null) + { + string name = DiscordPlaceholders.Instance.ProcessPlaceholders(Name, data); + choice.NameLocalizations[locale.Id] = name.TrimIfLargerThan(100); + } - /// - /// Apply the name to the auto complete choice - /// - /// Choice to apply the template to - /// Placeholders for be applied - public void ApplyName(CommandOptionChoice choice, PlaceholderData data = null) - { - string name = DiscordPlaceholders.Instance.ProcessPlaceholders(Name, data); - choice.Name = name.TrimIfLargerThan(100); - } + /// + /// Apply the name to the auto complete choice + /// + /// Choice to apply the template to + /// Placeholders for be applied + public void ApplyName(CommandOptionChoice choice, PlaceholderData data = null) + { + string name = DiscordPlaceholders.Instance.ProcessPlaceholders(Name, data); + choice.Name = name.TrimIfLargerThan(100); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/AutoComplete/DiscordAutoCompleteChoiceTemplates.cs b/Oxide.Ext.Discord/Libraries/Templates/AutoComplete/DiscordAutoCompleteChoiceTemplates.cs index 4d71f027a..2b0fcf9ac 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/AutoComplete/DiscordAutoCompleteChoiceTemplates.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/AutoComplete/DiscordAutoCompleteChoiceTemplates.cs @@ -12,265 +12,252 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Auto Complete Choice Templates Library +/// +public class DiscordAutoCompleteChoiceTemplates : BaseTemplateLibrary { + private readonly ConcurrentDictionary _globalCache = new(); + private readonly ConcurrentDictionary> _localizedCache = new(); + /// - /// Auto Complete Choice Templates Library + /// Constructor /// - public class DiscordAutoCompleteChoiceTemplates : BaseTemplateLibrary - { - private readonly ConcurrentDictionary _globalCache = new ConcurrentDictionary(); - private readonly ConcurrentDictionary> _localizedCache = new ConcurrentDictionary>(); + /// + public DiscordAutoCompleteChoiceTemplates(ILogger logger) : base(TemplateType.AutoCompleteChoice, logger) { } - /// - /// Constructor - /// - /// - public DiscordAutoCompleteChoiceTemplates(ILogger logger) : base(TemplateType.AutoCompleteChoice, logger) { } + /// + /// Registers a global template for Auto Complete Choices + /// + /// Plugin the template is for + /// Name of the template + /// The template to register + /// Current version of the template + /// Minimum supported version of the template + /// + /// Throw if plugin or templateName is null + public IPromise RegisterGlobalTemplate(Plugin plugin, TemplateKey templateName, DiscordAutoCompleteChoiceTemplate template, TemplateVersion version, TemplateVersion minVersion) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - /// - /// Registers a global template for Auto Complete Choices - /// - /// Plugin the template is for - /// Name of the template - /// The template to register - /// Current version of the template - /// Minimum supported version of the template - /// - /// Throw if plugin or templateName is null - public IPromise RegisterGlobalTemplate(Plugin plugin, TemplateKey templateName, DiscordAutoCompleteChoiceTemplate template, TemplateVersion version, TemplateVersion minVersion) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + TemplateId id = TemplateId.CreateGlobal(plugin, templateName); + return RegisterTemplate(id, template, version, minVersion); + } - TemplateId id = TemplateId.CreateGlobal(plugin, templateName); - return RegisterTemplate(id, template, version, minVersion); - } + /// + /// Registers a global template for Auto Complete Choices + /// + /// Plugin the template is for + /// Name of the template + /// The template to register + /// Current version of the template + /// Minimum supported version of the template + /// Server Language for the localized template + /// + /// Throw if plugin, templateName, or language is null/empty + public IPromise RegisterLocalizedTemplate(Plugin plugin, TemplateKey templateName, DiscordAutoCompleteChoiceTemplate template, TemplateVersion version, TemplateVersion minVersion, string language = DiscordLocales.DefaultServerLanguage) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); - /// - /// Registers a global template for Auto Complete Choices - /// - /// Plugin the template is for - /// Name of the template - /// The template to register - /// Current version of the template - /// Minimum supported version of the template - /// Server Language for the localized template - /// - /// Throw if plugin, templateName, or language is null/empty - public IPromise RegisterLocalizedTemplate(Plugin plugin, TemplateKey templateName, DiscordAutoCompleteChoiceTemplate template, TemplateVersion version, TemplateVersion minVersion, string language = DiscordLocales.DefaultServerLanguage) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + TemplateId id = TemplateId.CreateLocalized(plugin, templateName, ServerLocale.Parse(language)); + return RegisterTemplate(id, template, version, minVersion); + } - TemplateId id = TemplateId.CreateLocalized(plugin, templateName, ServerLocale.Parse(language)); - return RegisterTemplate(id, template, version, minVersion); - } + private IPromise RegisterTemplate(TemplateId id, DiscordAutoCompleteChoiceTemplate template, TemplateVersion version, TemplateVersion minVersion) + { + if (template == null) throw new ArgumentNullException(nameof(template)); + IPendingPromise promise = Promise.Create(); + RegisterTemplateCallback.Start(this, id, template, version, minVersion, promise); + return promise; + } - private IPromise RegisterTemplate(TemplateId id, DiscordAutoCompleteChoiceTemplate template, TemplateVersion version, TemplateVersion minVersion) + /// + /// Returns a global Auto Complete Template for the given plugin and template name + /// + /// Plugin for the template + /// Name of the template + /// + public DiscordAutoCompleteChoiceTemplate GetGlobalTemplate(Plugin plugin, TemplateKey templateName) + { + TemplateId id = TemplateId.CreateGlobal(plugin, templateName); + if (_globalCache.TryGetValue(id, out DiscordAutoCompleteChoiceTemplate cached)) { - if (template == null) throw new ArgumentNullException(nameof(template)); - IPendingPromise promise = Promise.Create(); - RegisterTemplateCallback.Start(this, id, template, version, minVersion, promise); - return promise; + return cached; } - /// - /// Returns a global Auto Complete Template for the given plugin and template name - /// - /// Plugin for the template - /// Name of the template - /// - public DiscordAutoCompleteChoiceTemplate GetGlobalTemplate(Plugin plugin, TemplateKey templateName) - { - TemplateId id = TemplateId.CreateGlobal(plugin, templateName); - if (_globalCache.TryGetValue(id, out DiscordAutoCompleteChoiceTemplate cached)) - { - return cached; - } - - DiscordTemplate template = LoadTemplate(id); + DiscordTemplate template = LoadTemplate(id); - if (template == null) - { - Logger.Error("Plugin {0} is using the {1} Template API but message template name '{2}' is not registered", id.GetPluginName(), GetType().GetRealTypeName(), id.TemplateName); - return new DiscordAutoCompleteChoiceTemplate(); - } + if (template == null) + { + Logger.Error("Plugin {0} is using the {1} Template API but message template name '{2}' is not registered", id.GetPluginName(), GetType().GetRealTypeName(), id.TemplateName); + return new DiscordAutoCompleteChoiceTemplate(); + } - SetCache(id, template.Template); + SetCache(id, template.Template); - return template.Template; - } + return template.Template; + } - /// - /// Applies a Global Template to a with optional placeholders - /// - /// Plugin for the template - /// Name of the template - /// Choice to be applied to - /// Placeholders to apply - /// - /// Thrown if plugin or templateName is null/empty - public CommandOptionChoice ApplyGlobal(Plugin plugin, TemplateKey templateName, CommandOptionChoice choice = null, PlaceholderData placeholders = null) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + /// + /// Applies a Global Template to a with optional placeholders + /// + /// Plugin for the template + /// Name of the template + /// Choice to be applied to + /// Placeholders to apply + /// + /// Thrown if plugin or templateName is null/empty + public CommandOptionChoice ApplyGlobal(Plugin plugin, TemplateKey templateName, CommandOptionChoice choice = null, PlaceholderData placeholders = null) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - if (choice == null) - { - choice = new CommandOptionChoice(); - } + choice ??= new CommandOptionChoice(); - TemplateId id = TemplateId.CreateGlobal(plugin, templateName); - ApplyGlobal(id, choice, placeholders); - return choice; - } + TemplateId id = TemplateId.CreateGlobal(plugin, templateName); + ApplyGlobal(id, choice, placeholders); + return choice; + } - private void ApplyGlobal(TemplateId id, CommandOptionChoice choice, PlaceholderData placeholders) - { - LoadTemplate(id)?.Template.ApplyName(choice, placeholders); - } + private void ApplyGlobal(TemplateId id, CommandOptionChoice choice, PlaceholderData placeholders) + { + LoadTemplate(id)?.Template.ApplyName(choice, placeholders); + } - /// - /// Applies a Localized Template to a with optional placeholders - /// - /// Plugin for the template - /// Name of the template - /// Choice to be applied to - /// Placeholders to apply - /// Server Language to apply - /// - /// Thrown if plugin or templateName is null/empty - public CommandOptionChoice ApplyLocalized(Plugin plugin, TemplateKey templateName, CommandOptionChoice choice = null, PlaceholderData placeholders = null, string language = DiscordLocales.DefaultServerLanguage) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + /// + /// Applies a Localized Template to a with optional placeholders + /// + /// Plugin for the template + /// Name of the template + /// Choice to be applied to + /// Placeholders to apply + /// Server Language to apply + /// + /// Thrown if plugin or templateName is null/empty + public CommandOptionChoice ApplyLocalized(Plugin plugin, TemplateKey templateName, CommandOptionChoice choice = null, PlaceholderData placeholders = null, string language = DiscordLocales.DefaultServerLanguage) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - if (choice == null) - { - choice = new CommandOptionChoice(); - } + choice ??= new CommandOptionChoice(); - ServerLocale locale = ServerLocale.Parse(language); - TemplateId id = TemplateId.CreateLocalized(plugin, templateName, locale); - ApplyLocalizations(id, choice, placeholders); - return choice; - } + ServerLocale locale = ServerLocale.Parse(language); + TemplateId id = TemplateId.CreateLocalized(plugin, templateName, locale); + ApplyLocalizations(id, choice, placeholders); + return choice; + } - /// - /// Applies a Localized Template to a with optional placeholders - /// - /// Plugin for the template - /// Name of the template - /// Interaction for the localization - /// Choice to be applied to - /// Placeholders to apply - /// - /// Thrown if plugin or templateName is null/empty - public CommandOptionChoice ApplyLocalized(Plugin plugin, TemplateKey templateName, DiscordInteraction interaction, CommandOptionChoice choice = null, PlaceholderData placeholders = null) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + /// + /// Applies a Localized Template to a with optional placeholders + /// + /// Plugin for the template + /// Name of the template + /// Interaction for the localization + /// Choice to be applied to + /// Placeholders to apply + /// + /// Thrown if plugin or templateName is null/empty + public CommandOptionChoice ApplyLocalized(Plugin plugin, TemplateKey templateName, DiscordInteraction interaction, CommandOptionChoice choice = null, PlaceholderData placeholders = null) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - if (choice == null) - { - choice = new CommandOptionChoice(); - } + choice ??= new CommandOptionChoice(); - TemplateId id = TemplateId.CreateInteraction(plugin, templateName, interaction); - ApplyLocalizations(id, choice, placeholders); - return choice; - } + TemplateId id = TemplateId.CreateInteraction(plugin, templateName, interaction); + ApplyLocalizations(id, choice, placeholders); + return choice; + } - private void ApplyLocalizations(TemplateId id, CommandOptionChoice choice, PlaceholderData data) - { - if (choice.NameLocalizations == null) - { - choice.NameLocalizations = new Hash(); - } + private void ApplyLocalizations(TemplateId id, CommandOptionChoice choice, PlaceholderData data) + { + choice.NameLocalizations ??= new Hash(); - data?.IncrementDepth(); + data?.IncrementDepth(); - //Apply global template to the name field if it exists - ApplyGlobal(id, choice, data); - - List list = GetLocalizedTemplates(id); - for (int index = 0; index < list.Count; index++) - { - LocalizedTemplate template = list[index]; - template.Template.ApplyLocalization(template.Locale, choice, data); - } + //Apply global template to the name field if it exists + ApplyGlobal(id, choice, data); - data?.DecrementDepth(); - data?.AutoDispose(); + List list = GetLocalizedTemplates(id); + for (int index = 0; index < list.Count; index++) + { + LocalizedTemplate template = list[index]; + template.Template.ApplyLocalization(template.Locale, choice, data); } - private List GetLocalizedTemplates(TemplateId id) + data?.DecrementDepth(); + data?.AutoDispose(); + } + + private List GetLocalizedTemplates(TemplateId id) + { + if(_localizedCache.TryGetValue(id, out List templates)) { - if(_localizedCache.TryGetValue(id, out List templates)) - { - return templates; - } + return templates; + } - templates = new List(); + templates = new List(); - foreach (string dir in Directory.EnumerateDirectories(GetTemplateFolder(id.PluginId))) + foreach (string dir in Directory.EnumerateDirectories(GetTemplateFolder(id.PluginId))) + { + ServerLocale locale = ServerLocale.Parse(Path.GetFileName(dir)); + DiscordLocale discordLocale = locale.GetDiscordLocale(); + if (!discordLocale.IsValid) { - ServerLocale locale = ServerLocale.Parse(Path.GetFileName(dir)); - DiscordLocale discordLocale = locale.GetDiscordLocale(); - if (!discordLocale.IsValid) - { - continue; - } + continue; + } - DiscordAutoCompleteChoiceTemplate template = LoadTemplate(id.WithLanguage(locale))?.Template; - if (template != null) - { - templates.Add(new LocalizedTemplate(discordLocale, template)); - } + DiscordAutoCompleteChoiceTemplate template = LoadTemplate(id.WithLanguage(locale))?.Template; + if (template != null) + { + templates.Add(new LocalizedTemplate(discordLocale, template)); } + } - _localizedCache[id] = templates; + _localizedCache[id] = templates; - return templates; - } + return templates; + } - private void SetCache(TemplateId id, DiscordAutoCompleteChoiceTemplate template) + private void SetCache(TemplateId id, DiscordAutoCompleteChoiceTemplate template) + { + if (id.IsGlobal) { - if (id.IsGlobal) - { - _globalCache[id] = template; - } + _globalCache[id] = template; } + } - internal override void OnTemplateRegistered(TemplateId id, DiscordAutoCompleteChoiceTemplate template) + internal override void OnTemplateRegistered(TemplateId id, DiscordAutoCompleteChoiceTemplate template) + { + if (id.IsGlobal) { - if (id.IsGlobal) - { - _globalCache[id] = template; - } + _globalCache[id] = template; } + } - /// - protected override void OnPluginUnloaded(Plugin plugin) - { - base.OnPluginUnloaded(plugin); - PluginId pluginId = plugin.Id(); - _globalCache.RemoveAll(t => t.PluginId == pluginId); - _localizedCache.RemoveAll(t => t.PluginId == pluginId); - } + /// + protected override void OnPluginUnloaded(Plugin plugin) + { + base.OnPluginUnloaded(plugin); + PluginId pluginId = plugin.Id(); + _globalCache.RemoveAll(t => t.PluginId == pluginId); + _localizedCache.RemoveAll(t => t.PluginId == pluginId); + } - private struct LocalizedTemplate - { - public readonly DiscordLocale Locale; - public readonly DiscordAutoCompleteChoiceTemplate Template; + private struct LocalizedTemplate + { + public readonly DiscordLocale Locale; + public readonly DiscordAutoCompleteChoiceTemplate Template; - public LocalizedTemplate(DiscordLocale locale, DiscordAutoCompleteChoiceTemplate template) - { - Locale = locale; - Template = template; - } + public LocalizedTemplate(DiscordLocale locale, DiscordAutoCompleteChoiceTemplate template) + { + Locale = locale; + Template = template; } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/BaseMessageTemplateLibrary.cs b/Oxide.Ext.Discord/Libraries/Templates/BaseMessageTemplateLibrary.cs index 817d850d2..ee1eeaf6a 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/BaseMessageTemplateLibrary.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/BaseMessageTemplateLibrary.cs @@ -11,175 +11,174 @@ using Oxide.Ext.Discord.Plugins; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Library for Discord Message templates +/// +public abstract class BaseMessageTemplateLibrary : BaseTemplateLibrary + where TTemplate : class, new() { + private readonly ConcurrentDictionary _templateCache = new(); + + internal BaseMessageTemplateLibrary(TemplateType type, ILogger logger) : base(type, logger) { } + /// - /// Library for Discord Message templates + /// Registers a global message template + /// Global Message templates cannot be localized /// - public abstract class BaseMessageTemplateLibrary : BaseTemplateLibrary - where TTemplate : class, new() + /// Plugin the template is for + /// Unique name of the template + /// Template to register + /// Version of the template + /// Min supported version for this template + /// + public IPromise RegisterGlobalTemplateAsync(Plugin plugin, TemplateKey templateName, TTemplate template, TemplateVersion version, TemplateVersion minVersion) { - private readonly ConcurrentDictionary _templateCache = new ConcurrentDictionary(); - - internal BaseMessageTemplateLibrary(TemplateType type, ILogger logger) : base(type, logger) { } - - /// - /// Registers a global message template - /// Global Message templates cannot be localized - /// - /// Plugin the template is for - /// Unique name of the template - /// Template to register - /// Version of the template - /// Min supported version for this template - /// - public IPromise RegisterGlobalTemplateAsync(Plugin plugin, TemplateKey templateName, TTemplate template, TemplateVersion version, TemplateVersion minVersion) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - if (template == null) throw new ArgumentNullException(nameof(template)); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + if (template == null) throw new ArgumentNullException(nameof(template)); - IPendingPromise promise = Promise.Create(); + IPendingPromise promise = Promise.Create(); - TemplateId id = TemplateId.CreateGlobal(plugin, templateName); - RegisterTemplateCallback.Start(this, id, template, version, minVersion, promise); - return promise; - } + TemplateId id = TemplateId.CreateGlobal(plugin, templateName); + RegisterTemplateCallback.Start(this, id, template, version, minVersion, promise); + return promise; + } - /// - /// Registers a message template with the given name and language - /// - /// Plugin the is for - /// Name of the - /// Template to be registered - /// Version of the template - /// - /// The minimum supported template version.
- /// If an existing template exists and it's version is >= the minimum supported version then we will use that template.
- /// If an existing template exists and it's version is < the min supported version. The existing version is backed up and a new template is created - /// - /// Language for the template - /// - public IPromise RegisterLocalizedTemplateAsync(Plugin plugin, TemplateKey templateName, TTemplate template, TemplateVersion version, TemplateVersion minVersion, string language = DiscordLocales.DefaultServerLanguage) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); - if (template == null) throw new ArgumentNullException(nameof(template)); + /// + /// Registers a message template with the given name and language + /// + /// Plugin the is for + /// Name of the + /// Template to be registered + /// Version of the template + /// + /// The minimum supported template version.
+ /// If an existing template exists and it's version is >= the minimum supported version then we will use that template.
+ /// If an existing template exists and it's version is < the min supported version. The existing version is backed up and a new template is created + /// + /// Language for the template + /// + public IPromise RegisterLocalizedTemplateAsync(Plugin plugin, TemplateKey templateName, TTemplate template, TemplateVersion version, TemplateVersion minVersion, string language = DiscordLocales.DefaultServerLanguage) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (!templateName.IsValid) throw new ArgumentNullException(nameof(templateName)); + if (template == null) throw new ArgumentNullException(nameof(template)); - IPendingPromise promise = Promise.Create(); + IPendingPromise promise = Promise.Create(); - TemplateId id = TemplateId.CreateLocalized(plugin, templateName, ServerLocale.Parse(language)); - RegisterTemplateCallback.Start(this, id, template, version, minVersion, promise); - return promise; - } + TemplateId id = TemplateId.CreateLocalized(plugin, templateName, ServerLocale.Parse(language)); + RegisterTemplateCallback.Start(this, id, template, version, minVersion, promise); + return promise; + } - /// - /// Returns a global message template for the plugin with the given name - /// - /// Plugin the template is for - /// Name of the template - /// - /// - public TTemplate GetGlobalTemplate(Plugin plugin, TemplateKey templateName) => HandleGetLocalizedTemplate(TemplateId.CreateGlobal(plugin, templateName), null); + /// + /// Returns a global message template for the plugin with the given name + /// + /// Plugin the template is for + /// Name of the template + /// + /// + public TTemplate GetGlobalTemplate(Plugin plugin, TemplateKey templateName) => HandleGetLocalizedTemplate(TemplateId.CreateGlobal(plugin, templateName), null); - /// - /// Returns a message template for a given player - /// - /// Plugin the template is for - /// Name of the template - /// IPlayer for the template - /// - /// Thrown if Plugin is null or name / language is null or empty - public TTemplate GetPlayerTemplate(Plugin plugin, TemplateKey templateName, IPlayer player) => GetPlayerTemplate(plugin, templateName, player?.Id); + /// + /// Returns a message template for a given player + /// + /// Plugin the template is for + /// Name of the template + /// IPlayer for the template + /// + /// Thrown if Plugin is null or name / language is null or empty + public TTemplate GetPlayerTemplate(Plugin plugin, TemplateKey templateName, IPlayer player) => GetPlayerTemplate(plugin, templateName, player?.Id); - /// - /// Returns a message template for a given player - /// - /// Plugin the template is for - /// Name of the template - /// Player ID for the template - /// - /// Thrown if Plugin is null or name / language is null or empty - public TTemplate GetPlayerTemplate(Plugin plugin, TemplateKey templateName, string playerId) => HandleGetLocalizedTemplate(TemplateId.CreatePlayer(plugin, templateName, playerId), null); - - /// - /// Returns a message template for a given language - /// - /// Plugin the template is for - /// Name of the template - /// Oxide language of the template - /// - /// Thrown if Plugin is null or name / language is null or empty - public TTemplate GetLocalizedTemplate(Plugin plugin, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage) => HandleGetLocalizedTemplate(TemplateId.CreateLocalized(plugin, templateName, ServerLocale.Parse(language)), null); - - /// - /// Returns a message template for a given language - /// - /// Plugin the template is for - /// Name of the template - /// Interaction to get the template for - /// - /// Thrown if Plugin is null or name / language is null or empty - public TTemplate GetLocalizedTemplate(Plugin plugin, TemplateKey templateName, DiscordInteraction interaction) => HandleGetLocalizedTemplate(TemplateId.CreateInteraction(plugin, templateName, interaction), interaction); - - private TTemplate HandleGetLocalizedTemplate(TemplateId id, DiscordInteraction interaction) + /// + /// Returns a message template for a given player + /// + /// Plugin the template is for + /// Name of the template + /// Player ID for the template + /// + /// Thrown if Plugin is null or name / language is null or empty + public TTemplate GetPlayerTemplate(Plugin plugin, TemplateKey templateName, string playerId) => HandleGetLocalizedTemplate(TemplateId.CreatePlayer(plugin, templateName, playerId), null); + + /// + /// Returns a message template for a given language + /// + /// Plugin the template is for + /// Name of the template + /// Oxide language of the template + /// + /// Thrown if Plugin is null or name / language is null or empty + public TTemplate GetLocalizedTemplate(Plugin plugin, TemplateKey templateName, string language = DiscordLocales.DefaultServerLanguage) => HandleGetLocalizedTemplate(TemplateId.CreateLocalized(plugin, templateName, ServerLocale.Parse(language)), null); + + /// + /// Returns a message template for a given language + /// + /// Plugin the template is for + /// Name of the template + /// Interaction to get the template for + /// + /// Thrown if Plugin is null or name / language is null or empty + public TTemplate GetLocalizedTemplate(Plugin plugin, TemplateKey templateName, DiscordInteraction interaction) => HandleGetLocalizedTemplate(TemplateId.CreateInteraction(plugin, templateName, interaction), interaction); + + private TTemplate HandleGetLocalizedTemplate(TemplateId id, DiscordInteraction interaction) + { + TTemplate cachedTemplate = LoadFromCache(id); + if (cachedTemplate != null) { - TTemplate cachedTemplate = LoadFromCache(id); - if (cachedTemplate != null) - { - return cachedTemplate; - } - - DiscordTemplate template; - if (interaction != null) - { - IPlayer player = interaction.User.Player; - template = LoadTemplate(id) - ?? (player != null ? LoadTemplate(id, DiscordLocales.Instance.GetPlayerLanguage(player)) : null) - ?? (interaction.GuildLocale.HasValue ? LoadTemplate(id, interaction.GuildLocale.Value.GetServerLocale()) : null) - ?? LoadTemplate(id, DiscordLocales.Instance.ServerLanguage) - ?? LoadTemplate(id, ServerLocale.Default); - } - else if (!id.IsGlobal) - { - template = LoadTemplate(id) - ?? LoadTemplate(id, DiscordLocales.Instance.ServerLanguage) - ?? LoadTemplate(id, ServerLocale.Default); - } - else - { - template = LoadTemplate(id); - } - - if (template == null) - { - Logger.Error("Plugin {0} is using the {1} Template API but message template name '{2}/{3}' is not registered", id.GetPluginName(), GetType().GetRealTypeName(), id.GetLanguageName(), id.TemplateName); - return new TTemplate(); - } + return cachedTemplate; + } - SetCache(id, template.Template); - - return template.Template; + DiscordTemplate template; + if (interaction != null) + { + IPlayer player = interaction.User.Player; + template = LoadTemplate(id) + ?? (player != null ? LoadTemplate(id, DiscordLocales.Instance.GetPlayerLanguage(player)) : null) + ?? (interaction.GuildLocale.HasValue ? LoadTemplate(id, interaction.GuildLocale.Value.GetServerLocale()) : null) + ?? LoadTemplate(id, DiscordLocales.Instance.ServerLanguage) + ?? LoadTemplate(id, ServerLocale.Default); } - - private TTemplate LoadFromCache(TemplateId id) => _templateCache.GetValueOrDefault(id); - - private void SetCache(TemplateId id, TTemplate template) + else if (!id.IsGlobal) { - _templateCache[id] = template; + template = LoadTemplate(id) + ?? LoadTemplate(id, DiscordLocales.Instance.ServerLanguage) + ?? LoadTemplate(id, ServerLocale.Default); } - - internal override void OnTemplateRegistered(TemplateId id, TTemplate template) + else { - SetCache(id, template); + template = LoadTemplate(id); } - /// - protected override void OnPluginUnloaded(Plugin plugin) + if (template == null) { - base.OnPluginUnloaded(plugin); - PluginId pluginId = plugin.Id(); - _templateCache.RemoveAll(t => t.PluginId == pluginId); + Logger.Error("Plugin {0} is using the {1} Template API but message template name '{2}/{3}' is not registered", id.GetPluginName(), GetType().GetRealTypeName(), id.GetLanguageName(), id.TemplateName); + return new TTemplate(); } + + SetCache(id, template.Template); + + return template.Template; + } + + private TTemplate LoadFromCache(TemplateId id) => _templateCache.GetValueOrDefault(id); + + private void SetCache(TemplateId id, TTemplate template) + { + _templateCache[id] = template; + } + + internal override void OnTemplateRegistered(TemplateId id, TTemplate template) + { + SetCache(id, template); + } + + /// + protected override void OnPluginUnloaded(Plugin plugin) + { + base.OnPluginUnloaded(plugin); + PluginId pluginId = plugin.Id(); + _templateCache.RemoveAll(t => t.PluginId == pluginId); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/BaseTemplateLibrary.cs b/Oxide.Ext.Discord/Libraries/Templates/BaseTemplateLibrary.cs index 0703a1681..90f2fb879 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/BaseTemplateLibrary.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/BaseTemplateLibrary.cs @@ -14,241 +14,240 @@ using Oxide.Ext.Discord.Plugins; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Oxide Library for Discord Templates +/// +public abstract class BaseTemplateLibrary : BaseDiscordLibrary where TTemplate : class { /// - /// Oxide Library for Discord Templates + /// Logger for the /// - public abstract class BaseTemplateLibrary : BaseDiscordLibrary where TTemplate : class - { - /// - /// Logger for the - /// - protected readonly ILogger Logger; + protected readonly ILogger Logger; - /// - /// Root Directory for the library - /// - private readonly string _rootDirectory; - - /// - /// Template Type Directory - /// - private readonly string _templateTypeDirectory; + /// + /// Root Directory for the library + /// + private readonly string _rootDirectory; + + /// + /// Template Type Directory + /// + private readonly string _templateTypeDirectory; - /// - /// The template type of this template library - /// - protected readonly TemplateType TemplateType; - - private readonly DiscordConcurrentSet _registeredTemplates = new DiscordConcurrentSet(); - private readonly ConcurrentDictionary _pluginTemplatePath = new ConcurrentDictionary(); - - /// - /// Constructor - /// - /// The template type of this library - /// - protected BaseTemplateLibrary(TemplateType type, ILogger logger) - { - _rootDirectory = Path.Combine(Interface.Oxide.InstanceDirectory, "discord"); - Logger = logger; - TemplateType = type; - _templateTypeDirectory = EnumCache.Instance.ToLower(TemplateType); - - if (!Directory.Exists(_rootDirectory)) - { - Directory.CreateDirectory(_rootDirectory); - } + /// + /// The template type of this template library + /// + protected readonly TemplateType TemplateType; + + private readonly DiscordConcurrentSet _registeredTemplates = new(); + private readonly ConcurrentDictionary _pluginTemplatePath = new(); + + /// + /// Constructor + /// + /// The template type of this library + /// + protected BaseTemplateLibrary(TemplateType type, ILogger logger) + { + _rootDirectory = Path.Combine(Interface.Oxide.InstanceDirectory, "discord"); + Logger = logger; + TemplateType = type; + _templateTypeDirectory = EnumCache.Instance.ToLower(TemplateType); + + if (!Directory.Exists(_rootDirectory)) + { + Directory.CreateDirectory(_rootDirectory); } + } - internal void HandleRegisterTemplate(TemplateId id, TTemplate template, TemplateVersion version, TemplateVersion minVersion, IPendingPromise promise) + internal void HandleRegisterTemplate(TemplateId id, TTemplate template, TemplateVersion version, TemplateVersion minVersion, IPendingPromise promise) + { + if (version < minVersion) { - if (version < minVersion) - { - string error = $"Failed to register for template: {id} because the template version {version} is less than the min supported version {minVersion}"; - Logger.Error(error); - promise.Reject(new InvalidTemplateVersionException(error)); - return; - } + string error = $"Failed to register for template: {id} because the template version {version} is less than the min supported version {minVersion}"; + Logger.Error(error); + promise.Reject(new InvalidTemplateVersionException(error)); + return; + } - if (!_registeredTemplates.Add(id)) - { - string error = $"Failed to register template Type: {TemplateType} {id}. Template has already been registered."; - Logger.Error(error); - promise.Reject(new DuplicateTemplateException(error)); - return; - } + if (!_registeredTemplates.Add(id)) + { + string error = $"Failed to register template Type: {TemplateType} {id}. Template has already been registered."; + Logger.Error(error); + promise.Reject(new DuplicateTemplateException(error)); + return; + } - DiscordTemplate registeringTemplate = new DiscordTemplate(template, version); - string path = GetTemplatePath(id); - if (File.Exists(path)) + DiscordTemplate registeringTemplate = new(template, version); + string path = GetTemplatePath(id); + if (File.Exists(path)) + { + DiscordTemplate existingTemplate = LoadTemplate(id); + if (existingTemplate != null) { - DiscordTemplate existingTemplate = LoadTemplate(id); - if (existingTemplate != null) + if (existingTemplate.Version < minVersion) { - if (existingTemplate.Version < minVersion) - { - BackupTemplateFiles(id, minVersion); - CreateFile(path, registeringTemplate); - OnTemplateRegistered(id, template); - promise.Resolve(template); - } - else - { - OnTemplateRegistered(id, existingTemplate.Template); - promise.Resolve(existingTemplate.Template); - } + BackupTemplateFiles(id, minVersion); + CreateFile(path, registeringTemplate); + OnTemplateRegistered(id, template); + promise.Resolve(template); + } + else + { + OnTemplateRegistered(id, existingTemplate.Template); + promise.Resolve(existingTemplate.Template); } - } - else - { - CreateFile(path, registeringTemplate); - OnTemplateRegistered(id, template); - promise.Resolve(template); } } + else + { + CreateFile(path, registeringTemplate); + OnTemplateRegistered(id, template); + promise.Resolve(template); + } + } - internal void HandleBulkRegisterTemplate(TemplateId id, List> templates, TemplateVersion minVersion, IPendingPromise promise) + internal void HandleBulkRegisterTemplate(TemplateId id, List> templates, TemplateVersion minVersion, IPendingPromise promise) + { + for (int index = 0; index < templates.Count; index++) { - for (int index = 0; index < templates.Count; index++) - { - BulkTemplateRegistration registration = templates[index]; - HandleRegisterTemplate(id.WithLanguage(ServerLocale.Parse(registration.Language)), registration.Template, registration.Version, minVersion, null); - } - - promise.Resolve(); + BulkTemplateRegistration registration = templates[index]; + HandleRegisterTemplate(id.WithLanguage(ServerLocale.Parse(registration.Language)), registration.Template, registration.Version, minVersion, null); } - internal DiscordTemplate LoadTemplate(TemplateId id) - { - string path = GetTemplatePath(id); - if (!File.Exists(path)) - { - return null; - } + promise.Resolve(); + } - try - { - string json = File.ReadAllText(path); - return JsonConvert.DeserializeObject>(json, JsonSettings.Indented); - } - catch (Exception ex) - { - Logger.Exception("Failed to load template from file: {0} Path: {1}", id.ToString(), path.Substring(Interface.Oxide.RootDirectory.Length), ex); - return null; - } + internal DiscordTemplate LoadTemplate(TemplateId id) + { + string path = GetTemplatePath(id); + if (!File.Exists(path)) + { + return null; } - internal DiscordTemplate LoadTemplate(TemplateId id, ServerLocale language) + try { - return LoadTemplate(id.WithLanguage(language)); + string json = File.ReadAllText(path); + return JsonConvert.DeserializeObject>(json, DiscordJson.IndentedSettings); } - - private void CreateFile(string path, DiscordTemplate template) + catch (Exception ex) { - string dir = Path.GetDirectoryName(path); - if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) - { - Directory.CreateDirectory(dir); - } + Logger.Exception("Failed to load template from file: {0} Path: {1}", id.ToString(), path.Substring(Interface.Oxide.RootDirectory.Length), ex); + return null; + } + } + + internal DiscordTemplate LoadTemplate(TemplateId id, ServerLocale language) + { + return LoadTemplate(id.WithLanguage(language)); + } - string json = JsonConvert.SerializeObject(template, JsonSettings.Indented); - File.WriteAllText(path, json); + private void CreateFile(string path, DiscordTemplate template) + { + string dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); } - private void BackupTemplateFiles(TemplateId id, TemplateVersion minVersion) + string json = JsonConvert.SerializeObject(template, DiscordJson.IndentedSettings); + File.WriteAllText(path, json); + } + + private void BackupTemplateFiles(TemplateId id, TemplateVersion minVersion) + { + if (id.IsGlobal) { - if (id.IsGlobal) - { - BackupTemplate(minVersion, id); - return; - } + BackupTemplate(minVersion, id); + return; + } - string path = GetTemplateFolder(id.PluginId); - if (Logger.IsLogging(DiscordLogLevel.Debug)) - { - Logger.Debug("Backup Template files for: {0} Path: {1}", id.ToString(), path); - } + string path = GetTemplateFolder(id.PluginId); + if (Logger.IsLogging(DiscordLogLevel.Debug)) + { + Logger.Debug("Backup Template files for: {0} Path: {1}", id.ToString(), path); + } - foreach (string dir in Directory.EnumerateDirectories(path)) - { - ServerLocale lang = ServerLocale.Parse(Path.GetFileName(dir)); - Logger.Debug("Processing Directory: {0} Lang: {1}", dir, lang); - BackupTemplate(minVersion, id.WithLanguage(lang)); - } + foreach (string dir in Directory.EnumerateDirectories(path)) + { + ServerLocale lang = ServerLocale.Parse(Path.GetFileName(dir)); + Logger.Debug("Processing Directory: {0} Lang: {1}", dir, lang); + BackupTemplate(minVersion, id.WithLanguage(lang)); } + } - private void BackupTemplate(TemplateVersion minVersion, TemplateId langId) + private void BackupTemplate(TemplateVersion minVersion, TemplateId langId) + { + string oldPath = GetTemplatePath(langId); + if (!File.Exists(oldPath)) { - string oldPath = GetTemplatePath(langId); - if (!File.Exists(oldPath)) - { - return; - } - - DiscordTemplate template = LoadTemplate(langId); - if (template == null) - { - return; - } - - if (template.Version >= minVersion) - { - return; - } - - string newPath = GetRenamePath(oldPath, template.Version); - if (File.Exists(newPath)) - { - File.Delete(newPath); - } - - File.Move(oldPath, newPath); + return; } - /// - /// Returns the template folder for a given plugin - /// - /// Plugin Name the template is for - /// - protected string GetTemplateFolder(PluginId plugin) + DiscordTemplate template = LoadTemplate(langId); + if (template == null) { - if (!_pluginTemplatePath.TryGetValue(plugin, out string path)) - { - path = Path.Combine(_rootDirectory, plugin.PluginName(), _templateTypeDirectory); - _pluginTemplatePath[plugin] = path; - } - - return path; + return; } - private string GetTemplatePath(TemplateId id) + if (template.Version >= minVersion) { - DiscordTemplateException.ThrowIfInvalidTemplateName(id.TemplateName.Name, TemplateType); + return; + } - if (id.IsGlobal) - { - return Path.Combine(GetTemplateFolder(id.PluginId), $"{id.TemplateName}.json"); - } - - return Path.Combine(GetTemplateFolder(id.PluginId), id.Language.Id, $"{id.TemplateName}.json"); + string newPath = GetRenamePath(oldPath, template.Version); + if (File.Exists(newPath)) + { + File.Delete(newPath); } - private string GetRenamePath(string path, TemplateVersion version) + File.Move(oldPath, newPath); + } + + /// + /// Returns the template folder for a given plugin + /// + /// Plugin Name the template is for + /// + protected string GetTemplateFolder(PluginId plugin) + { + if (!_pluginTemplatePath.TryGetValue(plugin, out string path)) { - if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path)); - return Path.Combine(Path.GetDirectoryName(path) ?? string.Empty, $"{Path.GetFileNameWithoutExtension(path)}.{version}.json"); + path = Path.Combine(_rootDirectory, plugin.PluginName(), _templateTypeDirectory); + _pluginTemplatePath[plugin] = path; } - internal virtual void OnTemplateRegistered(TemplateId id, TTemplate template) { } + return path; + } - /// - protected override void OnPluginUnloaded(Plugin plugin) + private string GetTemplatePath(TemplateId id) + { + DiscordTemplateException.ThrowIfInvalidTemplateName(id.TemplateName.Name, TemplateType); + + if (id.IsGlobal) { - PluginId id = plugin.Id(); - _registeredTemplates.RemoveWhere(t => t.PluginId == id); - _pluginTemplatePath.TryRemove(id, out string _); + return Path.Combine(GetTemplateFolder(id.PluginId), $"{id.TemplateName}.json"); } + + return Path.Combine(GetTemplateFolder(id.PluginId), id.Language.Id, $"{id.TemplateName}.json"); + } + + private string GetRenamePath(string path, TemplateVersion version) + { + if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path)); + return Path.Combine(Path.GetDirectoryName(path) ?? string.Empty, $"{Path.GetFileNameWithoutExtension(path)}.{version}.json"); + } + + internal virtual void OnTemplateRegistered(TemplateId id, TTemplate template) { } + + /// + protected override void OnPluginUnloaded(Plugin plugin) + { + PluginId id = plugin.Id(); + _registeredTemplates.RemoveWhere(t => t.PluginId == id); + _pluginTemplatePath.TryRemove(id, out string _); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/BulkTemplateRegistration.cs b/Oxide.Ext.Discord/Libraries/Templates/BulkTemplateRegistration.cs index c8e16854c..d398e3c66 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/BulkTemplateRegistration.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/BulkTemplateRegistration.cs @@ -1,37 +1,36 @@ -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Used for bulk template registration +/// +/// Type of the template being registered +public class BulkTemplateRegistration { /// - /// Used for bulk template registration + /// Language for this template /// - /// Type of the template being registered - public class BulkTemplateRegistration - { - /// - /// Language for this template - /// - public string Language { get; set; } + public string Language { get; set; } - /// - /// Template to register - /// - public T Template { get; set; } + /// + /// Template to register + /// + public T Template { get; set; } - /// - /// Version of the template - /// - public TemplateVersion Version { get; set; } + /// + /// Version of the template + /// + public TemplateVersion Version { get; set; } - /// - /// Constructor for bulk template registration - /// - /// Template to register - /// Language for the template - /// Version of the template - public BulkTemplateRegistration(T template, string language, TemplateVersion version) - { - Template = template; - Language = language; - Version = version; - } + /// + /// Constructor for bulk template registration + /// + /// Template to register + /// Language for the template + /// Version of the template + public BulkTemplateRegistration(T template, string language, TemplateVersion version) + { + Template = template; + Language = language; + Version = version; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Commands/ArgumentLocalization.cs b/Oxide.Ext.Discord/Libraries/Templates/Commands/ArgumentLocalization.cs index 040e1e3e0..775a5011d 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Commands/ArgumentLocalization.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Commands/ArgumentLocalization.cs @@ -2,75 +2,74 @@ using Oxide.Ext.Discord.Entities; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Localization for Application Command Arguments +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ArgumentLocalization { /// - /// Localization for Application Command Arguments + /// Localization for /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ArgumentLocalization - { - /// - /// Localization for - /// - [JsonProperty("Argument Name")] - public string Name { get; set; } + [JsonProperty("Argument Name")] + public string Name { get; set; } - /// - /// Localization for - /// - [JsonProperty("Argument Description")] - public string Description { get; set; } + /// + /// Localization for + /// + [JsonProperty("Argument Description")] + public string Description { get; set; } - /// - /// Localization for Select Menu Choices - /// - [JsonProperty("Argument Choices", NullValueHandling = NullValueHandling.Ignore)] - public Hash Choices { get; set; } + /// + /// Localization for Select Menu Choices + /// + [JsonProperty("Argument Choices", NullValueHandling = NullValueHandling.Ignore)] + public Hash Choices { get; set; } - /// - /// Constructor - /// - [JsonConstructor] - private ArgumentLocalization() { } + /// + /// Constructor + /// + [JsonConstructor] + private ArgumentLocalization() { } - /// - /// Constructor - /// - /// Option to create the localization for - /// The oxide lang for the localization - public ArgumentLocalization(CommandOption option, DiscordLocale locale) + /// + /// Constructor + /// + /// Option to create the localization for + /// The oxide lang for the localization + public ArgumentLocalization(CommandOption option, DiscordLocale locale) + { + Name = option.NameLocalizations[locale.Id]; + Description = option.DescriptionLocalizations[locale.Id]; + if (option.Choices != null) { - Name = option.NameLocalizations[locale.Id]; - Description = option.DescriptionLocalizations[locale.Id]; - if (option.Choices != null) + Choices = new Hash(); + for (int index = 0; index < option.Choices.Count; index++) { - Choices = new Hash(); - for (int index = 0; index < option.Choices.Count; index++) - { - CommandOptionChoice choice = option.Choices[index]; - Choices[choice.Name] = new ChoicesLocalization(choice.Name); - } + CommandOptionChoice choice = option.Choices[index]; + Choices[choice.Name] = new ChoicesLocalization(choice.Name); } } + } - /// - /// Apply localizations to the command option - /// - /// - /// - public void ApplyArgumentLocalization(CommandOption option, DiscordLocale locale) - { - option.NameLocalizations[locale.Id] = Name; - option.DescriptionLocalizations[locale.Id] = Description; + /// + /// Apply localizations to the command option + /// + /// + /// + public void ApplyArgumentLocalization(CommandOption option, DiscordLocale locale) + { + option.NameLocalizations[locale.Id] = Name; + option.DescriptionLocalizations[locale.Id] = Description; - if (option.Choices != null) + if (option.Choices != null) + { + for (int index = 0; index < option.Choices.Count; index++) { - for (int index = 0; index < option.Choices.Count; index++) - { - CommandOptionChoice choice = option.Choices[index]; - Choices?[choice.Name]?.ApplyChoiceLocalization(choice, locale); - } + CommandOptionChoice choice = option.Choices[index]; + Choices?[choice.Name]?.ApplyChoiceLocalization(choice, locale); } } } diff --git a/Oxide.Ext.Discord/Libraries/Templates/Commands/ChoicesLocalization.cs b/Oxide.Ext.Discord/Libraries/Templates/Commands/ChoicesLocalization.cs index 1827f109d..0277fb103 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Commands/ChoicesLocalization.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Commands/ChoicesLocalization.cs @@ -1,50 +1,49 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Localization for Select Menu Choices +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ChoicesLocalization { /// - /// Localization for Select Menu Choices + /// Localization for /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ChoicesLocalization - { - /// - /// Localization for - /// - [JsonProperty("Choice Name")] - public string Name { get; set; } + [JsonProperty("Choice Name")] + public string Name { get; set; } - /// - /// Constructor - /// - [JsonConstructor] - public ChoicesLocalization() { } + /// + /// Constructor + /// + [JsonConstructor] + public ChoicesLocalization() { } - /// - /// Constructor for command option choice localization - /// - /// Localized choice name - public ChoicesLocalization(string name) - { - Name = name; - } + /// + /// Constructor for command option choice localization + /// + /// Localized choice name + public ChoicesLocalization(string name) + { + Name = name; + } - /// - /// Constructor - /// - /// Option to localize - /// Oxide lang of the localization - public ChoicesLocalization(CommandOption option, string lang) : this(option.NameLocalizations[lang]) { } + /// + /// Constructor + /// + /// Option to localize + /// Oxide lang of the localization + public ChoicesLocalization(CommandOption option, string lang) : this(option.NameLocalizations[lang]) { } - /// - /// Apply Choice Localizations - /// - /// - /// - public void ApplyChoiceLocalization(CommandOptionChoice choice, DiscordLocale locale) - { - choice.NameLocalizations[locale.Id] = Name; - } + /// + /// Apply Choice Localizations + /// + /// + /// + public void ApplyChoiceLocalization(CommandOptionChoice choice, DiscordLocale locale) + { + choice.NameLocalizations[locale.Id] = Name; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Commands/CommandLocalization.cs b/Oxide.Ext.Discord/Libraries/Templates/Commands/CommandLocalization.cs index 340068990..b584e3838 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Commands/CommandLocalization.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Commands/CommandLocalization.cs @@ -3,175 +3,156 @@ using Oxide.Ext.Discord.Entities; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Localization for Application Commands +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class CommandLocalization { /// - /// Localization for Application Commands + /// Localization for or /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class CommandLocalization - { - /// - /// Localization for or - /// - [JsonProperty("Command Name")] - public string Name { get; set; } + [JsonProperty("Command Name")] + public string Name { get; set; } - /// - /// Localization for or - /// - [JsonProperty("Command Description")] - public string Description { get; set; } + /// + /// Localization for or + /// + [JsonProperty("Command Description")] + public string Description { get; set; } - /// - /// Localized Options for the Command - /// - [JsonProperty("Command Options", NullValueHandling = NullValueHandling.Ignore)] - public Hash Options { get; set; } + /// + /// Localized Options for the Command + /// + [JsonProperty("Command Options", NullValueHandling = NullValueHandling.Ignore)] + public Hash Options { get; set; } - /// - /// Localized Argument Options - /// - [JsonProperty("Argument Localization", NullValueHandling = NullValueHandling.Ignore)] - public Hash Arguments { get; set; } + /// + /// Localized Argument Options + /// + [JsonProperty("Argument Localization", NullValueHandling = NullValueHandling.Ignore)] + public Hash Arguments { get; set; } - /// - /// Constructor - /// - [JsonConstructor] - private CommandLocalization() { } + /// + /// Constructor + /// + [JsonConstructor] + private CommandLocalization() { } - private CommandLocalization(string name, string description) - { - Name = name; - Description = description; - } + private CommandLocalization(string name, string description) + { + Name = name; + Description = description; + } - /// - /// Constructor - /// - /// Command to be created - /// Oxide lang of the localization - public CommandLocalization(CommandCreate create, DiscordLocale locale) : this(create.NameLocalizations[locale.Id], create.DescriptionLocalizations[locale.Id]) + /// + /// Constructor + /// + /// Command to be created + /// Oxide lang of the localization + public CommandLocalization(CommandCreate create, DiscordLocale locale) : this(create.NameLocalizations[locale.Id], create.DescriptionLocalizations[locale.Id]) + { + if (create.Options != null) { - if (create.Options != null) + for (int index = 0; index < create.Options.Count; index++) { - for (int index = 0; index < create.Options.Count; index++) - { - ProcessOption(create.Options[index], locale); - } + ProcessOption(create.Options[index], locale); } } + } - /// - /// Constructor - /// - /// - /// - public CommandLocalization(CommandOption opt, DiscordLocale locale) : this(opt.NameLocalizations[locale.Id], opt.DescriptionLocalizations[locale.Id]) - { - if (opt.Options != null) - { - for (int index = 0; index < opt.Options.Count; index++) - { - ProcessOption(opt.Options[index], locale); - } + /// + /// Constructor + /// + /// + /// + public CommandLocalization(CommandOption opt, DiscordLocale locale) : this(opt.NameLocalizations[locale.Id], opt.DescriptionLocalizations[locale.Id]) + { + if (opt.Options != null) + { + for (int index = 0; index < opt.Options.Count; index++) + { + ProcessOption(opt.Options[index], locale); } } + } - private void ProcessOption(CommandOption option, DiscordLocale locale) + private void ProcessOption(CommandOption option, DiscordLocale locale) + { + if (option.Type == CommandOptionType.SubCommand || option.Type == CommandOptionType.SubCommandGroup) { - if (option.Type == CommandOptionType.SubCommand || option.Type == CommandOptionType.SubCommandGroup) - { - if (Options == null) - { - Options = new Hash(); - } - - Options[option.Name] = new CommandLocalization(option, locale); - return; - } - - if (Arguments == null) + if (Options == null) { - Arguments = new Hash(); + Options = new Hash(); } - Arguments[option.Name] = new ArgumentLocalization(option, locale); + Options[option.Name] = new CommandLocalization(option, locale); + return; } - - /// - /// Apply Command Localizations to the - /// - /// - /// - public void ApplyCommandLocalization(CommandCreate create, DiscordLocale locale) - { - if (create.NameLocalizations == null) - { - create.NameLocalizations = new Hash(); - } - if (create.DescriptionLocalizations == null) - { - create.DescriptionLocalizations = new Hash(); - } + Arguments ??= new Hash(); + Arguments[option.Name] = new ArgumentLocalization(option, locale); + } + + /// + /// Apply Command Localizations to the + /// + /// + /// + public void ApplyCommandLocalization(CommandCreate create, DiscordLocale locale) + { + create.NameLocalizations ??= new Hash(); + create.DescriptionLocalizations ??= new Hash(); - create.NameLocalizations[locale.Id] = Name; - create.DescriptionLocalizations[locale.Id] = Description; - List options = create.Options; - if (options != null) + create.NameLocalizations[locale.Id] = Name; + create.DescriptionLocalizations[locale.Id] = Description; + List options = create.Options; + if (options != null) + { + if (Options != null) { - if (Options != null) + for (int index = 0; index < options.Count; index++) { - for (int index = 0; index < options.Count; index++) - { - CommandOption option = options[index]; - Options[option.Name]?.ApplyOptionLocalization(option, locale); - } + CommandOption option = options[index]; + Options[option.Name]?.ApplyOptionLocalization(option, locale); } + } - if (Arguments != null) + if (Arguments != null) + { + for (int index = 0; index < options.Count; index++) { - for (int index = 0; index < options.Count; index++) - { - CommandOption option = options[index]; - Arguments[option.Name]?.ApplyArgumentLocalization(option, locale); - } + CommandOption option = options[index]; + Arguments[option.Name]?.ApplyArgumentLocalization(option, locale); } } } + } - private void ApplyOptionLocalization(CommandOption opt, DiscordLocale locale) + private void ApplyOptionLocalization(CommandOption opt, DiscordLocale locale) + { + opt.NameLocalizations ??= new Hash(); + opt.DescriptionLocalizations ??= new Hash(); + + if (opt.Type is CommandOptionType.SubCommand or CommandOptionType.SubCommandGroup) { - if (opt.NameLocalizations == null) - { - opt.NameLocalizations = new Hash(); - } + opt.NameLocalizations[locale.Id] = Name; + opt.DescriptionLocalizations[locale.Id] = Description; - if (opt.DescriptionLocalizations == null) + if (Options != null) { - opt.DescriptionLocalizations = new Hash(); - } - - if (opt.Type == CommandOptionType.SubCommand || opt.Type == CommandOptionType.SubCommandGroup) - { - opt.NameLocalizations[locale.Id] = Name; - opt.DescriptionLocalizations[locale.Id] = Description; - - if (Options != null) + for (int index = 0; index < opt.Options.Count; index++) { - for (int index = 0; index < opt.Options.Count; index++) - { - CommandOption option = opt.Options[index]; - Options[option.Name]?.ApplyOptionLocalization(option, locale); - } + CommandOption option = opt.Options[index]; + Options[option.Name]?.ApplyOptionLocalization(option, locale); } - - return; } - Arguments?[opt.Name]?.ApplyArgumentLocalization(opt, locale); + return; } + + Arguments?[opt.Name]?.ApplyArgumentLocalization(opt, locale); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Commands/DiscordCommandLocalization.cs b/Oxide.Ext.Discord/Libraries/Templates/Commands/DiscordCommandLocalization.cs index 5b1991600..90ba1fa1f 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Commands/DiscordCommandLocalization.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Commands/DiscordCommandLocalization.cs @@ -1,45 +1,44 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Command Localizations for Application Commands +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordCommandLocalization { /// - /// Command Localizations for Application Commands + /// Localized Command /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordCommandLocalization - { - /// - /// Localized Command - /// - [JsonProperty("Command Localization")] - public CommandLocalization Command { get; set; } + [JsonProperty("Command Localization")] + public CommandLocalization Command { get; set; } - /// - /// Constructor - /// - // ReSharper disable once UnusedMember.Local - [JsonConstructor] - private DiscordCommandLocalization() { } + /// + /// Constructor + /// + // ReSharper disable once UnusedMember.Local + [JsonConstructor] + private DiscordCommandLocalization() { } - /// - /// Constructor - /// - /// Command to create the localization for - /// Oxide Lang for the command - public DiscordCommandLocalization(CommandCreate command, ServerLocale locale) - { - Command = new CommandLocalization(command, locale.GetDiscordLocale()); - } + /// + /// Constructor + /// + /// Command to create the localization for + /// Oxide Lang for the command + public DiscordCommandLocalization(CommandCreate command, ServerLocale locale) + { + Command = new CommandLocalization(command, locale.GetDiscordLocale()); + } - /// - /// Apply localizations to for language - /// - /// - /// - public void ApplyCommandLocalization(CommandCreate create, DiscordLocale locale) - { - Command.ApplyCommandLocalization(create, locale); - } + /// + /// Apply localizations to for language + /// + /// + /// + public void ApplyCommandLocalization(CommandCreate create, DiscordLocale locale) + { + Command.ApplyCommandLocalization(create, locale); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Commands/DiscordCommandLocalizations.cs b/Oxide.Ext.Discord/Libraries/Templates/Commands/DiscordCommandLocalizations.cs index 0dac945eb..0180260b8 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Commands/DiscordCommandLocalizations.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Commands/DiscordCommandLocalizations.cs @@ -8,156 +8,141 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Library for localizing s +/// +public class DiscordCommandLocalizations : BaseTemplateLibrary { + internal DiscordCommandLocalizations(ILogger logger) : base(TemplateType.Command, logger) { } + /// - /// Library for localizing s + /// Registers Application Command Localization for a given language /// - public class DiscordCommandLocalizations : BaseTemplateLibrary + /// Plugin the for the command localization + /// Suffix to be applied to the localization. IE DiscordExtension.{suffix}.json (optional) + /// Localization to register + /// Version of the template + /// Min supported registered version + /// Language to register + /// + /// + public IPromise RegisterCommandLocalizationAsync(Plugin plugin, TemplateKey templateName, DiscordCommandLocalization localization, TemplateVersion version, TemplateVersion minVersion, string language = DiscordLocales.DefaultServerLanguage) { - internal DiscordCommandLocalizations(ILogger logger) : base(TemplateType.Command, logger) { } - - /// - /// Registers Application Command Localization for a given language - /// - /// Plugin the for the command localization - /// Suffix to be applied to the localization. IE DiscordExtension.{suffix}.json (optional) - /// Localization to register - /// Version of the template - /// Min supported registered version - /// Language to register - /// - /// - public IPromise RegisterCommandLocalizationAsync(Plugin plugin, TemplateKey templateName, DiscordCommandLocalization localization, TemplateVersion version, TemplateVersion minVersion, string language = DiscordLocales.DefaultServerLanguage) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (!templateName.IsValid) throw new ArgumentNullException(nameof(plugin)); - if (localization == null) throw new ArgumentNullException(nameof(localization)); + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (!templateName.IsValid) throw new ArgumentNullException(nameof(plugin)); + if (localization == null) throw new ArgumentNullException(nameof(localization)); - IPendingPromise promise = Promise.Create(); + IPendingPromise promise = Promise.Create(); - TemplateId id = TemplateId.CreateLocalized(plugin, templateName, ServerLocale.Parse(language)); - RegisterTemplateCallback.Start(this, id, localization, version, minVersion, promise); - return promise; - } + TemplateId id = TemplateId.CreateLocalized(plugin, templateName, ServerLocale.Parse(language)); + RegisterTemplateCallback.Start(this, id, localization, version, minVersion, promise); + return promise; + } - /// - /// Registers multiple command localizations - /// - /// Plugin the for the command localization - /// Suffix to be applied to the localization. IE DiscordExtension.{suffix}.json (optional) - /// List of to bulk register - /// Min supported registered version - /// - /// - public IPromise BulkRegisterCommandLocalizationsAsync(Plugin plugin, TemplateKey templateName, List> commands, TemplateVersion minVersion) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (!templateName.IsValid) throw new ArgumentNullException(nameof(plugin)); - if (commands == null) throw new ArgumentNullException(nameof(commands)); + /// + /// Registers multiple command localizations + /// + /// Plugin the for the command localization + /// Suffix to be applied to the localization. IE DiscordExtension.{suffix}.json (optional) + /// List of to bulk register + /// Min supported registered version + /// + /// + public IPromise BulkRegisterCommandLocalizationsAsync(Plugin plugin, TemplateKey templateName, List> commands, TemplateVersion minVersion) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (!templateName.IsValid) throw new ArgumentNullException(nameof(plugin)); + if (commands == null) throw new ArgumentNullException(nameof(commands)); - IPendingPromise promise = Promise.Create(); + IPendingPromise promise = Promise.Create(); - TemplateId id = TemplateId.CreateGlobal(plugin, templateName); - BulkRegisterTemplateCallback.Start(this, id, commands, minVersion, promise); - return promise; - } + TemplateId id = TemplateId.CreateGlobal(plugin, templateName); + BulkRegisterTemplateCallback.Start(this, id, commands, minVersion, promise); + return promise; + } - /// - /// Applies Command Localizations Async - /// - /// Plugin the localizations are for - /// The command to apply the localizations to - /// fileName suffix used when registering - /// - public IPromise ApplyCommandLocalizationsAsync(Plugin plugin, CommandCreate create, TemplateKey templateName) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - if (!templateName.IsValid) throw new ArgumentNullException(nameof(plugin)); + /// + /// Applies Command Localizations Async + /// + /// Plugin the localizations are for + /// The command to apply the localizations to + /// fileName suffix used when registering + /// + public IPromise ApplyCommandLocalizationsAsync(Plugin plugin, CommandCreate create, TemplateKey templateName) + { + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + if (!templateName.IsValid) throw new ArgumentNullException(nameof(plugin)); - IPendingPromise promise = Promise.Create(); - TemplateId id = TemplateId.CreateGlobal(plugin, templateName); - ApplyCommandLocalizationsCallback.Start(id, create, promise); - return promise; - } + IPendingPromise promise = Promise.Create(); + TemplateId id = TemplateId.CreateGlobal(plugin, templateName); + ApplyCommandLocalizationsCallback.Start(id, create, promise); + return promise; + } - internal void HandleApplyCommandLocalizationsAsync(TemplateId id, CommandCreate create, IPendingPromise promise) - { - PrepareCommandLocalizations(create); - - foreach (string dir in Directory.EnumerateDirectories(GetTemplateFolder(id.PluginId))) - { - ServerLocale lang = ServerLocale.Parse(Path.GetFileName(dir)); - HandleLoadAndApplyCommandLocalizationsAsync(id, create, lang); - } + internal void HandleApplyCommandLocalizationsAsync(TemplateId id, CommandCreate create, IPendingPromise promise) + { + PrepareCommandLocalizations(create); - promise.Resolve(); - } - - private void PrepareCommandLocalizations(CommandCreate create) + foreach (string dir in Directory.EnumerateDirectories(GetTemplateFolder(id.PluginId))) { - if (create.NameLocalizations == null) - { - create.NameLocalizations = new Hash(); - } + ServerLocale lang = ServerLocale.Parse(Path.GetFileName(dir)); + HandleLoadAndApplyCommandLocalizationsAsync(id, create, lang); + } + + promise.Resolve(); + } - if (create.DescriptionLocalizations == null) - { - create.DescriptionLocalizations = new Hash(); - } + private void PrepareCommandLocalizations(CommandCreate create) + { + create.NameLocalizations ??= new Hash(); + create.DescriptionLocalizations ??= new Hash(); - if (create.Options == null) - { - return; - } + if (create.Options == null) + { + return; + } - for (int index = 0; index < create.Options.Count; index++) - { - PrepareOptionLocalizations(create.Options[index]); - } + for (int index = 0; index < create.Options.Count; index++) + { + PrepareOptionLocalizations(create.Options[index]); } + } - private void PrepareOptionLocalizations(CommandOption opt) - { - if (opt.NameLocalizations == null) - { - opt.NameLocalizations = new Hash(); - } - - if (opt.DescriptionLocalizations == null) - { - opt.DescriptionLocalizations = new Hash(); - } + private void PrepareOptionLocalizations(CommandOption opt) + { + opt.NameLocalizations ??= new Hash(); + opt.DescriptionLocalizations ??= new Hash(); - if (opt.Options != null) + if (opt.Options != null) + { + for (int index = 0; index < opt.Options.Count; index++) { - for (int index = 0; index < opt.Options.Count; index++) - { - PrepareOptionLocalizations(opt.Options[index]); - } + PrepareOptionLocalizations(opt.Options[index]); } + } - if (opt.Choices != null) + if (opt.Choices != null) + { + for (int i = 0; i < opt.Choices.Count; i++) { - for (int i = 0; i < opt.Choices.Count; i++) + CommandOptionChoice choice = opt.Choices[i]; + if (choice.NameLocalizations == null) { - CommandOptionChoice choice = opt.Choices[i]; - if (choice.NameLocalizations == null) - { - choice.NameLocalizations = new Hash(); - } + choice.NameLocalizations = new Hash(); } } } + } - private void HandleLoadAndApplyCommandLocalizationsAsync(TemplateId id, CommandCreate create, ServerLocale locale) + private void HandleLoadAndApplyCommandLocalizationsAsync(TemplateId id, CommandCreate create, ServerLocale locale) + { + DiscordLocale discordLocale = locale.GetDiscordLocale(); + if (discordLocale.IsValid) { - DiscordLocale discordLocale = locale.GetDiscordLocale(); - if (discordLocale.IsValid) - { - DiscordTemplate localization = LoadTemplate(id.WithLanguage(locale)); - localization?.Template.ApplyCommandLocalization(create, discordLocale); - } + DiscordTemplate localization = LoadTemplate(id.WithLanguage(locale)); + localization?.Template.ApplyCommandLocalization(create, discordLocale); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Components/BaseComponentTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Components/BaseComponentTemplate.cs index 485a89371..7d6aec3ce 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Components/BaseComponentTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Components/BaseComponentTemplate.cs @@ -2,46 +2,45 @@ using Newtonsoft.Json.Converters; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Base Template for Message Components +/// +public abstract class BaseComponentTemplate { /// - /// Base Template for Message Components + /// If the component should be added to the message /// - public abstract class BaseComponentTemplate - { - /// - /// If the component should be added to the message - /// - [JsonProperty("Show Component")] - public bool Visible { get; set; } = true; + [JsonProperty("Show Component")] + public bool Visible { get; set; } = true; - /// - /// Type of the component - /// - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("Type")] - public MessageComponentType Type { get; set; } + /// + /// Type of the component + /// + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("Type")] + public MessageComponentType Type { get; set; } - /// - /// Constructor - /// - [JsonConstructor] - protected BaseComponentTemplate() { } + /// + /// Constructor + /// + [JsonConstructor] + protected BaseComponentTemplate() { } - /// - /// Represents a base Message Component Template - /// - /// - protected BaseComponentTemplate(MessageComponentType type) - { - Type = type; - } - - /// - /// Returns the built component - /// - /// to use - /// Component - public abstract BaseComponent ToComponent(PlaceholderData data); + /// + /// Represents a base Message Component Template + /// + /// + protected BaseComponentTemplate(MessageComponentType type) + { + Type = type; } + + /// + /// Returns the built component + /// + /// to use + /// Component + public abstract BaseComponent ToComponent(PlaceholderData data); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Components/ButtonTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Components/ButtonTemplate.cs index 49d5038c3..570cad37e 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Components/ButtonTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Components/ButtonTemplate.cs @@ -2,124 +2,123 @@ using Newtonsoft.Json.Converters; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Template for Button Components +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class ButtonTemplate : BaseComponentTemplate { /// - /// Template for Button Components + /// Display label for the button /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class ButtonTemplate : BaseComponentTemplate - { - /// - /// Display label for the button - /// - [JsonProperty("Button Label")] - public string Label { get; set; } = "Button Label"; + [JsonProperty("Button Label")] + public string Label { get; set; } = "Button Label"; - /// - /// Emoji for the button - /// - [JsonProperty("Button Emoji")] - public EmojiTemplate Emoji { get; set; } = new EmojiTemplate(); + /// + /// Emoji for the button + /// + [JsonProperty("Button Emoji")] + public EmojiTemplate Emoji { get; set; } = new(); - /// - /// for the button - /// - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("Button Style")] - public ButtonStyle Style { get; set; } = ButtonStyle.Primary; + /// + /// for the button + /// + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("Button Style")] + public ButtonStyle Style { get; set; } = ButtonStyle.Primary; - /// - /// Command for the button. If then this will set the Url field; Else the CustomId field - /// - [JsonProperty("Button Command")] - public string Command { get; set; } = "My Command"; + /// + /// Command for the button. If then this will set the Url field; Else the CustomId field + /// + [JsonProperty("Button Command")] + public string Command { get; set; } = "My Command"; - /// - /// Should the button be on the same or new row - /// - [JsonProperty("Keep Button On Same Row")] - public bool Inline { get; set; } = true; + /// + /// Should the button be on the same or new row + /// + [JsonProperty("Keep Button On Same Row")] + public bool Inline { get; set; } = true; - /// - /// If the Button is enabled - /// - [JsonProperty("Button Enabled")] - public bool Enabled { get; set; } = true; + /// + /// If the Button is enabled + /// + [JsonProperty("Button Enabled")] + public bool Enabled { get; set; } = true; - /// - /// Default Constructor - /// - [JsonConstructor] - public ButtonTemplate() : base(MessageComponentType.Button) { } + /// + /// Default Constructor + /// + [JsonConstructor] + public ButtonTemplate() : base(MessageComponentType.Button) { } - /// - /// Constructor without emoji - /// - /// Button Label - /// - /// Button Command - /// Is button enabled? - /// Should the button be on the same row or a new row? - public ButtonTemplate(string label, ButtonStyle style, string command, bool enabled = true, bool inline = true) : this(label, style, command, null, enabled, inline) { } + /// + /// Constructor without emoji + /// + /// Button Label + /// + /// Button Command + /// Is button enabled? + /// Should the button be on the same row or a new row? + public ButtonTemplate(string label, ButtonStyle style, string command, bool enabled = true, bool inline = true) : this(label, style, command, null, enabled, inline) { } - /// - /// Constructor with emoji - /// - /// Button Label - /// - /// Button Command - /// Emoji for the button - /// Is button enabled? - /// Should the button be on the same row or a new row? - public ButtonTemplate(string label, ButtonStyle style, string command, string emoji, bool enabled = true, bool inline = true) : this() + /// + /// Constructor with emoji + /// + /// Button Label + /// + /// Button Command + /// Emoji for the button + /// Is button enabled? + /// Should the button be on the same row or a new row? + public ButtonTemplate(string label, ButtonStyle style, string command, string emoji, bool enabled = true, bool inline = true) : this() + { + Label = label; + Style = style; + Command = command; + Emoji = new EmojiTemplate { - Label = label; - Style = style; - Command = command; - Emoji = new EmojiTemplate - { - Emoji = emoji - }; - Enabled = enabled; - Inline = inline; - } + Emoji = emoji + }; + Enabled = enabled; + Inline = inline; + } - /// - /// Converts the template to a - /// - /// - public override BaseComponent ToComponent(PlaceholderData data) + /// + /// Converts the template to a + /// + /// + public override BaseComponent ToComponent(PlaceholderData data) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + string command = placeholders.ProcessPlaceholders(Command, data); + if (string.IsNullOrEmpty(command)) { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - string command = placeholders.ProcessPlaceholders(Command, data); - if (string.IsNullOrEmpty(command)) - { - return null; - } + return null; + } - data?.IncrementDepth(); - ButtonComponent button = new ButtonComponent - { - Label = placeholders.ProcessPlaceholders(Label, data), - Style = Style, - Disabled = !Enabled, - Emoji = Emoji?.ToEmoji() - }; + data?.IncrementDepth(); + ButtonComponent button = new() + { + Label = placeholders.ProcessPlaceholders(Label, data), + Style = Style, + Disabled = !Enabled, + Emoji = Emoji?.ToEmoji() + }; - if (Style == ButtonStyle.Link) - { - button.Url = command; - } - else - { - button.CustomId = command; - } + if (Style == ButtonStyle.Link) + { + button.Url = command; + } + else + { + button.CustomId = command; + } - data?.DecrementDepth(); - data?.AutoDispose(); + data?.DecrementDepth(); + data?.AutoDispose(); - return button; - } + return button; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordButtonTemplates.cs b/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordButtonTemplates.cs index ee8fcc11f..bc1937991 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordButtonTemplates.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordButtonTemplates.cs @@ -1,16 +1,15 @@ using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Button Templates Library +/// +public class DiscordButtonTemplates : BaseMessageTemplateLibrary { /// - /// Button Templates Library + /// Constructor /// - public class DiscordButtonTemplates : BaseMessageTemplateLibrary - { - /// - /// Constructor - /// - /// - internal DiscordButtonTemplates(ILogger logger) : base(TemplateType.ButtonComponent, logger) { } - } + /// + internal DiscordButtonTemplates(ILogger logger) : base(TemplateType.ButtonComponent, logger) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordInputTextTemplates.cs b/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordInputTextTemplates.cs index 8d3270750..848741b10 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordInputTextTemplates.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordInputTextTemplates.cs @@ -1,16 +1,15 @@ using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// InputText Templates Library +/// +public class DiscordInputTextTemplates : BaseMessageTemplateLibrary { /// - /// InputText Templates Library + /// Constructor /// - public class DiscordInputTextTemplates : BaseMessageTemplateLibrary - { - /// - /// Constructor - /// - /// - internal DiscordInputTextTemplates(ILogger logger) : base(TemplateType.InputTextComponent, logger) { } - } + /// + internal DiscordInputTextTemplates(ILogger logger) : base(TemplateType.InputTextComponent, logger) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordSelectMenuTemplates.cs b/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordSelectMenuTemplates.cs index 166698cc2..b15e7cb6c 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordSelectMenuTemplates.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Components/DiscordSelectMenuTemplates.cs @@ -1,16 +1,15 @@ using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// InputText Templates Library +/// +public class DiscordSelectMenuTemplates : BaseMessageTemplateLibrary { /// - /// InputText Templates Library + /// Constructor /// - public class DiscordSelectMenuTemplates : BaseMessageTemplateLibrary - { - /// - /// Constructor - /// - /// - internal DiscordSelectMenuTemplates(ILogger logger) : base(TemplateType.SelectMenuComponent, logger) { } - } + /// + internal DiscordSelectMenuTemplates(ILogger logger) : base(TemplateType.SelectMenuComponent, logger) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Components/InputTextTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Components/InputTextTemplate.cs index 33669e6fa..389320ed9 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Components/InputTextTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Components/InputTextTemplate.cs @@ -2,114 +2,113 @@ using Newtonsoft.Json.Converters; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Input Text Message Component Template +/// +public class InputTextTemplate : BaseComponentTemplate { /// - /// Input Text Message Component Template + /// Custom ID of the input text /// - public class InputTextTemplate : BaseComponentTemplate - { - /// - /// Custom ID of the input text - /// - [JsonProperty("Input Text ID")] - public string CustomId { get; set; } = string.Empty; + [JsonProperty("Input Text ID")] + public string CustomId { get; set; } = string.Empty; - /// - /// The style of the input text - /// - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("Input Text Style")] - public InputTextStyles Style { get; set; } = InputTextStyles.Short; + /// + /// The style of the input text + /// + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("Input Text Style")] + public InputTextStyles Style { get; set; } = InputTextStyles.Short; - /// - /// Text that appears on top of the input text field, max 80 characters - /// - [JsonProperty("Input Text Label")] - public string Label { get; set; } = string.Empty; + /// + /// Text that appears on top of the input text field, max 80 characters + /// + [JsonProperty("Input Text Label")] + public string Label { get; set; } = string.Empty; - /// - /// The minimum length of the text input - /// - [JsonProperty("Input Text Min Length")] - public int MinLength { get; set; } + /// + /// The minimum length of the text input + /// + [JsonProperty("Input Text Min Length")] + public int MinLength { get; set; } - /// - /// The maximum length of the text input - /// - [JsonProperty("Input Text Max Length")] - public int MaxLength { get; set; } = 4000; + /// + /// The maximum length of the text input + /// + [JsonProperty("Input Text Max Length")] + public int MaxLength { get; set; } = 4000; - /// - /// The placeholder for the text input field - /// - [JsonProperty("Input Text Placeholder")] - public string Placeholder { get; set; } = string.Empty; + /// + /// The placeholder for the text input field + /// + [JsonProperty("Input Text Placeholder")] + public string Placeholder { get; set; } = string.Empty; - /// - /// The pre-filled value for text input - /// - [JsonProperty("Input Text Value")] - public string Value { get; set; } = string.Empty; + /// + /// The pre-filled value for text input + /// + [JsonProperty("Input Text Value")] + public string Value { get; set; } = string.Empty; - /// - /// Is the Input Text Required to be filled out - /// - [JsonProperty("Input Text Required")] - public bool Required { get; set; } + /// + /// Is the Input Text Required to be filled out + /// + [JsonProperty("Input Text Required")] + public bool Required { get; set; } - /// - /// Constructor - /// - [JsonConstructor] - public InputTextTemplate() : base(MessageComponentType.InputText) { } + /// + /// Constructor + /// + [JsonConstructor] + public InputTextTemplate() : base(MessageComponentType.InputText) { } - /// - /// Constructor - /// - /// - /// - /// - /// - /// - /// - /// - /// - public InputTextTemplate(string label, string customId, string value = "", InputTextStyles style = InputTextStyles.Short, bool required = false, string placeholder = "", int minLength = 0, int maxLength = 4000) : this() - { - Label = label; - CustomId = customId; - Value = value; - Style = style; - Required = required; - Placeholder = placeholder; - MinLength = minLength; - MaxLength = maxLength; - } + /// + /// Constructor + /// + /// + /// + /// + /// + /// + /// + /// + /// + public InputTextTemplate(string label, string customId, string value = "", InputTextStyles style = InputTextStyles.Short, bool required = false, string placeholder = "", int minLength = 0, int maxLength = 4000) : this() + { + Label = label; + CustomId = customId; + Value = value; + Style = style; + Required = required; + Placeholder = placeholder; + MinLength = minLength; + MaxLength = maxLength; + } - /// - /// Converts the template to a - /// - /// - /// - public override BaseComponent ToComponent(PlaceholderData data) + /// + /// Converts the template to a + /// + /// + /// + public override BaseComponent ToComponent(PlaceholderData data) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + data?.IncrementDepth(); + InputTextComponent text = new() { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - data?.IncrementDepth(); - InputTextComponent text = new InputTextComponent - { - Label = placeholders.ProcessPlaceholders(Label, data), - Placeholder = placeholders.ProcessPlaceholders(Placeholder, data), - Value = placeholders.ProcessPlaceholders(Value, data), - Required = Required, - Style = Style, - MinLength = MinLength, - MaxLength = MaxLength, - CustomId = CustomId - }; - data?.DecrementDepth(); - data?.AutoDispose(); - return text; - } + Label = placeholders.ProcessPlaceholders(Label, data), + Placeholder = placeholders.ProcessPlaceholders(Placeholder, data), + Value = placeholders.ProcessPlaceholders(Value, data), + Required = Required, + Style = Style, + MinLength = MinLength, + MaxLength = MaxLength, + CustomId = CustomId + }; + data?.DecrementDepth(); + data?.AutoDispose(); + return text; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Components/SelectMenuOptionTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Components/SelectMenuOptionTemplate.cs index 238bfcabe..459ba01f4 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Components/SelectMenuOptionTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Components/SelectMenuOptionTemplate.cs @@ -1,93 +1,92 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Template for Select Menu Options +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class SelectMenuOptionTemplate { /// - /// Template for Select Menu Options + /// The user-facing name of the option, + /// Max 100 characters /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class SelectMenuOptionTemplate - { - /// - /// The user-facing name of the option, - /// Max 100 characters - /// - [JsonProperty("Label")] - public string Label { get; set; } = string.Empty; + [JsonProperty("Label")] + public string Label { get; set; } = string.Empty; - /// - /// The dev-define value of the option, - /// Max 100 characters - /// - [JsonProperty("Value")] - public string Value { get; set; } = string.Empty; + /// + /// The dev-define value of the option, + /// Max 100 characters + /// + [JsonProperty("Value")] + public string Value { get; set; } = string.Empty; - /// - /// An additional description of the option, - /// Max 100 characters - /// - [JsonProperty("Description")] - public string Description { get; set; } = string.Empty; + /// + /// An additional description of the option, + /// Max 100 characters + /// + [JsonProperty("Description")] + public string Description { get; set; } = string.Empty; - /// - /// Emoji in the option - /// - [JsonProperty("Emoji")] - public EmojiTemplate Emoji { get; set; } + /// + /// Emoji in the option + /// + [JsonProperty("Emoji")] + public EmojiTemplate Emoji { get; set; } - /// - /// Will render this option as selected by default - /// - [JsonProperty("default")] - public bool Default { get; set; } + /// + /// Will render this option as selected by default + /// + [JsonProperty("default")] + public bool Default { get; set; } - /// - /// Constructor - /// - [JsonConstructor] - public SelectMenuOptionTemplate() - { - Emoji = new EmojiTemplate(); - } + /// + /// Constructor + /// + [JsonConstructor] + public SelectMenuOptionTemplate() + { + Emoji = new EmojiTemplate(); + } - /// - /// Constructor - /// - /// - /// - /// - /// - /// - public SelectMenuOptionTemplate(string label, string value, string description = "", EmojiTemplate emoji = null, bool @default = false) - { - Label = label; - Value = value; - Description = description; - Emoji = emoji ?? new EmojiTemplate(); - Default = @default; - } + /// + /// Constructor + /// + /// + /// + /// + /// + /// + public SelectMenuOptionTemplate(string label, string value, string description = "", EmojiTemplate emoji = null, bool @default = false) + { + Label = label; + Value = value; + Description = description; + Emoji = emoji ?? new EmojiTemplate(); + Default = @default; + } - /// - /// Converts the template to - /// - /// to use - /// - public SelectMenuOption ToOption(PlaceholderData data) + /// + /// Converts the template to + /// + /// to use + /// + public SelectMenuOption ToOption(PlaceholderData data) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + data?.IncrementDepth(); + SelectMenuOption option = new() { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - data?.IncrementDepth(); - SelectMenuOption option = new SelectMenuOption - { - Label = placeholders.ProcessPlaceholders(Label, data), - Value = placeholders.ProcessPlaceholders(Value, data), - Description = placeholders.ProcessPlaceholders(Description, data), - Emoji = Emoji.ToEmoji(), - Default = Default - }; - data?.DecrementDepth(); - data?.AutoDispose(); - return option; - } + Label = placeholders.ProcessPlaceholders(Label, data), + Value = placeholders.ProcessPlaceholders(Value, data), + Description = placeholders.ProcessPlaceholders(Description, data), + Emoji = Emoji.ToEmoji(), + Default = Default + }; + data?.DecrementDepth(); + data?.AutoDispose(); + return option; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Components/SelectMenuTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Components/SelectMenuTemplate.cs index 9f1ea650d..e8c3b5ba2 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Components/SelectMenuTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Components/SelectMenuTemplate.cs @@ -4,131 +4,130 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a template for select menus +/// +public class SelectMenuTemplate : BaseComponentTemplate { /// - /// Represents a template for select menus + /// Command for the Select Menu /// - public class SelectMenuTemplate : BaseComponentTemplate - { - /// - /// Command for the Select Menu - /// - [JsonProperty("Select Menu ID")] - public string CustomId { get; set; } = string.Empty; + [JsonProperty("Select Menu ID")] + public string CustomId { get; set; } = string.Empty; - /// - /// Custom placeholder text if nothing is selected - /// Max 150 characters - /// - [JsonProperty("Select Menu Placeholder Text")] - public string Placeholder { get; set; } + /// + /// Custom placeholder text if nothing is selected + /// Max 150 characters + /// + [JsonProperty("Select Menu Placeholder Text")] + public string Placeholder { get; set; } - /// - /// The choices in the select - /// Max 25 options - /// - [JsonProperty("Select Menu Options")] - public List Options { get; set; } + /// + /// The choices in the select + /// Max 25 options + /// + [JsonProperty("Select Menu Options")] + public List Options { get; set; } - /// - /// to show - /// Max 25 options - /// - [JsonProperty("Select Menu Channel Types")] - public List ChannelTypes { get; set; } = new List(); + /// + /// to show + /// Max 25 options + /// + [JsonProperty("Select Menu Channel Types")] + public List ChannelTypes { get; set; } = new(); - /// - /// the minimum number of items that must be chosen - /// Default 1, Min 0, Max 25 - /// - [JsonProperty("Select Menu Min Selected Values")] - public int MinValues { get; set; } = 1; + /// + /// the minimum number of items that must be chosen + /// Default 1, Min 0, Max 25 + /// + [JsonProperty("Select Menu Min Selected Values")] + public int MinValues { get; set; } = 1; - /// - /// the maximum number of items that must be chosen - /// Default 1, Min 0, Max 25 - /// - [JsonProperty("Select Menu Max Selected Values")] - public int MaxValues { get; set; } = 1; + /// + /// the maximum number of items that must be chosen + /// Default 1, Min 0, Max 25 + /// + [JsonProperty("Select Menu Max Selected Values")] + public int MaxValues { get; set; } = 1; - /// - /// If the Button is enabled - /// - [JsonProperty("Select Menu Enabled")] - public bool Enabled { get; set; } = true; + /// + /// If the Button is enabled + /// + [JsonProperty("Select Menu Enabled")] + public bool Enabled { get; set; } = true; - /// - /// Constructor - /// - [JsonConstructor] - public SelectMenuTemplate() { } + /// + /// Constructor + /// + [JsonConstructor] + public SelectMenuTemplate() { } - /// - /// Constructor - /// - /// - public SelectMenuTemplate(MessageComponentType type) : base(type) - { - InvalidSelectMenuComponentException.ThrowIfInvalidComponentType(type); - } + /// + /// Constructor + /// + /// + public SelectMenuTemplate(MessageComponentType type) : base(type) + { + InvalidSelectMenuComponentException.ThrowIfInvalidComponentType(type); + } - /// - public override BaseComponent ToComponent(PlaceholderData data) + /// + public override BaseComponent ToComponent(PlaceholderData data) + { + data?.IncrementDepth(); + BaseSelectMenuComponent component; + switch (Type) { - data?.IncrementDepth(); - BaseSelectMenuComponent component; - switch (Type) - { - case MessageComponentType.StringSelect: - StringSelectComponent text = new StringSelectComponent(); - component = text; - if (Options != null) + case MessageComponentType.StringSelect: + StringSelectComponent text = new(); + component = text; + if (Options != null) + { + for (int index = 0; index < Options.Count; index++) { - for (int index = 0; index < Options.Count; index++) - { - text.Options.Add(Options[index].ToOption(data)); - } + text.Options.Add(Options[index].ToOption(data)); } - break; + } + break; - case MessageComponentType.UserSelect: - component = new UserSelectComponent(); - break; + case MessageComponentType.UserSelect: + component = new UserSelectComponent(); + break; - case MessageComponentType.RoleSelect: - component = new RoleSelectComponent(); - break; + case MessageComponentType.RoleSelect: + component = new RoleSelectComponent(); + break; - case MessageComponentType.MentionableSelect: - component = new MentionableSelectComponent(); - break; + case MessageComponentType.MentionableSelect: + component = new MentionableSelectComponent(); + break; - case MessageComponentType.ChannelSelect: - ChannelSelectComponent channel = new ChannelSelectComponent(); - component = channel; - channel.ChannelTypes = ChannelTypes = ChannelTypes != null && ChannelTypes.Count != 0 ? ChannelTypes : null; - break; + case MessageComponentType.ChannelSelect: + ChannelSelectComponent channel = new(); + component = channel; + channel.ChannelTypes = ChannelTypes = ChannelTypes != null && ChannelTypes.Count != 0 ? ChannelTypes : null; + break; - default: - throw new ArgumentOutOfRangeException(); - } + default: + throw new ArgumentOutOfRangeException(); + } - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - component.CustomId = placeholders.ProcessPlaceholders(CustomId, data); - component.Placeholder = placeholders.ProcessPlaceholders(Placeholder, data); - component.MinValues = MinValues; - component.MaxValues = MaxValues; - component.Disabled = !Enabled; + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + component.CustomId = placeholders.ProcessPlaceholders(CustomId, data); + component.Placeholder = placeholders.ProcessPlaceholders(Placeholder, data); + component.MinValues = MinValues; + component.MaxValues = MaxValues; + component.Disabled = !Enabled; - data?.DecrementDepth(); - data?.AutoDispose(); + data?.DecrementDepth(); + data?.AutoDispose(); - return component; - } - - private bool ShouldSerializeOptions() => Type == MessageComponentType.StringSelect; - private bool ShouldSerializeChannelTypes() => Type == MessageComponentType.ChannelSelect; + return component; } + + private bool ShouldSerializeOptions() => Type == MessageComponentType.StringSelect; + private bool ShouldSerializeChannelTypes() => Type == MessageComponentType.ChannelSelect; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/DiscordTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/DiscordTemplate.cs index 891454098..57a829e98 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/DiscordTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/DiscordTemplate.cs @@ -1,35 +1,34 @@ using System; using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Base Template used in Discord Templates +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +internal sealed class DiscordTemplate where TTemplate : class { /// - /// Base Template used in Discord Templates + /// Template Data for the template /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - internal sealed class DiscordTemplate where TTemplate : class - { - /// - /// Template Data for the template - /// - [JsonProperty("Template", Order = 1)] - public TTemplate Template { get; private set;} + [JsonProperty("Template", Order = 1)] + public TTemplate Template { get; private set;} - /// - /// The version of the Template - /// Used when Registering templates to determine if we need to backup a template and create a new template for the given version - /// - [JsonProperty("Template Version", Order = 1000)] - public TemplateVersion Version { get; set; } = new TemplateVersion(1, 0, 0); + /// + /// The version of the Template + /// Used when Registering templates to determine if we need to backup a template and create a new template for the given version + /// + [JsonProperty("Template Version", Order = 1000)] + public TemplateVersion Version { get; set; } = new(1, 0, 0); - // ReSharper disable once UnusedMember.Local - [JsonConstructor] - private DiscordTemplate() { } + // ReSharper disable once UnusedMember.Local + [JsonConstructor] + private DiscordTemplate() { } - public DiscordTemplate(TTemplate template, TemplateVersion version) - { - Template = template ?? throw new ArgumentNullException(nameof(template)); - Version = version; - } + public DiscordTemplate(TTemplate template, TemplateVersion version) + { + Template = template ?? throw new ArgumentNullException(nameof(template)); + Version = version; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedFieldTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedFieldTemplate.cs index d800505b2..c447042d4 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedFieldTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedFieldTemplate.cs @@ -5,101 +5,97 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Discord Template for Embed Field +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordEmbedFieldTemplate : IBulkTemplate { /// - /// Discord Template for Embed Field + /// Title of the field /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordEmbedFieldTemplate : IBulkTemplate - { - /// - /// Title of the field - /// - [JsonProperty("Field Title")] - public string Name { get; set; } = string.Empty; + [JsonProperty("Field Title")] + public string Name { get; set; } = string.Empty; - /// - /// Value of the field - /// - [JsonProperty("Field Value")] - public string Value { get; set; } = string.Empty; + /// + /// Value of the field + /// + [JsonProperty("Field Value")] + public string Value { get; set; } = string.Empty; - /// - /// Should the field be on the same row - /// - [JsonProperty("Keep Field On Same Row")] - public bool Inline { get; set; } = true; + /// + /// Should the field be on the same row + /// + [JsonProperty("Keep Field On Same Row")] + public bool Inline { get; set; } = true; - /// - /// Hides the field if the value is null, empty, or \u200b - /// - [JsonProperty("Hide Field If Value Empty")] - public bool HideIfEmpty { get; set; } = false; + /// + /// Hides the field if the value is null, empty, or \u200b + /// + [JsonProperty("Hide Field If Value Empty")] + public bool HideIfEmpty { get; set; } = false; - /// - /// Constructor - /// - [JsonConstructor] - public DiscordEmbedFieldTemplate() { } + /// + /// Constructor + /// + [JsonConstructor] + public DiscordEmbedFieldTemplate() { } - /// - /// Constructor - /// - /// - /// - /// - public DiscordEmbedFieldTemplate(string name, string value, bool inline = true) - { - Name = name; - Value = value; - Inline = inline; - } + /// + /// Constructor + /// + /// + /// + /// + public DiscordEmbedFieldTemplate(string name, string value, bool inline = true) + { + Name = name; + Value = value; + Inline = inline; + } - /// - /// Converts the template to an - /// - /// Data to use - /// Initial field (Optional) - /// - public EmbedField ToEntity(PlaceholderData data = null, EmbedField field = null) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + /// + /// Converts the template to an + /// + /// Data to use + /// Initial field (Optional) + /// + public EmbedField ToEntity(PlaceholderData data = null, EmbedField field = null) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - data?.IncrementDepth(); + data?.IncrementDepth(); - if (field == null) - { - field = new EmbedField(); - } + field ??= new EmbedField(); - string value = placeholders.ProcessPlaceholders(Value, data); - if (string.IsNullOrEmpty(value) || value == EmbedField.Blank) + string value = placeholders.ProcessPlaceholders(Value, data); + if (string.IsNullOrEmpty(value) || value == EmbedField.Blank) + { + if (HideIfEmpty) { - if (HideIfEmpty) - { - return null; - } - - Value = EmbedField.Blank; + return null; } + + Value = EmbedField.Blank; + } - field.Name = placeholders.ProcessPlaceholders(Name, data); - field.Value = value; - field.Inline = Inline; + field.Name = placeholders.ProcessPlaceholders(Name, data); + field.Value = value; + field.Inline = Inline; - data?.DecrementDepth(); - data?.AutoDispose(); + data?.DecrementDepth(); + data?.AutoDispose(); - return field; - } + return field; + } - /// - public IPromise> ToEntityBulk(List data) - { - IPendingPromise> promise = Promise>.Create(); - BulkToEntityCallback.Start(this, data, promise); - return promise; - } + /// + public IPromise> ToEntityBulk(List data) + { + IPendingPromise> promise = Promise>.Create(); + BulkToEntityCallback.Start(this, data, promise); + return promise; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedFieldTemplates.cs b/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedFieldTemplates.cs index 8d658ed69..c6afbf26d 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedFieldTemplates.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedFieldTemplates.cs @@ -1,16 +1,15 @@ using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Embed Field Templates Library +/// +public class DiscordEmbedFieldTemplates : BaseMessageTemplateLibrary { /// - /// Embed Field Templates Library + /// Constructor /// - public class DiscordEmbedFieldTemplates : BaseMessageTemplateLibrary - { - /// - /// Constructor - /// - /// - internal DiscordEmbedFieldTemplates(ILogger logger) : base(TemplateType.EmbedField, logger) { } - } + /// + internal DiscordEmbedFieldTemplates(ILogger logger) : base(TemplateType.EmbedField, logger) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedTemplate.cs index 91c83d51e..a963fcf71 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedTemplate.cs @@ -7,176 +7,172 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Discord Template for embed +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordEmbedTemplate : IBulkTemplate { /// - /// Discord Template for embed + /// If this embed is enabled /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordEmbedTemplate : IBulkTemplate - { - /// - /// If this embed is enabled - /// - [JsonProperty("Show Embed")] - public bool Enabled { get; set; } = true; - - /// - /// The Tile for the embed - /// - [JsonProperty("Embed Title")] - public string Title { get; set; } = string.Empty; - - /// - /// This Title Url for the embed - /// - [JsonProperty("Embed Title URL")] - public string Url { get; set; } = string.Empty; - - /// - /// The description of the embed - /// - [JsonProperty("Embed Description")] - public string Description { get; set; } = string.Empty; - - /// - /// The Hex Color for the embed - /// - [JsonProperty("Embed Hex Color")] - public string Color { get; set; } = DiscordColor.Default.ToHex(); - - /// - /// Image URL to show in the embed - /// - [JsonProperty("Embed Image URL")] - public string ImageUrl { get; set; } = string.Empty; - - /// - /// Thumbnail url to show in the embed - /// - [JsonProperty("Embed Thumbnail URL")] - public string ThumbnailUrl { get; set; } = string.Empty; - - /// - /// Video url to show in the embed - /// - [JsonProperty("Embed Video Url")] - public string VideoUrl { get; set; } = string.Empty; - - /// - /// Show timestamp in the embed - /// - [JsonProperty("Show Embed TimeStamp")] - public bool TimeStamp { get; set; } = false; - - /// - /// Fields for the embed - /// - [JsonProperty("Embed Fields")] - public List Fields { get; set; } = new List(); - - /// - /// Footer for the embed - /// - [JsonProperty("Embed Footer")] - public EmbedFooterTemplate Footer { get; set; } = new EmbedFooterTemplate(); + [JsonProperty("Show Embed")] + public bool Enabled { get; set; } = true; + + /// + /// The Tile for the embed + /// + [JsonProperty("Embed Title")] + public string Title { get; set; } = string.Empty; + + /// + /// This Title Url for the embed + /// + [JsonProperty("Embed Title URL")] + public string Url { get; set; } = string.Empty; + + /// + /// The description of the embed + /// + [JsonProperty("Embed Description")] + public string Description { get; set; } = string.Empty; + + /// + /// The Hex Color for the embed + /// + [JsonProperty("Embed Hex Color")] + public string Color { get; set; } = DiscordColor.Default.ToHex(); + + /// + /// Image URL to show in the embed + /// + [JsonProperty("Embed Image URL")] + public string ImageUrl { get; set; } = string.Empty; + + /// + /// Thumbnail url to show in the embed + /// + [JsonProperty("Embed Thumbnail URL")] + public string ThumbnailUrl { get; set; } = string.Empty; + + /// + /// Video url to show in the embed + /// + [JsonProperty("Embed Video Url")] + public string VideoUrl { get; set; } = string.Empty; + + /// + /// Show timestamp in the embed + /// + [JsonProperty("Show Embed TimeStamp")] + public bool TimeStamp { get; set; } = false; + + /// + /// Fields for the embed + /// + [JsonProperty("Embed Fields")] + public List Fields { get; set; } = new(); + + /// + /// Footer for the embed + /// + [JsonProperty("Embed Footer")] + public EmbedFooterTemplate Footer { get; set; } = new(); - /// - /// Constructor - /// - [JsonConstructor] - public DiscordEmbedTemplate() { } - - /// - /// Constructor - /// - /// - /// - /// - public DiscordEmbedTemplate(string title, string description, string titleUrl = "") - { - Title = title; - Description = description; - Url = titleUrl; - } + /// + /// Constructor + /// + [JsonConstructor] + public DiscordEmbedTemplate() { } - /// - /// Converts the template to a - /// - /// Data to use - /// Initial embed to use - /// - public DiscordEmbed ToEntity(PlaceholderData data = null, DiscordEmbed embed = null) - { - if (embed == null) - { - embed = new DiscordEmbed(); - } + /// + /// Constructor + /// + /// + /// + /// + public DiscordEmbedTemplate(string title, string description, string titleUrl = "") + { + Title = title; + Description = description; + Url = titleUrl; + } + + /// + /// Converts the template to a + /// + /// Data to use + /// Initial embed to use + /// + public DiscordEmbed ToEntity(PlaceholderData data = null, DiscordEmbed embed = null) + { + embed ??= new DiscordEmbed(); - data?.IncrementDepth(); + data?.IncrementDepth(); - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - embed.Title = placeholders.ProcessPlaceholders(Title, data); - embed.Url = placeholders.ProcessPlaceholders(Url, data); - embed.Description = placeholders.ProcessPlaceholders(Description, data); - embed.Color = !string.IsNullOrEmpty(Color) ? new DiscordColor(placeholders.ProcessPlaceholders(Color, data)) : (DiscordColor?)null; - embed.Timestamp = TimeStamp ? DateTime.UtcNow : (DateTime?)null; + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + embed.Title = placeholders.ProcessPlaceholders(Title, data); + embed.Url = placeholders.ProcessPlaceholders(Url, data); + embed.Description = placeholders.ProcessPlaceholders(Description, data); + embed.Color = !string.IsNullOrEmpty(Color) ? new DiscordColor(placeholders.ProcessPlaceholders(Color, data)) : null; + embed.Timestamp = TimeStamp ? DateTime.UtcNow : null; - if (!string.IsNullOrEmpty(ImageUrl)) + if (!string.IsNullOrEmpty(ImageUrl)) + { + embed.Image = new EmbedImage { - embed.Image = new EmbedImage - { - Url = placeholders.ProcessPlaceholders(ImageUrl, data) - }; - } + Url = placeholders.ProcessPlaceholders(ImageUrl, data) + }; + } - if (!string.IsNullOrEmpty(ThumbnailUrl)) + if (!string.IsNullOrEmpty(ThumbnailUrl)) + { + embed.Thumbnail = new EmbedThumbnail { - embed.Thumbnail = new EmbedThumbnail - { - Url = placeholders.ProcessPlaceholders(ThumbnailUrl, data) - }; - } + Url = placeholders.ProcessPlaceholders(ThumbnailUrl, data) + }; + } - if (!string.IsNullOrEmpty(VideoUrl)) + if (!string.IsNullOrEmpty(VideoUrl)) + { + embed.Video = new EmbedVideo { - embed.Video = new EmbedVideo - { - Url = placeholders.ProcessPlaceholders(ThumbnailUrl, data) - }; - } + Url = placeholders.ProcessPlaceholders(ThumbnailUrl, data) + }; + } - if (Fields != null && Fields.Count != 0) + if (Fields != null && Fields.Count != 0) + { + InvalidEmbedException.ThrowIfInvalidFieldCount(Fields.Count); + embed.Fields = new List(); + for (int index = 0; index < Fields.Count; index++) { - InvalidEmbedException.ThrowIfInvalidFieldCount(Fields.Count); - embed.Fields = new List(); - for (int index = 0; index < Fields.Count; index++) + EmbedField field = Fields[index].ToEntity(data); + if (field != null) { - EmbedField field = Fields[index].ToEntity(data); - if (field != null) - { - embed.Fields.Add(field); - } + embed.Fields.Add(field); } } - - if (Footer != null && Footer.Enabled) - { - embed.Footer = Footer.ToFooter(data); - } - - data?.DecrementDepth(); - data?.AutoDispose(); - - return embed; } - /// - public IPromise> ToEntityBulk(List data = null) + if (Footer != null && Footer.Enabled) { - IPendingPromise> promise = Promise>.Create(); - BulkToEntityCallback.Start(this, data, promise); - return promise; + embed.Footer = Footer.ToFooter(data); } + + data?.DecrementDepth(); + data?.AutoDispose(); + + return embed; + } + + /// + public IPromise> ToEntityBulk(List data = null) + { + IPendingPromise> promise = Promise>.Create(); + BulkToEntityCallback.Start(this, data, promise); + return promise; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedTemplates.cs b/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedTemplates.cs index 8811c47e7..56b7fd8a1 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedTemplates.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Embeds/DiscordEmbedTemplates.cs @@ -1,16 +1,15 @@ using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Embed Templates Library +/// +public class DiscordEmbedTemplates : BaseMessageTemplateLibrary { /// - /// Embed Templates Library + /// Constructor /// - public class DiscordEmbedTemplates : BaseMessageTemplateLibrary - { - /// - /// Constructor - /// - /// - internal DiscordEmbedTemplates(ILogger logger) : base(TemplateType.Embed, logger) { } - } + /// + internal DiscordEmbedTemplates(ILogger logger) : base(TemplateType.Embed, logger) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Embeds/EmbedFooterTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Embeds/EmbedFooterTemplate.cs index 33da52ebc..3d35a7fe5 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Embeds/EmbedFooterTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Embeds/EmbedFooterTemplate.cs @@ -1,63 +1,62 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Discord Template for Embed Footer +/// +public class EmbedFooterTemplate { /// - /// Discord Template for Embed Footer + /// Show Embed Footer /// - public class EmbedFooterTemplate - { - /// - /// Show Embed Footer - /// - [JsonProperty("Show Footer")] - public bool Enabled { get; set; } + [JsonProperty("Show Footer")] + public bool Enabled { get; set; } - /// - /// Embed Footer Text - /// - [JsonProperty("Footer Text")] - public string Text { get; set; } = string.Empty; + /// + /// Embed Footer Text + /// + [JsonProperty("Footer Text")] + public string Text { get; set; } = string.Empty; - /// - /// Embed Footer Icon - /// - [JsonProperty("Footer Icon URL")] - public string IconUrl { get; set; } = string.Empty; + /// + /// Embed Footer Icon + /// + [JsonProperty("Footer Icon URL")] + public string IconUrl { get; set; } = string.Empty; - /// - /// Constructor - /// - [JsonConstructor] - public EmbedFooterTemplate() {} + /// + /// Constructor + /// + [JsonConstructor] + public EmbedFooterTemplate() {} - /// - /// Constructor - /// - /// - /// - /// - public EmbedFooterTemplate(string text = "", string iconUrl = "", bool enabled = false) - { - Text = text; - IconUrl = iconUrl; - Enabled = enabled; - } + /// + /// Constructor + /// + /// + /// + /// + public EmbedFooterTemplate(string text = "", string iconUrl = "", bool enabled = false) + { + Text = text; + IconUrl = iconUrl; + Enabled = enabled; + } - /// - /// Converts the template to a - /// - /// Data to use - /// - public EmbedFooter ToFooter(PlaceholderData data) - { - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - EmbedFooter footer = new EmbedFooter( - placeholders.ProcessPlaceholders(Text, data), - placeholders.ProcessPlaceholders(IconUrl, data)); - data?.AutoDispose(); - return footer; - } + /// + /// Converts the template to a + /// + /// Data to use + /// + public EmbedFooter ToFooter(PlaceholderData data) + { + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + EmbedFooter footer = new( + placeholders.ProcessPlaceholders(Text, data), + placeholders.ProcessPlaceholders(IconUrl, data)); + data?.AutoDispose(); + return footer; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Emojis/EmojiTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Emojis/EmojiTemplate.cs index 26cef4204..bdd4a45a6 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Emojis/EmojiTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Emojis/EmojiTemplate.cs @@ -2,77 +2,76 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Discord Template for Emoji +/// +public class EmojiTemplate { /// - /// Discord Template for Emoji + /// Emoji Name or ID /// - public class EmojiTemplate - { - /// - /// Emoji Name or ID - /// - [JsonProperty("Emoji Name Or ID")] - public string Emoji { get; set; } = string.Empty; + [JsonProperty("Emoji Name Or ID")] + public string Emoji { get; set; } = string.Empty; - /// - /// If the emoji is Animated - /// - [JsonProperty("For Custom Emojis Is The Emoji Animated")] - public bool Animated { get; set; } + /// + /// If the emoji is Animated + /// + [JsonProperty("For Custom Emojis Is The Emoji Animated")] + public bool Animated { get; set; } - /// - /// Default constructor - /// - [JsonConstructor] - public EmojiTemplate() { } + /// + /// Default constructor + /// + [JsonConstructor] + public EmojiTemplate() { } - /// - /// Unicode emoji constructor - /// - /// Unicode Emoji - public EmojiTemplate(string emoji) - { - Emoji = emoji; - } + /// + /// Unicode emoji constructor + /// + /// Unicode Emoji + public EmojiTemplate(string emoji) + { + Emoji = emoji; + } - /// - /// Custom Emoji Constructor - /// - /// ID of the emoji - /// Is the emoji animated? - public EmojiTemplate(Snowflake emojiId, bool animated = false) - { - Emoji = emojiId.ToString(); - Animated = animated; - } + /// + /// Custom Emoji Constructor + /// + /// ID of the emoji + /// Is the emoji animated? + public EmojiTemplate(Snowflake emojiId, bool animated = false) + { + Emoji = emojiId.ToString(); + Animated = animated; + } - /// - /// Converts the to a - /// - /// - public DiscordEmoji ToEmoji() + /// + /// Converts the to a + /// + /// + public DiscordEmoji ToEmoji() + { + if (string.IsNullOrEmpty(Emoji)) { - if (string.IsNullOrEmpty(Emoji)) - { - return null; - } - - if (Snowflake.TryParse(Emoji, out Snowflake id)) - { - return new DiscordEmoji - { - EmojiId = id, - Animated = Animated - }; - } + return null; + } - InvalidEmojiException.ThrowIfInvalidEmojiString(Emoji); - + if (Snowflake.TryParse(Emoji, out Snowflake id)) + { return new DiscordEmoji { - Name = Emoji + EmojiId = id, + Animated = Animated }; } + + InvalidEmojiException.ThrowIfInvalidEmojiString(Emoji); + + return new DiscordEmoji + { + Name = Emoji + }; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Messages/DiscordMessageTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Messages/DiscordMessageTemplate.cs index 7e6cc2374..b51d7a40e 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Messages/DiscordMessageTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Messages/DiscordMessageTemplate.cs @@ -5,156 +5,152 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Discord Message Template for sending localized Discord Messages +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordMessageTemplate { /// - /// Discord Message Template for sending localized Discord Messages + /// String contents of the message + /// + [JsonProperty("Message Content")] + public string Content { get; set; } = string.Empty; + + /// + /// Embeds for the message + /// + [JsonProperty("Message Embeds")] + public List Embeds { get; set; } = []; + + /// + /// Buttons for the message + /// + [JsonConverter(typeof(TemplateComponentsConverter))] + [JsonProperty("Message Components")] + // ReSharper disable once MemberCanBePrivate.Global + public List Components { get; set; } = []; + + /// + /// Constructor + /// + [JsonConstructor] + public DiscordMessageTemplate() {} + + /// + /// Constructor + /// + /// + public DiscordMessageTemplate(string content) + { + Content = content ?? string.Empty; + } + + /// + /// Converts the to a {T} message + /// {T} supports all message types /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordMessageTemplate + /// Placeholder Data for the template + /// {T} message to use when creating the message; if null a new {T} will be created + /// converted to type {T} message + public T ToMessage(PlaceholderData data = null, T message = null) where T : class, IDiscordMessageTemplate, new() { - /// - /// String contents of the message - /// - [JsonProperty("Message Content")] - public string Content { get; set; } = string.Empty; - - /// - /// Embeds for the message - /// - [JsonProperty("Message Embeds")] - public List Embeds { get; set; } = new List(); - - /// - /// Buttons for the message - /// - [JsonConverter(typeof(TemplateComponentsConverter))] - [JsonProperty("Message Components")] - // ReSharper disable once MemberCanBePrivate.Global - public List Components { get; set; } = new List(); - - /// - /// Constructor - /// - [JsonConstructor] - public DiscordMessageTemplate() {} - - /// - /// Constructor - /// - /// - public DiscordMessageTemplate(string content) + message ??= new T(); + + data?.IncrementDepth(); + + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + + if (!string.IsNullOrEmpty(Content)) { - Content = content ?? string.Empty; + message.Content = placeholders.ProcessPlaceholders(Content, data); } - /// - /// Converts the to a {T} message - /// {T} supports all message types - /// - /// Placeholder Data for the template - /// {T} message to use when creating the message; if null a new {T} will be created - /// converted to type {T} message - public T ToMessage(PlaceholderData data = null, T message = null) where T : class, IDiscordMessageTemplate, new() + if (Embeds != null && Embeds.Count != 0) { - if (message == null) - { - message = new T(); - } - - data?.IncrementDepth(); + message.Embeds = CreateEmbeds(data); + } - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + if (Components != null && Components.Count != 0) + { + message.Components = CreateComponents(data); + } - if (!string.IsNullOrEmpty(Content)) - { - message.Content = placeholders.ProcessPlaceholders(Content, data); - } + data?.DecrementDepth(); + data?.AutoDispose(); + + return message; + } - if (Embeds != null && Embeds.Count != 0) - { - message.Embeds = CreateEmbeds(data); - } + private List CreateEmbeds(PlaceholderData data) + { + List embeds = []; - if (Components != null && Components.Count != 0) + for (int index = 0; index < Embeds.Count; index++) + { + DiscordEmbedTemplate template = Embeds[index]; + if (template.Enabled) { - message.Components = CreateComponents(data); + embeds.Add(template.ToEntity(data)); } - - data?.DecrementDepth(); - data?.AutoDispose(); - - return message; } - private List CreateEmbeds(PlaceholderData data) - { - List embeds = new List(); + return embeds; + } - for (int index = 0; index < Embeds.Count; index++) + private List CreateComponents(PlaceholderData data) + { + List rows = new(); + ActionRowComponent active = AddActionRow(rows, -1, Components.Count); + for (int index = 0; index < Components.Count; index++) + { + BaseComponentTemplate component = Components[index]; + if (!component.Visible || active == null) { - DiscordEmbedTemplate template = Embeds[index]; - if (template.Enabled) - { - embeds.Add(template.ToEntity(data)); - } + continue; } - return embeds; - } - - private List CreateComponents(PlaceholderData data) - { - List rows = new List(); - ActionRowComponent active = AddActionRow(rows, -1, Components.Count); - for (int index = 0; index < Components.Count; index++) + if (component is ButtonTemplate template) { - BaseComponentTemplate component = Components[index]; - if (!component.Visible || active == null) + BaseComponent button = template.ToComponent(data); + if (button != null) { - continue; + active.Components.Add(button); } - - if (component is ButtonTemplate template) - { - BaseComponent button = template.ToComponent(data); - if (button != null) - { - active.Components.Add(button); - } - if (!template.Inline || active.Components.Count == 5) - { - InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(rows.Count); - active = AddActionRow(rows, index, Components.Count); - } - } - else if (component is SelectMenuTemplate selectMenu) + if (!template.Inline || active.Components.Count == 5) { - active.Components.Add(selectMenu.ToComponent(data)); InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(rows.Count); active = AddActionRow(rows, index, Components.Count); } } - - if (active != null && active.Components.Count == 0) + else if (component is SelectMenuTemplate selectMenu) { - rows.Remove(active); + active.Components.Add(selectMenu.ToComponent(data)); + InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(rows.Count); + active = AddActionRow(rows, index, Components.Count); } - - return rows; } - private ActionRowComponent AddActionRow(List row, int index, int count) + if (active != null && active.Components.Count == 0) { - if (index + 1 >= count) - { - return null; - } + rows.Remove(active); + } + + return rows; + } - ActionRowComponent comp = new ActionRowComponent(); - row.Add(comp); - return comp; + private ActionRowComponent AddActionRow(List row, int index, int count) + { + if (index + 1 >= count) + { + return null; } + + ActionRowComponent comp = new(); + row.Add(comp); + return comp; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Messages/DiscordMessageTemplates.cs b/Oxide.Ext.Discord/Libraries/Templates/Messages/DiscordMessageTemplates.cs index 34983263a..bf33210c8 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Messages/DiscordMessageTemplates.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Messages/DiscordMessageTemplates.cs @@ -1,16 +1,15 @@ using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Modal Templates Library +/// +public class DiscordMessageTemplates : BaseMessageTemplateLibrary { /// - /// Modal Templates Library + /// Constructor /// - public class DiscordMessageTemplates : BaseMessageTemplateLibrary - { - /// - /// Constructor - /// - /// - internal DiscordMessageTemplates(ILogger logger) : base(TemplateType.Message, logger) { } - } + /// + internal DiscordMessageTemplates(ILogger logger) : base(TemplateType.Message, logger) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Modals/DiscordModalTemplate.cs b/Oxide.Ext.Discord/Libraries/Templates/Modals/DiscordModalTemplate.cs index f8a226886..b050b48e0 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Modals/DiscordModalTemplate.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Modals/DiscordModalTemplate.cs @@ -4,88 +4,84 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Template used for Modal Message Component +/// +[JsonObject(MemberSerialization = MemberSerialization.OptIn)] +public class DiscordModalTemplate { /// - /// Template used for Modal Message Component + /// Title of the modal /// - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public class DiscordModalTemplate - { - /// - /// Title of the modal - /// - [JsonProperty("Modal Title")] - public string Title { get; set; } + [JsonProperty("Modal Title")] + public string Title { get; set; } - /// - /// Title of the modal - /// - [JsonProperty("Modal ID")] - public string CustomId { get; set; } + /// + /// Title of the modal + /// + [JsonProperty("Modal ID")] + public string CustomId { get; set; } - /// - /// Components of the Modal - /// - [JsonConverter(typeof(TemplateComponentsConverter))] - [JsonProperty("Modal Components")] - public List Components { get; set; } = new List(); + /// + /// Components of the Modal + /// + [JsonConverter(typeof(TemplateComponentsConverter))] + [JsonProperty("Modal Components")] + public List Components { get; set; } = []; - /// - /// Constructor - /// - [JsonConstructor] - public DiscordModalTemplate() {} + /// + /// Constructor + /// + [JsonConstructor] + public DiscordModalTemplate() {} - /// - /// Constructor - /// - /// - /// - public DiscordModalTemplate(string title, string customId) - { - Title = title; - CustomId = customId; - } + /// + /// Constructor + /// + /// + /// + public DiscordModalTemplate(string title, string customId) + { + Title = title; + CustomId = customId; + } - /// - /// Converts the template to a - /// - /// - /// - /// - public InteractionModalMessage ToModal(PlaceholderData data = null, InteractionModalMessage modal = null) - { - if (modal == null) - { - modal = new InteractionModalMessage(); - } + /// + /// Converts the template to a + /// + /// + /// + /// + public InteractionModalMessage ToModal(PlaceholderData data = null, InteractionModalMessage modal = null) + { + modal ??= new InteractionModalMessage(); - data?.IncrementDepth(); + data?.IncrementDepth(); - DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; + DiscordPlaceholders placeholders = DiscordPlaceholders.Instance; - modal.Title = placeholders.ProcessPlaceholders(Title, data); - modal.CustomId = placeholders.ProcessPlaceholders(CustomId, data); - modal.Components = new List(); + modal.Title = placeholders.ProcessPlaceholders(Title, data); + modal.CustomId = placeholders.ProcessPlaceholders(CustomId, data); + modal.Components = []; - for (int index = 0; index < Components.Count; index++) + for (int index = 0; index < Components.Count; index++) + { + BaseComponentTemplate component = Components[index]; + if (component is InputTextTemplate input && input.Visible) { - BaseComponentTemplate component = Components[index]; - if (component is InputTextTemplate input && input.Visible) + InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(modal.Components.Count); + modal.Components.Add(new ActionRowComponent { - InvalidMessageComponentException.ThrowIfInvalidMaxActionRows(modal.Components.Count); - modal.Components.Add(new ActionRowComponent - { - Components = { input.ToComponent(data) } - }); - } + Components = { input.ToComponent(data) } + }); } + } - data?.DecrementDepth(); - data?.AutoDispose(); + data?.DecrementDepth(); + data?.AutoDispose(); - return modal; - } + return modal; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/Modals/DiscordModalTemplates.cs b/Oxide.Ext.Discord/Libraries/Templates/Modals/DiscordModalTemplates.cs index 80610ef4c..e9ccf2674 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/Modals/DiscordModalTemplates.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/Modals/DiscordModalTemplates.cs @@ -1,16 +1,15 @@ using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Modal Templates Library +/// +public class DiscordModalTemplates : BaseMessageTemplateLibrary { /// - /// Modal Templates Library + /// Constructor /// - public class DiscordModalTemplates : BaseMessageTemplateLibrary - { - /// - /// Constructor - /// - /// - internal DiscordModalTemplates(ILogger logger) : base(TemplateType.Modal, logger) { } - } + /// + internal DiscordModalTemplates(ILogger logger) : base(TemplateType.Modal, logger) { } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/TemplateId.cs b/Oxide.Ext.Discord/Libraries/Templates/TemplateId.cs index 12bf2c1e9..5a3fcf7d5 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/TemplateId.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/TemplateId.cs @@ -4,57 +4,41 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +internal readonly record struct TemplateId { - internal struct TemplateId : IEquatable - { - internal readonly PluginId PluginId; - public readonly TemplateKey TemplateName; - public readonly ServerLocale Language; + internal readonly PluginId PluginId; + public readonly TemplateKey TemplateName; + public readonly ServerLocale Language; - public bool IsGlobal => !Language.IsValid; + public bool IsGlobal => !Language.IsValid; - private TemplateId(Plugin plugin, TemplateKey templateName, ServerLocale language) : this(plugin?.Id() ?? throw new ArgumentNullException(nameof(plugin)), templateName, language) { } - - private TemplateId(PluginId pluginName, TemplateKey templateName, ServerLocale language) - { - PluginId = pluginName; - TemplateName = templateName; - Language = language; - } - - public static TemplateId CreateGlobal(Plugin plugin, TemplateKey templateName) => new TemplateId(plugin, templateName, default(ServerLocale)); - public static TemplateId CreateLocalized(Plugin plugin, TemplateKey templateName, ServerLocale language) => new TemplateId(plugin, templateName, language); - public static TemplateId CreateInteraction(Plugin plugin, TemplateKey templateName, DiscordInteraction interaction) => new TemplateId(plugin, templateName, interaction.Locale.GetServerLocale()); - public static TemplateId CreatePlayer(Plugin plugin, TemplateKey templateName, string playerId) => new TemplateId(plugin, templateName, DiscordLocales.Instance.GetPlayerLanguage(playerId)); - - public string GetPluginName() - { - return PluginExt.GetFullName(PluginId); - } - - public TemplateId WithLanguage(ServerLocale language) - { - return new TemplateId(PluginId, TemplateName, language); - } - - public string GetLanguageName() => IsGlobal ? "Global" : Language.Id; - - public bool Equals(TemplateId other) => PluginId == other.PluginId && TemplateName == other.TemplateName && Language == other.Language; - - public override bool Equals(object obj) => obj is TemplateId other && Equals(other); - - public override string ToString() => $"Plugin: {PluginId} Template: {TemplateName} Language: {GetLanguageName()}"; - - public override int GetHashCode() - { - unchecked - { - int hashCode = PluginId.GetHashCode(); - hashCode = (hashCode * 397) ^ (TemplateName.IsValid ? TemplateName.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (Language.IsValid ? Language.GetHashCode() : 0); - return hashCode; - } - } + private TemplateId(Plugin plugin, TemplateKey templateName, ServerLocale language) : this(plugin?.Id() ?? throw new ArgumentNullException(nameof(plugin)), templateName, language) { } + + private TemplateId(PluginId pluginName, TemplateKey templateName, ServerLocale language) + { + PluginId = pluginName; + TemplateName = templateName; + Language = language; + } + + public static TemplateId CreateGlobal(Plugin plugin, TemplateKey templateName) => new(plugin, templateName, default); + public static TemplateId CreateLocalized(Plugin plugin, TemplateKey templateName, ServerLocale language) => new(plugin, templateName, language); + public static TemplateId CreateInteraction(Plugin plugin, TemplateKey templateName, DiscordInteraction interaction) => new(plugin, templateName, interaction.Locale.GetServerLocale()); + public static TemplateId CreatePlayer(Plugin plugin, TemplateKey templateName, string playerId) => new(plugin, templateName, DiscordLocales.Instance.GetPlayerLanguage(playerId)); + + public string GetPluginName() + { + return PluginExt.GetFullName(PluginId); } + + public TemplateId WithLanguage(ServerLocale language) + { + return new TemplateId(PluginId, TemplateName, language); + } + + public string GetLanguageName() => IsGlobal ? "Global" : Language.Id; + + public override string ToString() => $"Plugin: {PluginId} Template: {TemplateName} Language: {GetLanguageName()}"; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/TemplateKey.cs b/Oxide.Ext.Discord/Libraries/Templates/TemplateKey.cs index 1cddc893c..379d16f43 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/TemplateKey.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/TemplateKey.cs @@ -1,71 +1,44 @@ -using System; -using Newtonsoft.Json; +using Newtonsoft.Json; using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents a Template Key. This is the key for template lookup +/// +[JsonConverter(typeof(TemplateKeyConverter))] +public readonly record struct TemplateKey: IDiscordKey { /// - /// Represents a Template Key. This is the key for template lookup + /// Placeholder Key /// - [JsonConverter(typeof(TemplateKeyConverter))] - public struct TemplateKey: IEquatable, IDiscordKey - { - /// - /// Placeholder Key - /// - public readonly string Name; - - /// - /// If Is a Valid Key - /// - public bool IsValid => !string.IsNullOrEmpty(Name); - - /// - /// Constructor - /// - /// Placeholder Value - public TemplateKey(string name) - { - Name = name; - } - - /// - public bool Equals(TemplateKey other) => Name == other.Name; + public readonly string Name; - /// - public override bool Equals(object obj) => obj is TemplateKey other && Equals(other); - - /// - public override int GetHashCode() => Name != null ? Name.GetHashCode() : 0; - - /// - /// Template Key == operator - /// - /// - /// - /// - public static bool operator ==(TemplateKey left, TemplateKey right) => left.Name == right.Name; + /// + /// If Is a Valid Key + /// + public bool IsValid => !string.IsNullOrEmpty(Name); - /// - /// Template Key != operator - /// - /// - /// - /// - public static bool operator !=(TemplateKey left, TemplateKey right) => !(left == right); + /// + /// Constructor + /// + /// Placeholder Value + public TemplateKey(string name) + { + Name = name; + } - /// - /// Returns the template name - /// - /// - public override string ToString() => Name; + /// + /// Returns the template name + /// + /// + public override string ToString() => Name; - /// - /// Implicitly converts to by calling the method. - /// - /// - /// - public static implicit operator string(TemplateKey key) => key.ToString(); - } + /// + /// Implicitly converts to by calling the method. + /// + /// + /// + public static implicit operator string(TemplateKey key) => key.ToString(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/TemplateType.cs b/Oxide.Ext.Discord/Libraries/Templates/TemplateType.cs index 54b5a4e71..74535529d 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/TemplateType.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/TemplateType.cs @@ -1,53 +1,52 @@ -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Represents available template type +/// +public enum TemplateType : byte { /// - /// Represents available template type + /// Message Template Type /// - public enum TemplateType : byte - { - /// - /// Message Template Type - /// - Message, + Message, - /// - /// Embed Template Type - /// - Embed, + /// + /// Embed Template Type + /// + Embed, - /// - /// Embed Field Type - /// - EmbedField, + /// + /// Embed Field Type + /// + EmbedField, - /// - /// Modal Template Type - /// - Modal, + /// + /// Modal Template Type + /// + Modal, - /// - /// Command Template Type - /// - Command, + /// + /// Command Template Type + /// + Command, - /// - /// Auto Complete Choice Template Type - /// - AutoCompleteChoice, + /// + /// Auto Complete Choice Template Type + /// + AutoCompleteChoice, - /// - /// Button Component Template Type - /// - ButtonComponent, + /// + /// Button Component Template Type + /// + ButtonComponent, - /// - /// Input Text Component Template Type - /// - InputTextComponent, + /// + /// Input Text Component Template Type + /// + InputTextComponent, - /// - /// Select Menu Template Type - /// - SelectMenuComponent, - } + /// + /// Select Menu Template Type + /// + SelectMenuComponent, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Libraries/Templates/TemplateVersion.cs b/Oxide.Ext.Discord/Libraries/Templates/TemplateVersion.cs index af51e362c..4930e530b 100644 --- a/Oxide.Ext.Discord/Libraries/Templates/TemplateVersion.cs +++ b/Oxide.Ext.Discord/Libraries/Templates/TemplateVersion.cs @@ -2,130 +2,89 @@ using Newtonsoft.Json; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.Libraries +namespace Oxide.Ext.Discord.Libraries; + +/// +/// Version of a specific template +/// +[JsonConverter(typeof(TemplateVersionConverter))] +public readonly record struct TemplateVersion : IComparable { /// - /// Version of a specific template + /// Major Version /// - [JsonConverter(typeof(TemplateVersionConverter))] - public struct TemplateVersion : IEquatable, IComparable - { - /// - /// Major Version - /// - public readonly ushort Major; + public readonly ushort Major; - /// - /// Minor Version - /// - public readonly ushort Minor; - - /// - /// Revision Version - /// - public readonly ushort Revision; - - /// - /// Constructor - /// - /// Major Version - /// Minor Version - /// Revision Version - public TemplateVersion(ushort major, ushort minor, ushort revision) - { - Major = major; - Minor = minor; - Revision = revision; - } - - /// - public bool Equals(TemplateVersion other) - { - return Major == other.Major && Minor == other.Minor && Revision == other.Revision; - } - - /// - public override bool Equals(object obj) - { - return obj is TemplateVersion other && Equals(other); - } + /// + /// Minor Version + /// + public readonly ushort Minor; - /// - public override int GetHashCode() - { - unchecked - { - int hashCode = Major.GetHashCode(); - hashCode = (hashCode * 397) ^ Minor.GetHashCode(); - hashCode = (hashCode * 397) ^ Revision.GetHashCode(); - return hashCode; - } - } - - /// - public int CompareTo(TemplateVersion other) - { - int majorComparison = Major.CompareTo(other.Major); - if (majorComparison != 0) - return majorComparison; - int minorComparison = Minor.CompareTo(other.Minor); - if (minorComparison != 0) - return minorComparison; - return Revision.CompareTo(other.Revision); - } + /// + /// Revision Version + /// + public readonly ushort Revision; - /// - /// Returns if the template versions are equal - /// - /// - /// - /// - public static bool operator == (TemplateVersion left, TemplateVersion right) => left.Equals(right); - - /// - /// Returns if the template versions are not equal - /// - /// - /// - /// - public static bool operator != (TemplateVersion left, TemplateVersion right) => !(left == right); + /// + /// Constructor + /// + /// Major Version + /// Minor Version + /// Revision Version + public TemplateVersion(ushort major, ushort minor, ushort revision) + { + Major = major; + Minor = minor; + Revision = revision; + } + + /// + public int CompareTo(TemplateVersion other) + { + int majorComparison = Major.CompareTo(other.Major); + if (majorComparison != 0) + return majorComparison; + int minorComparison = Minor.CompareTo(other.Minor); + if (minorComparison != 0) + return minorComparison; + return Revision.CompareTo(other.Revision); + } - /// - /// Returns if the left template version is less than the right - /// - /// - /// - /// - public static bool operator <(TemplateVersion left, TemplateVersion right) => left.CompareTo(right) < 0; + /// + /// Returns if the left template version is less than the right + /// + /// + /// + /// + public static bool operator <(TemplateVersion left, TemplateVersion right) => left.CompareTo(right) < 0; - /// - /// Returns if the left template version is less than or equal the right - /// - /// - /// - /// - public static bool operator <=(TemplateVersion left, TemplateVersion right) => left.CompareTo(right) <= 0; + /// + /// Returns if the left template version is less than or equal the right + /// + /// + /// + /// + public static bool operator <=(TemplateVersion left, TemplateVersion right) => left.CompareTo(right) <= 0; - /// - /// Returns if the right template version is greater than the left - /// - /// - /// - /// - public static bool operator >(TemplateVersion left, TemplateVersion right) => left.CompareTo(right) > 0; + /// + /// Returns if the right template version is greater than the left + /// + /// + /// + /// + public static bool operator >(TemplateVersion left, TemplateVersion right) => left.CompareTo(right) > 0; - /// - /// Returns if the right template version is greater or equal than the left - /// - /// - /// - /// - public static bool operator >=(TemplateVersion left, TemplateVersion right) => left.CompareTo(right) >= 0; + /// + /// Returns if the right template version is greater or equal than the left + /// + /// + /// + /// + public static bool operator >=(TemplateVersion left, TemplateVersion right) => left.CompareTo(right) >= 0; - /// - public override string ToString() - { - return $"{Major}.{Minor}.{Revision}"; - } + /// + public override string ToString() + { + return $"{Major}.{Minor}.{Revision}"; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Logging/DebugLogger.cs b/Oxide.Ext.Discord/Logging/DebugLogger.cs index 4679331c4..a36da446d 100644 --- a/Oxide.Ext.Discord/Logging/DebugLogger.cs +++ b/Oxide.Ext.Discord/Logging/DebugLogger.cs @@ -11,515 +11,514 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Logging +namespace Oxide.Ext.Discord.Logging; + +/// +/// Debug Logger used for logging debug information +/// +public class DebugLogger { - /// - /// Debug Logger used for logging debug information - /// - public class DebugLogger - { - private readonly StringBuilder _logger = DiscordPool.Internal.GetStringBuilder(); - private const char IndentCharacter = '\t'; + private readonly StringBuilder _logger = DiscordPool.Internal.GetStringBuilder(); + private const char IndentCharacter = '\t'; - private int _indent; + private int _indent; - /// - /// Increments the Indent - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void IncrementIndent() => _indent++; + /// + /// Increments the Indent + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void IncrementIndent() => _indent++; - /// - /// Decrements the Indent - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void DecrementIndent() => _indent = Math.Max(_indent - 1, 0); + /// + /// Decrements the Indent + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void DecrementIndent() => _indent = Math.Max(_indent - 1, 0); - /// - /// Appends the current indent into the logger - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AppendIndent() => _logger.Append(IndentCharacter, _indent); - - /// - /// Appends the field name into the logger - /// - /// Name of the field - public void AppendFieldPrefix(string name) - { - AppendIndent(); - _logger.Append(name); - _logger.Append(": "); - } + /// + /// Appends the current indent into the logger + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AppendIndent() => _logger.Append(IndentCharacter, _indent); - /// - /// Appends a field into the logger - /// - /// Name of the field - /// Value of the field - public void AppendField(string name, string value) => AppendField(name, value.AsSpan()); + /// + /// Appends the field name into the logger + /// + /// Name of the field + public void AppendFieldPrefix(string name) + { + AppendIndent(); + _logger.Append(name); + _logger.Append(": "); + } + + /// + /// Appends a field into the logger + /// + /// Name of the field + /// Value of the field + public void AppendField(string name, string value) => AppendField(name, value.AsSpan()); - /// - /// Appends a field into the logger - /// - /// Name of the field - /// Value of the field - public void AppendField(string name, ReadOnlySpan value) + /// + /// Appends a field into the logger + /// + /// Name of the field + /// Value of the field + public void AppendField(string name, ReadOnlySpan value) + { + AppendFieldPrefix(name); + _logger.Append(value); + _logger.AppendLine(); + } + + /// + /// Appends a field with the given name and int value + /// + /// Name of the field + /// Value of the field + public void AppendField(string name, int value) + { + char[] array = ArrayPool.Shared.Rent(20); + Span span = array.AsSpan(); + if (value.TryFormat(span, out int written)) { - AppendFieldPrefix(name); - _logger.Append(value); - _logger.AppendLine(); + AppendField(name, span.Slice(0, written)); } - - /// - /// Appends a field with the given name and int value - /// - /// Name of the field - /// Value of the field - public void AppendField(string name, int value) + else { - char[] array = ArrayPool.Shared.Rent(20); - Span span = array.AsSpan(); - if (value.TryFormat(span, out int written)) - { - AppendField(name, span.Slice(0, written)); - } - else - { - AppendField(name, value.ToString()); - } - ArrayPool.Shared.Return(array); + AppendField(name, value.ToString()); } + ArrayPool.Shared.Return(array); + } - /// - /// Appends a field with the given name and double value - /// - /// Name of the field - /// Value of the field - public void AppendField(string name, double value) + /// + /// Appends a field with the given name and double value + /// + /// Name of the field + /// Value of the field + public void AppendField(string name, double value) + { + char[] array = ArrayPool.Shared.Rent(64); + Span span = array.AsSpan(); + if (value.TryFormat(span, out int written)) { - char[] array = ArrayPool.Shared.Rent(64); - Span span = array.AsSpan(); - if (value.TryFormat(span, out int written)) - { - AppendField(name, span.Slice(0, written)); - } - else - { - AppendField(name, value.ToString(CultureInfo.InvariantCulture)); - } - ArrayPool.Shared.Return(array); + AppendField(name, span.Slice(0, written)); } - - /// - /// Appends a field with the given name and float value - /// - /// Name of the field - /// Value of the field - public void AppendField(string name, float value) + else { - char[] array = ArrayPool.Shared.Rent(64); - Span span = array.AsSpan(); - if (value.TryFormat(span, out int written)) - { - AppendField(name, span.Slice(0, written)); - } - else - { - AppendField(name, value.ToString(CultureInfo.InvariantCulture)); - } - ArrayPool.Shared.Return(array); + AppendField(name, value.ToString(CultureInfo.InvariantCulture)); } + ArrayPool.Shared.Return(array); + } - /// - /// Appends a field with the given name and ulong value - /// - /// Name of the field - /// Value of the field - public void AppendField(string name, ulong value) + /// + /// Appends a field with the given name and float value + /// + /// Name of the field + /// Value of the field + public void AppendField(string name, float value) + { + char[] array = ArrayPool.Shared.Rent(64); + Span span = array.AsSpan(); + if (value.TryFormat(span, out int written)) { - char[] array = ArrayPool.Shared.Rent(32); - Span span = array.AsSpan(); - if (value.TryFormat(span, out int written)) - { - AppendField(name, span.Slice(0, written)); - } - else - { - AppendField(name, value.ToString()); - } - ArrayPool.Shared.Return(array); + AppendField(name, span.Slice(0, written)); } - - /// - /// Appends a field with the given name and long value - /// - /// Name of the field - /// Value of the field - public void AppendField(string name, long value) + else { - char[] array = ArrayPool.Shared.Rent(32); - Span span = array.AsSpan(); - if (value.TryFormat(span, out int written)) - { - AppendField(name, span.Slice(0, written)); - } - else - { - AppendField(name, value.ToString()); - } - ArrayPool.Shared.Return(array); + AppendField(name, value.ToString(CultureInfo.InvariantCulture)); } + ArrayPool.Shared.Return(array); + } - /// - /// Appends a field with the given name and bool value - /// - /// Name of the field - /// Value of the field - public void AppendField(string name, bool value) + /// + /// Appends a field with the given name and ulong value + /// + /// Name of the field + /// Value of the field + public void AppendField(string name, ulong value) + { + char[] array = ArrayPool.Shared.Rent(32); + Span span = array.AsSpan(); + if (value.TryFormat(span, out int written)) { - AppendFieldPrefix(name); - _logger.AppendLine(value ? "Yes" : "No"); + AppendField(name, span.Slice(0, written)); } - - /// - /// Appends a field with the given name and Snowflake value - /// - /// Name of the field - /// Value of the field - public void AppendField(string name, Snowflake value) + else { - char[] array = ArrayPool.Shared.Rent(64); - Span span = array.AsSpan(); - if (value.TryFormat(span, out int written)) - { - AppendField(name, span.Slice(0, written)); - } - else - { - AppendField(name, value.ToString()); - } - ArrayPool.Shared.Return(array); + AppendField(name, value.ToString()); } + ArrayPool.Shared.Return(array); + } - /// - /// Appends a field with the given name and Snowflake? value - /// - /// Name of the field - /// Value of the field - public void AppendField(string name, Snowflake? value) + /// + /// Appends a field with the given name and long value + /// + /// Name of the field + /// Value of the field + public void AppendField(string name, long value) + { + char[] array = ArrayPool.Shared.Rent(32); + Span span = array.AsSpan(); + if (value.TryFormat(span, out int written)) { - if (value.HasValue) - { - AppendField(name, value.Value); - return; - } - - AppendField(name, "Invalid ID"); + AppendField(name, span.Slice(0, written)); } - - /// - /// Appends a field with the given name and enum value - /// - /// Name of the field - /// Value of the field - public void AppendFieldEnum(string name, T value) where T : struct, IComparable, IFormattable, IConvertible => AppendField(name, EnumCache.Instance.ToString(value)); - - /// - /// Appends a field with the given name and int amount over int total value - /// - /// Name of the field - /// Amount / Top value - /// Total / Bottom Value - public void AppendFieldOutOf(string name, int amount, int total) + else { - AppendFieldPrefix(name); - _logger.Append(StringCache.Instance.ToString(amount)); - _logger.Append('/'); - _logger.AppendLine(StringCache.Instance.ToString(total)); + AppendField(name, value.ToString()); } + ArrayPool.Shared.Return(array); + } - /// - /// Appends a field with the given name and method info - /// - /// Name of the field - /// Method info to append - public void AppendMethod(string name, MethodInfo info) + /// + /// Appends a field with the given name and bool value + /// + /// Name of the field + /// Value of the field + public void AppendField(string name, bool value) + { + AppendFieldPrefix(name); + _logger.AppendLine(value ? "Yes" : "No"); + } + + /// + /// Appends a field with the given name and Snowflake value + /// + /// Name of the field + /// Value of the field + public void AppendField(string name, Snowflake value) + { + char[] array = ArrayPool.Shared.Rent(64); + Span span = array.AsSpan(); + if (value.TryFormat(span, out int written)) { - AppendFieldPrefix(name); - _logger.Append(info.DeclaringType?.Name ?? "Unknown Type"); - _logger.Append('.'); - _logger.AppendLine(info.Name); + AppendField(name, span.Slice(0, written)); } - - /// - /// Appends a field with the given name and values seperated by a space - /// - /// Name of the field - /// First value - /// Second value - public void AppendField(string name, string value1, string value2) + else { - AppendFieldPrefix(name); - _logger.Append(value1); - _logger.Append(' '); - _logger.AppendLine(value2); + AppendField(name, value.ToString()); } + ArrayPool.Shared.Return(array); + } - /// - /// Appends a field with the given name and TimeSpan value - /// - /// Name of the field - /// TimeSpan value - public void AppendField(string name, TimeSpan time) + /// + /// Appends a field with the given name and Snowflake? value + /// + /// Name of the field + /// Value of the field + public void AppendField(string name, Snowflake? value) + { + if (value.HasValue) { - AppendFieldPrefix(name); - bool hasTime = AppendTimeSlice(time.TotalDays, time.Hours, " Days", false); - hasTime = AppendTimeSlice(time.TotalHours, time.Hours, " Hours", hasTime); - hasTime = AppendTimeSlice(time.TotalMinutes, time.Minutes, " Hours", hasTime); - hasTime = AppendTimeSlice(time.TotalSeconds, time.Seconds, " Seconds", hasTime); - if (hasTime) - { - return; - } - - hasTime = AppendTimeSlice(time.TotalMilliseconds, time.Milliseconds, " Milliseconds", false); - if (hasTime) - { - return; - } - - _logger.Append("0 Seconds"); + AppendField(name, value.Value); + return; } - - private bool AppendTimeSlice(double total, int time, string suffix, bool hasTime) - { - if (total < 1) - { - return false; - } - if (hasTime) - { - _logger.Append(' '); - } - - _logger.Append(StringCache.Instance.ToString(time)); - _logger.Append(suffix); - return true; - } + AppendField(name, "Invalid ID"); + } + + /// + /// Appends a field with the given name and enum value + /// + /// Name of the field + /// Value of the field + public void AppendFieldEnum(string name, T value) where T : struct, IComparable, IFormattable, IConvertible => AppendField(name, EnumCache.Instance.ToString(value)); + + /// + /// Appends a field with the given name and int amount over int total value + /// + /// Name of the field + /// Amount / Top value + /// Total / Bottom Value + public void AppendFieldOutOf(string name, int amount, int total) + { + AppendFieldPrefix(name); + _logger.Append(StringCache.Instance.ToString(amount)); + _logger.Append('/'); + _logger.AppendLine(StringCache.Instance.ToString(total)); + } - /// - /// Appends a field with the given name and Null value - /// - /// Name of the field - public void AppendNullField(string name) + /// + /// Appends a field with the given name and method info + /// + /// Name of the field + /// Method info to append + public void AppendMethod(string name, MethodInfo info) + { + AppendFieldPrefix(name); + _logger.Append(info.DeclaringType?.Name ?? "Unknown Type"); + _logger.Append('.'); + _logger.AppendLine(info.Name); + } + + /// + /// Appends a field with the given name and values seperated by a space + /// + /// Name of the field + /// First value + /// Second value + public void AppendField(string name, string value1, string value2) + { + AppendFieldPrefix(name); + _logger.Append(value1); + _logger.Append(' '); + _logger.AppendLine(value2); + } + + /// + /// Appends a field with the given name and TimeSpan value + /// + /// Name of the field + /// TimeSpan value + public void AppendField(string name, TimeSpan time) + { + AppendFieldPrefix(name); + bool hasTime = AppendTimeSlice(time.TotalDays, time.Hours, " Days", false); + hasTime = AppendTimeSlice(time.TotalHours, time.Hours, " Hours", hasTime); + hasTime = AppendTimeSlice(time.TotalMinutes, time.Minutes, " Hours", hasTime); + hasTime = AppendTimeSlice(time.TotalSeconds, time.Seconds, " Seconds", hasTime); + if (hasTime) { - AppendFieldPrefix(name); - _logger.AppendLine("IS NULL"); + return; } - - /// - /// Appends a line to the logger - /// - public void AppendLine() + + hasTime = AppendTimeSlice(time.TotalMilliseconds, time.Milliseconds, " Milliseconds", false); + if (hasTime) { - _logger.AppendLine(); + return; } + + _logger.Append("0 Seconds"); + } - /// - /// Appends a line to the logger with the given character repeated amount time - /// - /// Character to repeat - /// Amount of times to repeat the character - public void AppendLine(char character, int amount) + private bool AppendTimeSlice(double total, int time, string suffix, bool hasTime) + { + if (total < 1) { - AppendIndent(); - _logger.Append(character, amount); - _logger.AppendLine(); + return false; } - - /// - /// Appends a line to the logger with the given string value - /// - /// Value of the line - public void AppendLine(string value) + + if (hasTime) { - AppendIndent(); - _logger.AppendLine(value); + _logger.Append(' '); } - /// - /// Appends a channel path to the logger. - /// This path will include the guild name / Parent Channel Name (Optional) / Channel Name - /// - /// Name of the field - /// Guild for the name - /// Channel for the channel name - /// Parent for the Parent Channel Name - public void AppendChannelPath(string name, DiscordGuild guild, DiscordChannel channel, DiscordChannel parent = null) + _logger.Append(StringCache.Instance.ToString(time)); + _logger.Append(suffix); + return true; + } + + /// + /// Appends a field with the given name and Null value + /// + /// Name of the field + public void AppendNullField(string name) + { + AppendFieldPrefix(name); + _logger.AppendLine("IS NULL"); + } + + /// + /// Appends a line to the logger + /// + public void AppendLine() + { + _logger.AppendLine(); + } + + /// + /// Appends a line to the logger with the given character repeated amount time + /// + /// Character to repeat + /// Amount of times to repeat the character + public void AppendLine(char character, int amount) + { + AppendIndent(); + _logger.Append(character, amount); + _logger.AppendLine(); + } + + /// + /// Appends a line to the logger with the given string value + /// + /// Value of the line + public void AppendLine(string value) + { + AppendIndent(); + _logger.AppendLine(value); + } + + /// + /// Appends a channel path to the logger. + /// This path will include the guild name / Parent Channel Name (Optional) / Channel Name + /// + /// Name of the field + /// Guild for the name + /// Channel for the channel name + /// Parent for the Parent Channel Name + public void AppendChannelPath(string name, DiscordGuild guild, DiscordChannel channel, DiscordChannel parent = null) + { + AppendFieldPrefix(name); + _logger.Append(guild?.Name ?? "Unknown Guild"); + _logger.Append(" ("); + _logger.Append(guild?.Id.ToString()); + _logger.Append(")/"); + if (parent != null) { - AppendFieldPrefix(name); - _logger.Append(guild?.Name ?? "Unknown Guild"); + _logger.Append(parent.Name ?? "Unknown Channel"); _logger.Append(" ("); - _logger.Append(guild?.Id.ToString()); + _logger.Append(parent.Id.ToString()); _logger.Append(")/"); - if (parent != null) - { - _logger.Append(parent.Name ?? "Unknown Channel"); - _logger.Append(" ("); - _logger.Append(parent.Id.ToString()); - _logger.Append(")/"); - } - _logger.Append(channel?.Name ?? "Unknown Channel"); - _logger.Append(" ("); - _logger.Append(channel?.Id.ToString()); - _logger.AppendLine(")"); } + _logger.Append(channel?.Name ?? "Unknown Channel"); + _logger.Append(" ("); + _logger.Append(channel?.Id.ToString()); + _logger.AppendLine(")"); + } - /// - /// Appends a object to the logger with the given name - /// - /// Name of the object - /// Object to be logged - public void AppendObject(string name, IDebugLoggable obj) + /// + /// Appends a object to the logger with the given name + /// + /// Name of the object + /// Object to be logged + public void AppendObject(string name, IDebugLoggable obj) + { + if (obj == null) { - if (obj == null) - { - AppendNullField(name); - return; - } - - StartObject(name); - obj.LogDebug(this); - EndObject(); + AppendNullField(name); + return; } + + StartObject(name); + obj.LogDebug(this); + EndObject(); + } - /// - /// Appends an where T is string items to add to the logger - /// - /// Name of the list - /// String items to add - public void AppendList(string name, IEnumerable items) - { - List list = items.ToPooledList(DiscordPool.Internal); - AppendList(name, list); - DiscordPool.Internal.FreeList(list); - } + /// + /// Appends an where T is string items to add to the logger + /// + /// Name of the list + /// String items to add + public void AppendList(string name, IEnumerable items) + { + List list = items.ToPooledList(DiscordPool.Internal); + AppendList(name, list); + DiscordPool.Internal.FreeList(list); + } - /// - /// Appends an where T is string items to add to the logger - /// - /// Name of the list - /// String items to add - public void AppendList(string name, List items) + /// + /// Appends an where T is string items to add to the logger + /// + /// Name of the list + /// String items to add + public void AppendList(string name, List items) + { + if (items.Count == 0) { - if (items.Count == 0) - { - AppendField(name, "[]"); - return; - } - - StartArray(name); - for (int index = 0; index < items.Count; index++) - { - AppendLine(items[index]); - } - EndArray(); + AppendField(name, "[]"); + return; } - - /// - /// Appends an where T is items to add to the logger - /// - /// Name of the list - /// Loggable items to add - public void AppendList(string name, IEnumerable items) where T : IDebugLoggable + + StartArray(name); + for (int index = 0; index < items.Count; index++) { - List list = items.ToPooledList(DiscordPool.Internal); - AppendList(name, list); - DiscordPool.Internal.FreeList(list); + AppendLine(items[index]); } + EndArray(); + } + + /// + /// Appends an where T is items to add to the logger + /// + /// Name of the list + /// Loggable items to add + public void AppendList(string name, IEnumerable items) where T : IDebugLoggable + { + List list = items.ToPooledList(DiscordPool.Internal); + AppendList(name, list); + DiscordPool.Internal.FreeList(list); + } - /// - /// Appends an where T is items to add to the logger - /// - /// Name of the list - /// Loggable items to add - public void AppendList(string name, List items) where T : IDebugLoggable + /// + /// Appends an where T is items to add to the logger + /// + /// Name of the list + /// Loggable items to add + public void AppendList(string name, List items) where T : IDebugLoggable + { + if (items.Count == 0) { - if (items.Count == 0) - { - AppendField(name, "[]"); - return; - } - - StartArray(name); - for (int index = 0; index < items.Count; index++) - { - AppendObject(string.Empty, items[index]); - } - EndArray(); + AppendField(name, "[]"); + return; } - - /// - /// Starts an array on the logger with the given name - /// - /// Name of the array - public void StartArray(string name) + + StartArray(name); + for (int index = 0; index < items.Count; index++) { - if (!string.IsNullOrEmpty(name)) - { - AppendFieldPrefix(name); - _logger.AppendLine(); - } - AppendIndent(); - _logger.AppendLine("["); - IncrementIndent(); + AppendObject(string.Empty, items[index]); } + EndArray(); + } - /// - /// Ends an array on the logger - /// - public void EndArray() + /// + /// Starts an array on the logger with the given name + /// + /// Name of the array + public void StartArray(string name) + { + if (!string.IsNullOrEmpty(name)) { - DecrementIndent(); - AppendIndent(); - _logger.Append("]"); + AppendFieldPrefix(name); _logger.AppendLine(); } - - /// - /// Starts an object on the logger with the given name - /// - /// - public void StartObject(string name) - { - if (!string.IsNullOrEmpty(name)) - { - AppendFieldPrefix(name); - _logger.AppendLine(); - } - - AppendIndent(); - _logger.AppendLine("{"); - IncrementIndent(); - } + AppendIndent(); + _logger.AppendLine("["); + IncrementIndent(); + } - /// - /// Ends an object on the logger - /// - public void EndObject() + /// + /// Ends an array on the logger + /// + public void EndArray() + { + DecrementIndent(); + AppendIndent(); + _logger.Append("]"); + _logger.AppendLine(); + } + + /// + /// Starts an object on the logger with the given name + /// + /// + public void StartObject(string name) + { + if (!string.IsNullOrEmpty(name)) { - DecrementIndent(); - AppendIndent(); - _logger.Append("}"); + AppendFieldPrefix(name); _logger.AppendLine(); } - /// - /// Returns the logged data as a string - /// - /// - public override string ToString() => DiscordPool.Internal.ToStringAndFree(_logger); + AppendIndent(); + _logger.AppendLine("{"); + IncrementIndent(); + } + + /// + /// Ends an object on the logger + /// + public void EndObject() + { + DecrementIndent(); + AppendIndent(); + _logger.Append("}"); + _logger.AppendLine(); } + + /// + /// Returns the logged data as a string + /// + /// + public override string ToString() => DiscordPool.Internal.ToStringAndFree(_logger); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Logging/DiscordConsoleLogger.cs b/Oxide.Ext.Discord/Logging/DiscordConsoleLogger.cs index aa5db962b..9096eb540 100644 --- a/Oxide.Ext.Discord/Logging/DiscordConsoleLogger.cs +++ b/Oxide.Ext.Discord/Logging/DiscordConsoleLogger.cs @@ -5,67 +5,66 @@ using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Logging +namespace Oxide.Ext.Discord.Logging; + +/// +/// Represents a Console Logger for Discord +/// +internal class DiscordConsoleLogger : IOutputLogger { + private readonly string _pluginName; + private readonly object[] _empty = []; + + private static readonly ThreadLocal Builder = new(() => new StringBuilder()); + + public DiscordConsoleLogger(string pluginName) + { + _pluginName = $"[{pluginName}] "; + } + /// - /// Represents a Console Logger for Discord + /// Adds a message to the server console /// - internal class DiscordConsoleLogger : IOutputLogger + /// + /// + /// + /// + public void AddMessage(DiscordLogLevel level, string log, object[] args, Exception ex) { - private readonly string _pluginName; - private readonly object[] _empty = Array.Empty(); - - private static readonly ThreadLocal Builder = new ThreadLocal(() => new StringBuilder()); - - public DiscordConsoleLogger(string pluginName) + StringBuilder sb = Builder.Value; + sb.Clear(); + sb.Append(_pluginName); + sb.Append('['); + sb.Append(EnumCache.Instance.ToString(level)); + sb.Append("]: "); + if (args.Length != 0) { - _pluginName = $"[{pluginName}] "; + sb.AppendFormat(log, args); } - - /// - /// Adds a message to the server console - /// - /// - /// - /// - /// - public void AddMessage(DiscordLogLevel level, string log, object[] args, Exception ex) + else { - StringBuilder sb = Builder.Value; - sb.Clear(); - sb.Append(_pluginName); - sb.Append('['); - sb.Append(EnumCache.Instance.ToString(level)); - sb.Append("]: "); - if (args.Length != 0) - { - sb.AppendFormat(log, args); - } - else - { - sb.Append(log); - } + sb.Append(log); + } - string message = sb.ToString(); + string message = sb.ToString(); - switch (level) - { - case DiscordLogLevel.Debug: - case DiscordLogLevel.Warning: - Interface.Oxide.LogWarning(message, _empty); - break; - case DiscordLogLevel.Error: - Interface.Oxide.LogError(message, _empty); - break; - case DiscordLogLevel.Exception: - Interface.Oxide.LogException(message, ex); - break; - default: - Interface.Oxide.LogInfo(message, _empty); - break; - } + switch (level) + { + case DiscordLogLevel.Debug: + case DiscordLogLevel.Warning: + Interface.Oxide.LogWarning(message, _empty); + break; + case DiscordLogLevel.Error: + Interface.Oxide.LogError(message, _empty); + break; + case DiscordLogLevel.Exception: + Interface.Oxide.LogException(message, ex); + break; + default: + Interface.Oxide.LogInfo(message, _empty); + break; } - - public void OnShutdown() {} } + + public void OnShutdown() {} } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Logging/DiscordFileLogger.cs b/Oxide.Ext.Discord/Logging/DiscordFileLogger.cs index 984897a88..3248befec 100644 --- a/Oxide.Ext.Discord/Logging/DiscordFileLogger.cs +++ b/Oxide.Ext.Discord/Logging/DiscordFileLogger.cs @@ -8,82 +8,77 @@ using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Logging +namespace Oxide.Ext.Discord.Logging; + +/// +/// Represents a File Logger for Discord +/// +internal class DiscordFileLogger : IOutputLogger { - /// - /// Represents a File Logger for Discord - /// - internal class DiscordFileLogger : IOutputLogger - { - private readonly ConcurrentQueue _messages = new ConcurrentQueue(); - private readonly string _logFileName; - private readonly string _dateTimeFormat; - private readonly AutoResetEvent _reset; + private readonly ConcurrentQueue _messages = new(); + private readonly string _logFileName; + private readonly string _dateTimeFormat; + private readonly AutoResetEvent _reset; - private static readonly ThreadLocal Builder = new ThreadLocal(() => new StringBuilder()); + private static readonly ThreadLocal Builder = new(() => new StringBuilder()); - internal DiscordFileLogger(string pluginName, string dateTimeFormat, AutoResetEvent reset) + internal DiscordFileLogger(string pluginName, string dateTimeFormat, AutoResetEvent reset) + { + _dateTimeFormat = dateTimeFormat; + _reset = reset; + string logPath = Path.Combine(Interface.Oxide.LogDirectory, pluginName); + if (!Directory.Exists(logPath)) { - _dateTimeFormat = dateTimeFormat; - _reset = reset; - string logPath = Path.Combine(Interface.Oxide.LogDirectory, pluginName); - if (!Directory.Exists(logPath)) - { - Directory.CreateDirectory(logPath); - } - - _logFileName = Path.Combine(logPath, $"{pluginName}-{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt"); + Directory.CreateDirectory(logPath); } + + _logFileName = Path.Combine(logPath, $"{pluginName}-{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt"); + } - public void AddMessage(DiscordLogLevel level, string log, object[] args, Exception ex) + public void AddMessage(DiscordLogLevel level, string log, object[] args, Exception ex) + { + StringBuilder sb = Builder.Value; + sb.Clear(); + Span span = stackalloc char[_dateTimeFormat.Length]; + DateTime.Now.TryFormat(span, out int written, _dateTimeFormat); + sb.Append(span.Slice(0, written)); + sb.Append(" ["); + sb.Append(EnumCache.Instance.ToString(level)); + sb.Append("]: "); + if (args.Length != 0) + { + sb.AppendFormat(log, args); + } + else { - StringBuilder sb = Builder.Value; - sb.Clear(); - char[] formatting = ArrayPool.Shared.Rent(_dateTimeFormat.Length); - Span span = formatting.AsSpan(); - DateTime.Now.TryFormat(span, out int written, _dateTimeFormat); - sb.Append(span.Slice(0, written)); - sb.Append(" ["); - sb.Append(EnumCache.Instance.ToString(level)); - sb.Append("]: "); - if (args.Length != 0) - { - sb.AppendFormat(log, args); - } - else - { - sb.Append(log); - } + sb.Append(log); + } - _messages.Enqueue(sb.ToString()); - if (ex != null) - { - _messages.Enqueue(ex.ToString()); - } - _reset.Set(); - ArrayPool.Shared.Return(formatting); + _messages.Enqueue(sb.ToString()); + if (ex != null) + { + _messages.Enqueue(ex.ToString()); } + _reset.Set(); + } - internal void WriteLog() + internal void WriteLog() + { + if (_messages.IsEmpty) { - if (_messages.IsEmpty) - { - return; - } - - using (StreamWriter fileWriter = File.AppendText(_logFileName)) - { - while (_messages.TryDequeue(out string message)) - { - fileWriter.WriteLine(message); - } - } + return; } - public void OnShutdown() + using StreamWriter fileWriter = File.AppendText(_logFileName); + while (_messages.TryDequeue(out string message)) { - WriteLog(); - DiscordFileLoggerFactory.Instance.RemoveLogger(this); + fileWriter.WriteLine(message); } } + + public void OnShutdown() + { + WriteLog(); + DiscordFileLoggerFactory.Instance.RemoveLogger(this); + } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Logging/DiscordFileLoggerFactory.cs b/Oxide.Ext.Discord/Logging/DiscordFileLoggerFactory.cs index 7874b2acc..2398cc35e 100644 --- a/Oxide.Ext.Discord/Logging/DiscordFileLoggerFactory.cs +++ b/Oxide.Ext.Discord/Logging/DiscordFileLoggerFactory.cs @@ -3,63 +3,62 @@ using System.Threading; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Logging +namespace Oxide.Ext.Discord.Logging; + +internal sealed class DiscordFileLoggerFactory : Singleton { - internal sealed class DiscordFileLoggerFactory : Singleton - { - private readonly Thread _writerThread; - private readonly List _loggers = new List(); - private readonly AutoResetEvent _reset = new AutoResetEvent(false); - private bool _exit; + private readonly Thread _writerThread; + private readonly List _loggers = []; + private readonly AutoResetEvent _reset = new(false); + private bool _exit; - private DiscordFileLoggerFactory() + private DiscordFileLoggerFactory() + { + _writerThread = new Thread(WriteLogThread) { - _writerThread = new Thread(WriteLogThread) - { - IsBackground = true, - Name = nameof(DiscordFileLogger) - }; - _writerThread.Start(); - } + IsBackground = true, + Name = nameof(DiscordFileLogger) + }; + _writerThread.Start(); + } - public DiscordFileLogger CreateLogger(string pluginName, string dateTimeFormat) - { - DiscordFileLogger logger = new DiscordFileLogger(pluginName, dateTimeFormat, _reset); - _loggers.Add(logger); - return logger; - } + public DiscordFileLogger CreateLogger(string pluginName, string dateTimeFormat) + { + DiscordFileLogger logger = new(pluginName, dateTimeFormat, _reset); + _loggers.Add(logger); + return logger; + } - private void WriteLogThread() + private void WriteLogThread() + { + try { - try + while (!_exit) { - while (!_exit) + _reset.WaitOne(); + for (int index = 0; index < _loggers.Count; index++) { - _reset.WaitOne(); - for (int index = 0; index < _loggers.Count; index++) - { - _loggers[index].WriteLog(); - } + _loggers[index].WriteLog(); } } - catch (ThreadAbortException) { } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An exception occured writing log file.", ex); - WriteLogThread(); - } } - - internal void OnServerShutdown() + catch (ThreadAbortException) { } + catch (Exception ex) { - _exit = true; - _reset.Set(); - _writerThread.Join(TimeSpan.FromSeconds(5)); + DiscordExtension.GlobalLogger.Exception("An exception occured writing log file.", ex); + WriteLogThread(); } + } + + internal void OnServerShutdown() + { + _exit = true; + _reset.Set(); + _writerThread.Join(TimeSpan.FromSeconds(5)); + } - internal void RemoveLogger(DiscordFileLogger logger) - { - _loggers.Remove(logger); - } + internal void RemoveLogger(DiscordFileLogger logger) + { + _loggers.Remove(logger); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Logging/DiscordLogHandler.cs b/Oxide.Ext.Discord/Logging/DiscordLogHandler.cs index e4afefee7..e74a19591 100644 --- a/Oxide.Ext.Discord/Logging/DiscordLogHandler.cs +++ b/Oxide.Ext.Discord/Logging/DiscordLogHandler.cs @@ -1,33 +1,34 @@ using System; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Logging +namespace Oxide.Ext.Discord.Logging; + +internal class DiscordLogHandler { - internal class DiscordLogHandler - { - private readonly DiscordConsoleLogger _consoleLogger; - private readonly DiscordFileLogger _fileLogger; + private readonly DiscordConsoleLogger _consoleLogger; + private readonly DiscordFileLogger _fileLogger; + public bool IsShutdown { get; private set; } - public DiscordLogHandler(string pluginName, IDiscordLoggingConfig config, bool isExtension) - { - _consoleLogger = isExtension || config.ConsoleLogLevel != DiscordLogLevel.Off ? new DiscordConsoleLogger(pluginName) : null; - _fileLogger = isExtension || config.FileLogLevel != DiscordLogLevel.Off ? DiscordFileLoggerFactory.Instance.CreateLogger(pluginName, config.FileDateTimeFormat) : null; - } + public DiscordLogHandler(string pluginName, IDiscordLoggingConfig config, bool isExtension) + { + _consoleLogger = isExtension || config.ConsoleLogLevel != DiscordLogLevel.Off ? new DiscordConsoleLogger(pluginName) : null; + _fileLogger = isExtension || config.FileLogLevel != DiscordLogLevel.Off ? DiscordFileLoggerFactory.Instance.CreateLogger(pluginName, config.FileDateTimeFormat) : null; + } - public void LogConsole(DiscordLogLevel level, string log, object[] args, Exception exception = null) - { - _consoleLogger?.AddMessage(level, log, args, exception); - } + public void LogConsole(DiscordLogLevel level, string log, object[] args, Exception exception = null) + { + _consoleLogger?.AddMessage(level, log, args, exception); + } - public void LogFile(DiscordLogLevel level, string log, object[] args, Exception exception = null) - { - _fileLogger?.AddMessage(level, log, args, exception); - } + public void LogFile(DiscordLogLevel level, string log, object[] args, Exception exception = null) + { + _fileLogger?.AddMessage(level, log, args, exception); + } - public void Shutdown() - { - _consoleLogger?.OnShutdown(); - _fileLogger?.OnShutdown(); - } + public void Shutdown() + { + _consoleLogger?.OnShutdown(); + _fileLogger?.OnShutdown(); + IsShutdown = true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Logging/DiscordLogLevel.cs b/Oxide.Ext.Discord/Logging/DiscordLogLevel.cs index ba1d63989..36669c725 100644 --- a/Oxide.Ext.Discord/Logging/DiscordLogLevel.cs +++ b/Oxide.Ext.Discord/Logging/DiscordLogLevel.cs @@ -1,43 +1,42 @@ -namespace Oxide.Ext.Discord.Logging +namespace Oxide.Ext.Discord.Logging; + +/// +/// Represents the log level for a logger +/// +public enum DiscordLogLevel : byte { /// - /// Represents the log level for a logger + /// Verbose log level displays all message /// - public enum DiscordLogLevel : byte - { - /// - /// Verbose log level displays all message - /// - Verbose, + Verbose, - /// - /// Debug log level display all messages up to and include Debug - /// - Debug, + /// + /// Debug log level display all messages up to and including Debug + /// + Debug, - /// - /// Info log level display all messages up to and include Info - /// - Info, + /// + /// Info log level display all messages up to and including Info + /// + Info, - /// - /// Warning log level display all messages up to and include Warning - /// - Warning, + /// + /// Warning log level display all messages up to and including Warning + /// + Warning, - /// - /// Error log level display all messages up to and include Error - /// - Error, + /// + /// Error log level display all messages up to and including Error + /// + Error, - /// - /// Exception log level display all messages up to and include Exception - /// - Exception, + /// + /// Exception log level display all messages up to and including Exception + /// + Exception, - /// - /// Disables all logging - /// - Off - } + /// + /// Disables all logging + /// + Off } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Logging/DiscordLogger.cs b/Oxide.Ext.Discord/Logging/DiscordLogger.cs index e7ed79413..9780b4b35 100644 --- a/Oxide.Ext.Discord/Logging/DiscordLogger.cs +++ b/Oxide.Ext.Discord/Logging/DiscordLogger.cs @@ -1,73 +1,74 @@ using System; +using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Logging +namespace Oxide.Ext.Discord.Logging; + +/// +/// Represents a discord extension logger +/// +public class DiscordLogger : ILogger { + /// + public DiscordLogLevel LogLevel { get; private set; } + private readonly IDiscordLoggingConfig _config; + private readonly DiscordLogHandler _handler; + /// - /// Represents a discord extension logger + /// Creates a new logger with the given log level /// - public class DiscordLogger : ILogger + /// Log level of the logger + /// Configuration for the logger + /// Handler for the logger + internal DiscordLogger(DiscordLogLevel logLevel, IDiscordLoggingConfig config, DiscordLogHandler handler) { - /// - public DiscordLogLevel LogLevel { get; private set; } - private readonly IDiscordLoggingConfig _config; - private readonly DiscordLogHandler _handler; + LogLevel = logLevel; + _config = config; + _handler = handler; + } - /// - /// Creates a new logger with the given log level - /// - /// Log level of the logger - /// Configuration for the logger - /// Handler for the logger - internal DiscordLogger(DiscordLogLevel logLevel, IDiscordLoggingConfig config, DiscordLogHandler handler) + /// + public void Log(DiscordLogLevel level, string log, object[] args, Exception exception = null) + { + DiscordLoggerException.ThrowIfShutdown(_handler); + if (IsConsoleLogging(level)) { - LogLevel = logLevel; - _config = config; - _handler = handler; + _handler.LogConsole(level, log, args, exception); } - /// - public void Log(DiscordLogLevel level, string log, object[] args, Exception exception = null) + if (IsFileLogging(level)) { - if (IsConsoleLogging(level)) - { - _handler.LogConsole(level, log, args, exception); - } - - if (IsFileLogging(level)) - { - _handler.LogFile(level, log, args, exception); - } + _handler.LogFile(level, log, args, exception); } + } - /// - public void UpdateLogLevel(DiscordLogLevel level) - { - LogLevel = level; - } + /// + public void UpdateLogLevel(DiscordLogLevel level) + { + LogLevel = level; + } - /// - public bool IsLogging(DiscordLogLevel level) - { - return level >= LogLevel && (level >= _config.ConsoleLogLevel || level >= _config.FileLogLevel); - } + /// + public bool IsLogging(DiscordLogLevel level) + { + return level >= LogLevel && (level >= _config.ConsoleLogLevel || level >= _config.FileLogLevel); + } - /// - public bool IsConsoleLogging(DiscordLogLevel level) - { - return level >= LogLevel && level >= _config.ConsoleLogLevel; - } + /// + public bool IsConsoleLogging(DiscordLogLevel level) + { + return level >= LogLevel && level >= _config.ConsoleLogLevel; + } - /// - public bool IsFileLogging(DiscordLogLevel level) - { - return level >= LogLevel && level >= _config.FileLogLevel; - } + /// + public bool IsFileLogging(DiscordLogLevel level) + { + return level >= LogLevel && level >= _config.FileLogLevel; + } - /// - public void Shutdown() - { - _handler.Shutdown(); - } + /// + public void Shutdown() + { + _handler.Shutdown(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Logging/DiscordLoggerFactory.cs b/Oxide.Ext.Discord/Logging/DiscordLoggerFactory.cs index 313d663da..4426b8d58 100644 --- a/Oxide.Ext.Discord/Logging/DiscordLoggerFactory.cs +++ b/Oxide.Ext.Discord/Logging/DiscordLoggerFactory.cs @@ -5,72 +5,71 @@ using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Logging +namespace Oxide.Ext.Discord.Logging; + +/// +/// Factory for creating DiscordLoggers +/// +public sealed class DiscordLoggerFactory : Singleton { + private readonly Hash _handlers = new(); + + private DiscordLoggerFactory() {} + /// - /// Factory for creating DiscordLoggers + /// Returns a newly created for a given plugin /// - public sealed class DiscordLoggerFactory : Singleton + /// Plugin the logger is for + /// The current LogLevel for the logger + /// The config for the logger + /// + public DiscordLogger CreateLogger(Plugin plugin, DiscordLogLevel logLevel, IDiscordLoggingConfig config) { - private readonly Hash _handlers = new Hash(); - - private DiscordLoggerFactory() {} - - /// - /// Returns a newly created for a given plugin - /// - /// Plugin the logger is for - /// The current LogLevel for the logger - /// The config for the logger - /// - public DiscordLogger CreateLogger(Plugin plugin, DiscordLogLevel logLevel, IDiscordLoggingConfig config) - { - if (plugin == null) throw new ArgumentNullException(nameof(plugin)); - return GetLoggerInternal(plugin.Name, logLevel, config, false); - } + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + return GetLoggerInternal(plugin.Name, logLevel, config, false); + } - internal DiscordLogLevel GetLogLevel() - { - return DiscordConfig.Instance.Logging.ConsoleLogLevel <= DiscordConfig.Instance.Logging.FileLogLevel ? DiscordConfig.Instance.Logging.ConsoleLogLevel : DiscordConfig.Instance.Logging.FileLogLevel; - } + internal DiscordLogLevel GetLogLevel() + { + return DiscordConfig.Instance.Logging.ConsoleLogLevel <= DiscordConfig.Instance.Logging.FileLogLevel ? DiscordConfig.Instance.Logging.ConsoleLogLevel : DiscordConfig.Instance.Logging.FileLogLevel; + } - internal DiscordLogLevel GetLogLevel(DiscordLogLevel level) - { - DiscordLogLevel globalLevel = GetLogLevel(); - return level < globalLevel ? level : globalLevel; - } + internal DiscordLogLevel GetLogLevel(DiscordLogLevel level) + { + DiscordLogLevel globalLevel = GetLogLevel(); + return level < globalLevel ? level : globalLevel; + } - internal DiscordLogger CreateExtensionLogger() => CreateExtensionLogger(GetLogLevel()); - internal DiscordLogger CreateExtensionLogger(DiscordLogLevel logLevel) => GetLoggerInternal(nameof(DiscordExtension), GetLogLevel(logLevel), DiscordConfig.Instance.Logging, true); + internal DiscordLogger CreateExtensionLogger() => CreateExtensionLogger(GetLogLevel()); + internal DiscordLogger CreateExtensionLogger(DiscordLogLevel logLevel) => GetLoggerInternal(nameof(DiscordExtension), GetLogLevel(logLevel), DiscordConfig.Instance.Logging, true); - private DiscordLogger GetLoggerInternal(string pluginName, DiscordLogLevel logLevel, IDiscordLoggingConfig config, bool isExtension) + private DiscordLogger GetLoggerInternal(string pluginName, DiscordLogLevel logLevel, IDiscordLoggingConfig config, bool isExtension) + { + DiscordLogHandler handler = _handlers[pluginName]; + if (handler == null) { - DiscordLogHandler handler = _handlers[pluginName]; - if (handler == null) - { - handler = new DiscordLogHandler(pluginName, config, isExtension); - _handlers[pluginName] = handler; - } - - return new DiscordLogger(logLevel, config, handler); + handler = new DiscordLogHandler(pluginName, config, isExtension); + _handlers[pluginName] = handler; } - internal void OnPluginUnloaded(Plugin plugin) - { - string name = plugin.Name; - _handlers[name]?.Shutdown(); - _handlers.Remove(name); - } + return new DiscordLogger(logLevel, config, handler); + } + + internal void OnPluginUnloaded(Plugin plugin) + { + string name = plugin.Name; + _handlers[name]?.Shutdown(); + _handlers.Remove(name); + } - internal void OnServerShutdown() + internal void OnServerShutdown() + { + foreach (DiscordLogHandler handler in _handlers.Values) { - foreach (DiscordLogHandler handler in _handlers.Values) - { - handler.Shutdown(); - } - - _handlers.Clear(); - DiscordFileLoggerFactory.Instance.OnServerShutdown(); + handler.Shutdown(); } + + _handlers.Clear(); + DiscordFileLoggerFactory.Instance.OnServerShutdown(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Logging/Logger.Ext.cs b/Oxide.Ext.Discord/Logging/Logger.Ext.cs index 52aabeee0..1e5e2ec4e 100644 --- a/Oxide.Ext.Discord/Logging/Logger.Ext.cs +++ b/Oxide.Ext.Discord/Logging/Logger.Ext.cs @@ -4,746 +4,745 @@ #pragma warning disable CS1591 -namespace Oxide.Ext.Discord.Logging +namespace Oxide.Ext.Discord.Logging; + +public static class LoggerExt { - public static class LoggerExt + #region Verbose + public static void Verbose(this ILogger logger, string message) { - #region Verbose - public static void Verbose(this ILogger logger, string message) + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message); - } + HandleLog(logger, DiscordLogLevel.Verbose, message); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0) + public static void Verbose(this ILogger logger, string message, T1 arg0) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1) + public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2) + public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3) + public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) + public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) + public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) + public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) + public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) + public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) + public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } + } - public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) + public static void Verbose(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) + { + if (logger.IsLogging(DiscordLogLevel.Verbose)) { - if (logger.IsLogging(DiscordLogLevel.Verbose)) - { - HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); - } + HandleLog(logger, DiscordLogLevel.Verbose, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } - #endregion + } + #endregion - #region Debug - public static void Debug(this ILogger logger, string message) + #region Debug + public static void Debug(this ILogger logger, string message) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message); - } + HandleLog(logger, DiscordLogLevel.Debug, message); } + } - public static void Debug(this ILogger logger, string message, T1 arg0) + public static void Debug(this ILogger logger, string message, T1 arg0) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0); } + } - public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1) + public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1); } + } - public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2) + public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2); } + } - public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3) + public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3); } + } - public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) + public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4); } + } - public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) + public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5); } + } - public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) + public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6); } + } - public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) + public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } + } - public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) + public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } + } - public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) + public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } + } - public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) + public static void Debug(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) + { + if (logger.IsLogging(DiscordLogLevel.Debug)) { - if (logger.IsLogging(DiscordLogLevel.Debug)) - { - HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); - } + HandleLog(logger, DiscordLogLevel.Debug, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } - #endregion + } + #endregion - #region Info - public static void Info(this ILogger logger, string message) + #region Info + public static void Info(this ILogger logger, string message) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message); - } + HandleLog(logger, DiscordLogLevel.Info, message); } + } - public static void Info(this ILogger logger, string message, T1 arg0) + public static void Info(this ILogger logger, string message, T1 arg0) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0); } + } - public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1) + public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1); } + } - public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2) + public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2); } + } - public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3) + public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3); } + } - public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) + public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4); } + } - public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) + public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5); } + } - public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) + public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6); } + } - public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) + public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } + } - public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) + public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } + } - public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) + public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } + } - public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) + public static void Info(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) + { + if (logger.IsLogging(DiscordLogLevel.Info)) { - if (logger.IsLogging(DiscordLogLevel.Info)) - { - HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); - } + HandleLog(logger, DiscordLogLevel.Info, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } - #endregion + } + #endregion - #region Warning - public static void Warning(this ILogger logger, string message) + #region Warning + public static void Warning(this ILogger logger, string message) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message); - } + HandleLog(logger, DiscordLogLevel.Warning, message); } + } - public static void Warning(this ILogger logger, string message, T1 arg0) + public static void Warning(this ILogger logger, string message, T1 arg0) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0); } + } - public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1) + public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1); } + } - public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2) + public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2); } + } - public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3) + public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3); } + } - public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) + public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4); } + } - public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) + public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5); } + } - public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) + public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6); } + } - public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) + public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } + } - public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) + public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } + } - public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) + public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } + } - public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) + public static void Warning(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) + { + if (logger.IsLogging(DiscordLogLevel.Warning)) { - if (logger.IsLogging(DiscordLogLevel.Warning)) - { - HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); - } + HandleLog(logger, DiscordLogLevel.Warning, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } - #endregion + } + #endregion - #region Error - public static void Error(this ILogger logger, string message) + #region Error + public static void Error(this ILogger logger, string message) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message); - } + HandleLog(logger, DiscordLogLevel.Error, message); } + } - public static void Error(this ILogger logger, string message, T1 arg0) + public static void Error(this ILogger logger, string message, T1 arg0) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0); } + } - public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1) + public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1); } + } - public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2) + public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2); } + } - public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3) + public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3); } + } - public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) + public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4); } + } - public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) + public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5); } + } - public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) + public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6); } + } - public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) + public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } + } - public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) + public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } + } - public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) + public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } + } - public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) + public static void Error(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10) + { + if (logger.IsLogging(DiscordLogLevel.Error)) { - if (logger.IsLogging(DiscordLogLevel.Error)) - { - HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); - } + HandleLog(logger, DiscordLogLevel.Error, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } - #endregion + } + #endregion - #region Exception - public static void Exception(this ILogger logger, string message, Exception exception = null) + #region Exception + public static void Exception(this ILogger logger, string message, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, exception); } + } - public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10, Exception exception = null) + public static void Exception(this ILogger logger, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10, Exception exception = null) + { + if (logger.IsLogging(DiscordLogLevel.Exception)) { - if (logger.IsLogging(DiscordLogLevel.Exception)) - { - HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, exception); - } + HandleLog(logger, DiscordLogLevel.Exception, message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, exception); } - #endregion + } + #endregion - #region HandleLog - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, Exception exception = null) - { - logger.Log(level, message, Array.Empty(), exception); - } + #region HandleLog + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, Exception exception = null) + { + logger.Log(level, message, [], exception); + } - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(1); - array[0] = arg0; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(1); + array[0] = arg0; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); + } - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(2); - array[0] = arg0; - array[1] = arg1; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(2); + array[0] = arg0; + array[1] = arg1; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); + } - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(3); - array[0] = arg0; - array[1] = arg1; - array[2] = arg2; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(3); + array[0] = arg0; + array[1] = arg1; + array[2] = arg2; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); + } - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(4); - array[0] = arg0; - array[1] = arg1; - array[2] = arg2; - array[3] = arg3; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } - - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(5); - array[0] = arg0; - array[1] = arg1; - array[2] = arg2; - array[3] = arg3; - array[4] = arg4; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } - - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(6); - array[0] = arg0; - array[1] = arg1; - array[2] = arg2; - array[3] = arg3; - array[4] = arg4; - array[5] = arg5; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } - - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(7); - array[0] = arg0; - array[1] = arg1; - array[2] = arg2; - array[3] = arg3; - array[4] = arg4; - array[5] = arg5; - array[6] = arg6; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } - - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(8); - array[0] = arg0; - array[1] = arg1; - array[2] = arg2; - array[3] = arg3; - array[4] = arg4; - array[5] = arg5; - array[6] = arg6; - array[7] = arg7; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } - - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(9); - array[0] = arg0; - array[1] = arg1; - array[2] = arg2; - array[3] = arg3; - array[4] = arg4; - array[5] = arg5; - array[6] = arg6; - array[7] = arg7; - array[8] = arg8; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } - - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(10); - array[0] = arg0; - array[1] = arg1; - array[2] = arg2; - array[3] = arg3; - array[4] = arg4; - array[5] = arg5; - array[6] = arg6; - array[7] = arg7; - array[8] = arg8; - array[9] = arg9; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } - - private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10, Exception exception = null) - { - object[] array = ArrayPool.Instance.Get(11); - array[0] = arg0; - array[1] = arg1; - array[2] = arg2; - array[3] = arg3; - array[4] = arg4; - array[5] = arg5; - array[6] = arg6; - array[7] = arg7; - array[8] = arg8; - array[9] = arg9; - array[10] = arg10; - logger.Log(level, message, array, exception); - ArrayPool.Instance.Free(ref array); - } - #endregion + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(4); + array[0] = arg0; + array[1] = arg1; + array[2] = arg2; + array[3] = arg3; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); + } + + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(5); + array[0] = arg0; + array[1] = arg1; + array[2] = arg2; + array[3] = arg3; + array[4] = arg4; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); + } + + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(6); + array[0] = arg0; + array[1] = arg1; + array[2] = arg2; + array[3] = arg3; + array[4] = arg4; + array[5] = arg5; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); + } + + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(7); + array[0] = arg0; + array[1] = arg1; + array[2] = arg2; + array[3] = arg3; + array[4] = arg4; + array[5] = arg5; + array[6] = arg6; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); + } + + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(8); + array[0] = arg0; + array[1] = arg1; + array[2] = arg2; + array[3] = arg3; + array[4] = arg4; + array[5] = arg5; + array[6] = arg6; + array[7] = arg7; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); + } + + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(9); + array[0] = arg0; + array[1] = arg1; + array[2] = arg2; + array[3] = arg3; + array[4] = arg4; + array[5] = arg5; + array[6] = arg6; + array[7] = arg7; + array[8] = arg8; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); + } + + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(10); + array[0] = arg0; + array[1] = arg1; + array[2] = arg2; + array[3] = arg3; + array[4] = arg4; + array[5] = arg5; + array[6] = arg6; + array[7] = arg7; + array[8] = arg8; + array[9] = arg9; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); + } + + private static void HandleLog(ILogger logger, DiscordLogLevel level, string message, T1 arg0, T2 arg1, T3 arg2, T4 arg3, T5 arg4, T6 arg5, T7 arg6, T8 arg7, T9 arg8, T10 arg9, T11 arg10, Exception exception = null) + { + object[] array = ArrayPool.Instance.Get(11); + array[0] = arg0; + array[1] = arg1; + array[2] = arg2; + array[3] = arg3; + array[4] = arg4; + array[5] = arg5; + array[6] = arg6; + array[7] = arg7; + array[8] = arg8; + array[9] = arg9; + array[10] = arg10; + logger.Log(level, message, array, exception); + ArrayPool.Instance.Free(ref array); } + #endregion } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Oxide.Ext.Discord.csproj b/Oxide.Ext.Discord/Oxide.Ext.Discord.csproj index c6988b1e2..b60542f80 100644 --- a/Oxide.Ext.Discord/Oxide.Ext.Discord.csproj +++ b/Oxide.Ext.Discord/Oxide.Ext.Discord.csproj @@ -6,9 +6,9 @@ An Oxide extension for Discord. https://github.com/MJSU/Oxide.Ext.Discord net48; - 7 - 3.0.0 - 3.0.0 + 12 + 3.1.0 + 3.1.0 Debug;Release Carbon;Oxide $(outdir)Oxide.Ext.Discord.xml diff --git a/Oxide.Ext.Discord/Oxide.Ext.Discord.csproj.DotSettings b/Oxide.Ext.Discord/Oxide.Ext.Discord.csproj.DotSettings index 710ff0582..cea312bcb 100644 --- a/Oxide.Ext.Discord/Oxide.Ext.Discord.csproj.DotSettings +++ b/Oxide.Ext.Discord/Oxide.Ext.Discord.csproj.DotSettings @@ -20,6 +20,7 @@ True True True + True True True True @@ -42,6 +43,7 @@ True True True + True True True True @@ -77,6 +79,7 @@ True True True + True True True True diff --git a/Oxide.Ext.Discord/Oxide.Ext.Discord.xml b/Oxide.Ext.Discord/Oxide.Ext.Discord.xml index 839ec0ed3..f9b606672 100644 --- a/Oxide.Ext.Discord/Oxide.Ext.Discord.xml +++ b/Oxide.Ext.Discord/Oxide.Ext.Discord.xml @@ -554,7 +554,7 @@ Enable auto complete for the option - If the option support auto complete (Default: true) + If the option supports auto complete (Default: true) This @@ -617,7 +617,7 @@ Value of the choice Localizations for the name This - Thrown if option type is not string + Thrown if the option type is not string @@ -627,7 +627,7 @@ Value of the choice Localizations for the name This - Thrown if option type is not int + Thrown if the option type is not int @@ -637,7 +637,7 @@ Value of the choice Localizations for the name This - Thrown if option type is not double + Thrown if the option type is not double @@ -755,7 +755,7 @@ Adds an author to the embed message. The author will appear above the title Name of the author - Url to go to when the authors name is clicked on + Url to go to when the author's name is clicked on Icon Url to use for the author Backup icon url. Can be left null if you only have one icon url This @@ -804,9 +804,9 @@ Adds a RGB based color. Color appears as a bar on the left side of the message - Red value between 0 - 255 - Green value between 0 - 255 - Blue value between 0 - 255 + Red value between 0-255 + Green value between 0-255 + Blue value between 0-255 This Thrown if red, green, or blue is outside of range @@ -814,9 +814,9 @@ Adds a RGB based color. Color appears as a bar on the left side of the message - Red value between 0 - 1 - Green value between 0 - 1 - Blue value between 0 - 1 + Red value between 0-1 + Green value between 0-1 + Blue value between 0-1 This Thrown if red, green, or blue is outside of range @@ -824,9 +824,9 @@ Adds a RGB based color. Color appears as a bar on the left side of the message - Red value between 0 - 1 - Green value between 0 - 1 - Blue value between 0 - 1 + Red value between 0-1 + Green value between 0-1 + Blue value between 0-1 This Thrown if red, green, or blue is outside of range @@ -846,8 +846,8 @@ Adds a blank field. - If inline it will add a blank column. - If not inline will add a blank row + If inline, it will add a blank column. + If not, inline will add a blank row If the field is inline This @@ -855,7 +855,7 @@ Adds a new field with the name as the title and value as the value. - If inline will add a new column. If row will add in a new row. + If inline add a new column. If row adds in a new row. Name of the field Value of the field @@ -865,7 +865,7 @@ Adds an image to the embed. The url should point to the url of the image. - If using attachment image you can make the url: "attachment://{image name}.{image extension} + If using attachment image, you can make the url: "attachment://{image name}.{image extension} Url for the image width of the image @@ -875,8 +875,8 @@ - Adds a thumbnail in the top right corner of the embed - If using attachment image you can make the url: "attachment://{image name}.{image extension} + Adds a thumbnail in the top right corner of the embed, + If using attachment image, you can make the url: "attachment://{image name}.{image extension} Url for the image width of the image @@ -976,7 +976,7 @@ - Include Player Id in the player name + Include Player ID in the player name @@ -1215,7 +1215,7 @@ - Adds a player by player Id to the list + Adds a player by player ID to the list Player ID to add Formatter for the player name @@ -1352,7 +1352,7 @@ Emoji to display with the button - Throw if the button style is link or if the button goes outside the max number of action rows + Throw if the button style is a link or if the button goes outside the max number of action rows @@ -1464,18 +1464,18 @@ Sticker ID to be added This - + - Adds stickers to the message + Adds a sticker to the message - Sticker ID's to be added + Sticker to be added This - + - Adds a sticker to the message + Adds stickers to the message - Sticker to be added + Sticker ID's to be added This @@ -1608,7 +1608,7 @@ Build to add components from This - + Adds an attachment to the message @@ -1616,6 +1616,7 @@ byte[] of the attachment Attachment content type Description for the attachment + Title of the attachment @@ -1662,7 +1663,7 @@ - Constructor to use existing message + Constructor to use an existing message Message to use @@ -1687,12 +1688,6 @@ Builder used to build query strings for urls - - - Creates a pooled - - - Add a key value pair to the query string @@ -1715,18 +1710,6 @@ - - - Returns the query string and returns the builder back to the pool - - - - - - - - - Represents a cache for Loaded and Loadable plugins @@ -1752,7 +1735,7 @@ - Convert an emoji character to emoji string text + Convert an emoji character to the emoji string text Emoji to convert @@ -1768,16 +1751,48 @@ Replaces emoji character with emoji string characters - - + Text to replace + Replacement Text to use if non-matching Replaces emoji string text with emoji characters - - + Text to replace + Replacement Text to use if non-matching + + + + + Replaces emoji character with emoji string characters + + Text to replace + Replacement Evaluator function + + + + + Replaces emoji string text with emoji characters + + Text to replace + Replacement Evaluator function + + + + + Replaces emoji character with emoji string characters + If no match is found then the original text is used + + Text to replace + + + + + Replaces emoji string text with emoji characters + If no match is found then the original text is used + + Text to replace @@ -1798,7 +1813,7 @@ - Returns a cached for the given user ID or creates a new with that ID + Returns a cached {T} for the given user ID or creates a new {T} with that ID User ID to lookup in the cache Cached @@ -1849,7 +1864,7 @@ - Returns the next enum values. If the value is the last value it will start from the beginning + Returns the next enum values. If the value is the last value, it will start from the beginning Value to get the next enum from Next enum from the given value @@ -1900,14 +1915,14 @@ - Returns a cached ToString call of type {T} + Returns a cached ToString call of the type {T} value to ToString - Returns the lowered string representation of type {T} + Returns the lowered string representation of the type {T} value to lower @@ -2004,9 +2019,60 @@ + + + BaseClient that can connect to discord + + + + + Rest handler for all discord API calls + + + + + If the connection is initialized and not disconnected + + + + + List of all clients using this client + + + + + List of all clients that are using this bot client + + + + + Constructor + + + + + Returns the list of plugins for this bot + + + + + + Add a to this bot / webhook client + + Client to add + True if this is the initial setup of the client; false otherwise + Thrown if already has been added to this bot / webhook client + + + + Removes the from this bot / webhook client + + Client to remove + returns true if the client is shutting down; false otherwise + - Represents a bot that is connected to discord + Represents a bot connected to discord @@ -2016,7 +2082,7 @@ - All the direct messages that we have seen by channel Id + All the direct messages that we have seen by channel ID @@ -2024,11 +2090,6 @@ All the direct messages that we have seen by User ID - - - If the connection is initialized and not disconnected - - Application reference for this bot @@ -2039,11 +2100,6 @@ Bot User - - - Rest handler for all discord API calls - - Returns if the bot has fully loaded. @@ -2055,18 +2111,13 @@ Returns if ReadyData is set - - - List of all clients that are using this bot client - - Connection settings to use for the bot - + Connects the websocket to discord. Should only be called if the websocket is disconnected @@ -2078,30 +2129,16 @@ Should we attempt to reconnect to discord after closing Should we attempt to resume the previous session - + - Called when bot client is no longer used by any client and can be shutdown. + Called when the bot client is no longer used by any client and can be shutdown. - - - Add a client to this bot client - - Client to add to the bot - Setup data for the plugin + + - - Remove a client from the bot client - If not clients are left bot will shutdown - - Client to remove from bot client - - - - Returns the list of plugins for this bot - - + @@ -2128,8 +2165,8 @@ Returns the channel for the given channel ID. - If guild ID is null it will search for a direct message channel - If guild ID is not null it will search for a guild channel + If guild ID is null, it will search for a direct message channel + If guild ID is not null, it will search for a guild channel @@ -2170,7 +2207,7 @@ - Represents the object a plugin uses to connects to discord + Represents the object a plugin uses to connect to discord @@ -2193,6 +2230,11 @@ The bot client that is unique to the Token used + + + Webhook clients for this DiscordClient + + Settings used to connect to discord and configure the extension @@ -2209,7 +2251,7 @@ Starts a connection to discord with the given apiKey and intents API key for the connecting bot - Intents the bot needs in order to function + Intents the bot needs to function @@ -2217,6 +2259,18 @@ Discord connection settings + + + Connect to the webhook + + Webhook URL to connect to + + + + Connect to the webhook + + Webhook connection to connect to + Disconnects this client from discord @@ -2224,7 +2278,7 @@ - Returns if the client is connected to a bot and if the bot is initialized + Returns if the client is connected to a bot / webhook and if the bot / webhook is initialized @@ -2242,10 +2296,32 @@ - Used to update the bots status in discord + Used to update the bot status in discord + + + A client that can connect to a webhook + + + + + Webhook that has been connected to + + + + + Constructor + + Connection for the webhook + + + + + + + Represents Discord Extension Bot Config @@ -2442,17 +2518,17 @@ - Returns if the settings has the given intents + Returns if the settings have the given intents Intents to be compared against - True if settings has the given intents; False otherwise + True if settings have the given intents; False otherwise - Returns if the settings has any intent specified + Returns if the settings have any intent specified Intents to compare against - True if settings has at least one of the given intents + True if settings have at least one of the given intents @@ -2476,6 +2552,34 @@ + + + Connection for a webhook + + + + + API token for the bot + + + + + Token for the webhook + + + + + Discord Extension Logging Level. + See + + + + + Constructor for a webhook connection + + URL of the webhook + Log level for the webhook + Encoding format the Discord Uses @@ -3766,12 +3870,30 @@ - + Called when we receive an event we do not handle yet. If you need this event, you can listen to it using this hook until we support it Please create an issue on uMod if this error ever occurs + void OnDiscordPollVoteAdded(MessagePollVoteAddedEvent vote, DiscordGuild guild) + { + Puts("OnDiscordPollVoteAdded Works!"); + } + + + + + + void OnDiscordAutoModActionExecuted(MessagePollVoteRemovedEvent vote, DiscordGuild guild) + { + Puts("OnDiscordPollVoteRemoved Works!"); + } + + + + + void OnDiscordUnhandledCommand(EventPayload payload) { Puts("OnDiscordUnhandledCommand Works!"); @@ -3811,7 +3933,7 @@ - Total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond ratelimit precision + Total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond rate-limit precision @@ -4043,6 +4165,9 @@ Playing {name} + + Playing {name} + Streaming {name} @@ -4076,7 +4201,7 @@ - Stream url, is validated when type is 1 + Stream url is validated when type is 1 @@ -4532,6 +4657,31 @@ Indicates if an app has registered global application commands + + + Represents a Application Integration Types + + + + + App is installable to servers + + + + + App is installable to users + + + + + Represents a Application Integration Type Configuration + + + + + Install params for each installation context's default in-app authorization link + + Represents Edit Application Structure @@ -4557,6 +4707,11 @@ Settings for the application's default in-app authorization link, if enabled + + + Default scopes and permissions for each supported installation context. + + App's public flags @@ -4712,6 +4867,11 @@ Settings for the application's default in-app authorization link, if enabled + + + Default scopes and permissions for each supported installation context + + The application's default custom authorization link, if enabled @@ -4849,9 +5009,87 @@ Client to use The records to update on the application + + + Returns the list of all application emojis + + Client to use + + + + Return an application emoji by ID + + Client to use + ID of the emoji + + + + Creates a new application emoji + + Client to use + Emoji to create + + + + Updates an existing application emoji + + Client to use + ID of the emoji to update + Update to the application emoji + + + + Deletes an application emoji + + Client to use + ID of the emoji to delete + + + + Represents Application Emoji Create Structure + + + + + Emoji name + + + + + The 128x128 emoji image + Emojis and animated emojis have a maximum file size of 256kb. + Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request + + + + + + + + Represents Application Emojis + + + + + List of application emojis + + + + + Represents Emoji Update Structure + + + + + Emoji name + + + + + Represents a Install Params Structure @@ -5011,6 +5249,11 @@ MODERATE_MEMBERS permission is required to use the TIMEOUT action type. + + + Prevents a member from using text, voice, or other interactions + + Represents Auto Mod Event Type @@ -5021,6 +5264,11 @@ When a member sends or edits a message in the guild + + + When a member edits their profile + + Represents Auto Mod Keyword Preset Types @@ -5317,6 +5565,11 @@ Check if content contains more unique mentions than allowed + + + Check if member profile contains words from a user defined list of keywords + + Represents a Guild Channel Create Structure @@ -6389,7 +6642,7 @@ - Represents the type of a permission + Represents the type of permission @@ -6759,7 +7012,7 @@ Attachments for the message - + Adds an attachment to the message @@ -6767,6 +7020,7 @@ byte[] of the attachment Attachment content type Description for the attachment + Title of the attachment @@ -7115,7 +7369,7 @@ - The ID for the emoji if it is custom; Otherwise invalid snowflake + The ID for the emoji if it is custom; Otherwise default snowflake @@ -8097,39 +8351,99 @@ The id of the guild - + - Represents Message Reaction Add + Represents Message Poll Vote Added Event - + - The id of the user + ID of the user - + The id of the channel - + - The id of the message + ID of the message - + - The id of the guild + ID of the guild - + - The member who reacted if this happened in a guild + ID of the answer - + - The emoji used to react + Represents Message Poll Vote Removed Event + + + + + ID of the user + + + + + The id of the channel + + + + + ID of the message + + + + + ID of the guild + + + + + ID of the answer + + + + + Represents Message Reaction Add + + + + + The id of the user + + + + + The id of the channel + + + + + The id of the message + + + + + The id of the guild + + + + + The member who reacted if this happened in a guild + + + + + The emoji used to react @@ -8137,6 +8451,21 @@ ID of the user who authored the message which was reacted to + + + True if this is a super-reaction + + + + + Colors used for super-reaction animation + + + + + The type of the reaction + + Represents Message Reaction Remove All @@ -8194,7 +8523,17 @@ - The emoji removed + Emoji used to react + + + + + True if this is a super-reaction + + + + + The type of the reaction @@ -9020,7 +9359,7 @@ Client to use UserID to get guild member for - + Returns a list of guild member objects that are members of the guild. In the future, this endpoint will be restricted in line with our Privileged Intents @@ -9901,6 +10240,11 @@ When the user's timeout will expire and the user will be able to communicate in the guild again, null or a time in the past if the user is not timed out + + + Data for the member's guild avatar decoration + + When the Nickname was last updated UTC. Null if we haven't seen a nickname update yet @@ -11570,9 +11914,14 @@ Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. - + - Indicates whether the command is age-restricted + Installation context(s) where the command is available + + + + + Interaction context(s) where the command can be used @@ -11580,6 +11929,11 @@ The of the command + + + Indicates whether the command is age-restricted + + Constructor @@ -11896,6 +12250,16 @@ Whether the command is enabled by default when the app is added to a guild + + + Installation context(s) where the command is available + + + + + Interaction context(s) where the command can be used + + Indicates whether the command is age-restricted @@ -11977,6 +12341,18 @@ Indicates whether the command is age-restricted + + + Installation context(s) where the command is available, only for globally-scoped commands. + Defaults to GUILD_INSTALL (0) + + + + + Interaction context(s) where the command can be used, only for globally-scoped commands. + By default, all interaction context types included for new commands.. + + Auto incrementing version identifier updated during substantial record changes @@ -12083,6 +12459,11 @@ See + + + Guild that the interaction was sent from + + Guild that the interaction was sent from @@ -12127,7 +12508,7 @@ - Bitwise set of permissions the app or bot has within the channel the interaction was sent from + Bitwise set of permissions the app has in the source location of the interaction @@ -12147,6 +12528,16 @@ For monetized apps, any entitlements for the invoking user, representing access to premium SKUs + + + Mapping of installation contexts that the interaction was authorized for to related user or guild IDs + + + + + Context where the interaction was triggered from + + Returns the interaction parsed args to make it easier to process that interaction. @@ -12296,12 +12687,6 @@ Client to use - - - Creates a response indication that the interaction requires premium to be purchased. - - Client to use - Gets the initial Interaction response @@ -12386,6 +12771,26 @@ Client to use Message ID to delete + + + Represents a Interaction Context Types + + + + + Interaction can be used within servers + + + + + Interaction can be used within DMs with the app's bot user + + + + + Interaction can be used within Group DMs and DMs other than the app's bot user + + Represents ApplicationCommandInteractionData @@ -12754,11 +13159,6 @@ Note: You can't respond to a ModalSubmit with a new MODAL. - - - Respond to an interaction with an upgrade button, only available for apps with monetization enabled - - Represents InteractionType @@ -12856,6 +13256,11 @@ Emoji on the component + + + Identifier for a purchasable SKU, only available when using premium-style buttons + + URL for link-style buttons @@ -12912,6 +13317,13 @@ Requires Url field + + + Color blurple + Navigates to a URL + Requires SkuId field + + Represents a Input Text Component within discord. @@ -13337,21 +13749,6 @@ Message to use for the response - - - Message for Premium Required - - - - - Response for premium Required - - - - - Constructor - - Represents Interaction Response @@ -13380,6 +13777,11 @@ Represents an Invite Structure that when used, adds a user to a guild or group DM channel. + + + The type of the invite + + The invite code (unique ID) @@ -13536,6 +13938,26 @@ The topic of the Stage instance (1-120 characters) + + + Represents Invite Types + + + + + Guild Invite + + + + + Guild Invite + + + + + Guild Invite + + Represents Target User Types @@ -13664,6 +14086,11 @@ Attachments for the message + + + Poll Create Request + + Attachments for a discord message @@ -13674,7 +14101,7 @@ Attachments for the message - + Adds an attachment to the message @@ -13682,6 +14109,7 @@ byte[] of the attachment Attachment content type Description for the attachment + Title of the attachment @@ -13836,6 +14264,13 @@ + + + The message associated with the message_reference. + This is a minimal subset of fields in a message (e.g. author is excluded.) + + + Message flags combined as a bitfield @@ -13847,6 +14282,11 @@ The message associated with the message_reference + + + sent if the message is sent as a result of an interaction + + Sent if the message is a response to an Interaction @@ -13877,6 +14317,16 @@ The data of the role subscription purchase or renewal that prompted this ROLE_SUBSCRIPTION_PURCHASE message + + + Poll object + + + + + The call associated with the message + + File Attachments to add to the message on edit @@ -14212,11 +14662,28 @@ Creates a new public thread this message - See + See Start Thread Client to use Data to use when creating the thread + + + Get a list of users that voted for this specific answer. + See Get Answer Voters + + Client to use + Answer to get voters for + + + + + Immediately ends the poll. + You cannot end polls from other users. + See End Poll + + Client to use + Represents Embed Structure @@ -14605,6 +15072,11 @@ Name of file attached + + + Title of the file + + Description for the file @@ -14660,6 +15132,21 @@ Attachment Flags + + + Represents a Message Call Structure + + + + + Array of user ids that participated in the call + + + + + Time when call ended + + Represents a Message Create Structure to be created in discord @@ -14678,7 +15165,7 @@ - Include to make your message a reply + Include to make your message a reply or a forward @@ -14804,6 +15291,46 @@ Member who invoked the interaction in the guild + + + Represents a Message Interaction Metadata Structure within Discord. + + + + + ID of the interaction + + + + + Type of interaction + + + + + IUser who triggered the interaction + + + + + IDs for installation context(s) related to an interaction. + + + + + ID of the original response message, present only on follow-up messages + + + + + ID of the message that contained interactive component, present only on messages created from component interactions + + + + + Metadata for the interaction that was used to open the modal, present only on modal submit interactions + + Represents a Reaction Structure @@ -14846,6 +15373,11 @@ Represents a Message Reference Structure for a message + + + Type of reference. + + ID of the originating message @@ -14867,6 +15399,36 @@ When sending, whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message, default true + + + Represents Message Reference Type + + + + + A standard reference used by replies. + + + + + Reference used to point to a message at a point in time. + + + + + Represents a Message Snapshot + + + + + Subset of fields in the message object + + + + + ID of the origin message's guild + + Represents Message Types @@ -15032,6 +15594,31 @@ Message is a Guild Application Premium Subscription + + + Message is a Guild Incident Alert Mode Enabled + + + + + Message is a Guild Incident Alert Mode Disabled + + + + + Message is a Guild Incident Report Raid + + + + + Message is a Guild Incident Report False Alarm + + + + + Message is a Purchase Notification + + Represents a Message Update Structure sent in a channel within Discord.. @@ -15096,6 +15683,179 @@ + + + Represents a Discord Poll + + + + + The question of the poll. Only text is supported. + + + + + Each of the answers available in the poll. + + + + + The time when the poll ends. + + + + + Whether a user can select multiple answers + + + + + The layout type of the poll + + + + + The results of the poll + + + + + Represents a Get Poll Answers Response + + + + + Users who voted for this answer + + + + + Represents a Get Answer Voters Query String Params + + + + + The type of reaction + + + + + Get users after this user ID + + + + + Max number of users to return (1-100) + + + + + + + + Represents a Discord Poll Answer Count + + + + + The answer_id + + + + + The number of votes for this answer + + + + + Whether the current user voted for this answer + + + + + Represents a Discord Poll Answers + + + + + The ID of the answer + + + + + The data of the answer + + + + + Represents a Discord Poll Create + + + + + The question of the poll. Only text is supported. + + + + + Each of the answers available in the poll. + + + + + Number of hours the poll should be open for, up to 32 days + + + + + Whether a user can select multiple answers + + + + + The layout type of the poll + + + + + Represents a Discord Poll Layout Type + + + + + The default layout type. + + + + + Represents a Discord Poll Media + + + + + The text of the field + + + + + The emoji of the field + + + + + Represents a Discord Poll Results + + + + + Whether the votes have been precisely counted + + + + + The counts for each answer + + Represents a Reaction Count Details Structure @@ -15111,6 +15871,21 @@ Count of normal reactions + + + Represents a Discord Reaction Type + + + + + Normal Reaction Type + + + + + Burst Reaction Type + + Represents a Create Test Entitlement Structure @@ -15181,17 +15956,31 @@ ID of the guild that is granted access to the entitlement's sku + + + For consumable items, whether the entitlement has been consumed + + Returns all entitlements for a given app, active and expired. + See List Entitlements Client to use Application ID to get entitlement for Query string options for the request + + + For One-Time Purchase consumable SKUs, marks a given entitlement for the user as consumed. + See Consume an Entitlement + + Client to use + Creates a test entitlement to a given SKU for a given guild or user. Discord will act as though that user or guild has entitlement to your premium offering. + See Create Test Entitlement Client to use Create request @@ -15199,27 +15988,63 @@ Deletes a currently-active test entitlement. Discord will act as though that user or guild no longer has entitlement to your premium offering. + See Delete Test Entitlement Client to use - + + + Represents a Entitlement Owner Types + + + + + Subscription is a Guild Subscription + + + + + Subscription is a User Subscription + + + + + Represents a Entitlement Types + + + + + Entitlement was purchased by user + + + + + Entitlement for Discord Nitro subscription + + + + + Entitlement was gifted by developer + + + - Represents a Entitlement Owner Types + Entitlement was purchased by a dev in application test mode - + - Subscription is a Guild Subscription + Entitlement was granted when the SKU was free - + - Subscription is a User Subscription + Entitlement was claimed by user for free as a Nitro Subscriber - + - Represents a Entitlement Types + Entitlement was purchased as an app subscription @@ -15320,6 +16145,16 @@ Represents a Discord SKU Types + + + Durable one-time purchase + + + + + Consumable one-time purchase + + Represents a recurring subscription @@ -15753,7 +16588,17 @@ - Allows members to interact with the Clyde AI bot + Allows sending polls + + + + + Allows sending polls + + + + + Allows user-installed apps to send public responses. When disabled, users will still be allowed to use their apps but the responses will be ephemeral. This only applies to apps not also installed to the server. @@ -15891,6 +16736,14 @@ Snowflake to return True if parse succeeded; false otherwise + + + Try to parse the a string into a snowflake value + + String to parse + Snowflake to return + True if parse succeeded; false otherwise + Try to format the snowflake into the span @@ -16353,6 +17206,21 @@ Read-only members can access information about a team and any team-owned apps. Some examples include getting the IDs of applications and exporting payout records. + + + Represents Avatar Decoration Structure + + + + + The avatar decoration hash + + + + + Id of the avatar decoration's SKU + + Represents a Discord Users Connection @@ -16426,6 +17294,16 @@ Connection type is Battle.net + + + Connection type is Bungie.net + + + + + Connection type is Domain + + Connection type is Epic Games @@ -16473,7 +17351,12 @@ - Connection type is Reddit + Connection type is Riot Games + + + + + Connection type is Roblox @@ -16626,7 +17509,7 @@ - The user's avatar decoration hash + The user's avatar decoration @@ -16958,6 +17841,11 @@ If passed, modifies the user's avatar + + + If passed, modifies the user's banner + + @@ -17191,6 +18079,11 @@ The channel that this webhook is following (returned for Channel Follower Webhooks) + + + Client for the webhook + + Create a new webhook. @@ -17502,7 +18395,7 @@ This Thrown if more than 10 embeds are added in a send as that is the discord limit - + Adds an attachment to the message @@ -17510,6 +18403,7 @@ byte[] of the attachment Attachment content type Description for the attachment + Title of the attachment @@ -17987,6 +18881,11 @@ Thrown when the minimum template version is higher than the current template version + + + Exceptions for the + + An exception when something is invalid with a pool @@ -18055,14 +18954,14 @@ - Send chat message to the user if they're connected + Send a chat message to the user if they're connected User to send the message to on the server Message to send - Send chat message to the user if they're connected + Send a chat message to the user if they're connected User to send the message to on the server Message to send @@ -18072,7 +18971,7 @@ Return if the discord user has the given oxide permission. - If the user is not linked this will return false + If the user is not linked, this will return false User to check for permission Permission to check for @@ -18111,7 +19010,7 @@ - Creates a clone of a hash with it's current key value pairs + Creates a clone of a hash with its current key value pairs Hash to be copied @@ -18131,7 +19030,7 @@ The to pool from Type of the list Pooled List{TSource} - Thrown if source is null + Thrown if the source is null @@ -18144,7 +19043,7 @@ Key type for the hash Value type for the hash Pooled Hash{TKey, TElement} - Thrown if source is null + Thrown if the source is null @@ -18158,7 +19057,7 @@ Key type for the hash Value type for the hash Pooled Hash{TKey, TElement} - Thrown if source is null + Thrown if the source is null @@ -18376,7 +19275,7 @@ - Determine if current thread is main thread + Determine if current thread is the main thread @@ -18417,11 +19316,12 @@ List of active bots by bot API key - + Gets or creates a new bot client for the given discord client Client to use for creating / loading the bot client + Connection for the bot Bot client that is created or already exists @@ -18440,7 +19340,7 @@ - Creates the client for the given plugin. If one already exist the existing one is returned + Creates the client for the given plugin. If one already exists, the existing one is returned Plugin the client is for DiscordClient for plugin @@ -18450,21 +19350,21 @@ Gets the client for the given plugin - Plugin to get client for + Plugin to get the client for Discord client for the plugin Gets the client for the given plugin - Plugin to get client for + Plugin to get the client for Discord client for the plugin Gets the client for the given plugin name - Plugin Name to get client for + Plugin Name to get the client for Discord client for the plugin name @@ -18478,6 +19378,19 @@ + + + List of active bots by bot API key + + + + + Gets or creates a new bot client for the given discord client + + Client to use for creating / loading the bot client + Connection for the webhook + Bot client that is created or already exists + Discord App Routes for navigating the client within the discord app using links @@ -18617,7 +19530,7 @@ ID of the emoji The format the emoji is in Url of the emoji - Thrown if format is Jpg or WebP + Thrown if the format is Jpg or WebP @@ -18636,7 +19549,7 @@ Guild Splash from guild Format the icon is in Url of the guild splash - Thrown if format is Gif + Thrown if the format is GIF @@ -18646,7 +19559,7 @@ Guild Discovery Splash from guild Format the icon is in Url of the guild discovery splash - Thrown if format is Gif + Thrown if the format is GIF @@ -18656,7 +19569,7 @@ Guild Banner from guild Format the icon is in Url of the guild banner - Thrown if format is Gif + Thrown if the format is GIF @@ -18666,7 +19579,7 @@ User Banner from user Format the icon is in Url of the User banner - Thrown if format is Gif + Thrown if the format is GIF @@ -18682,7 +19595,7 @@ Discord User ID User avatar from user Format the avatar is in - Url of the users avatar + Url of the user's avatar @@ -18694,12 +19607,11 @@ Format the avatar is in Url of the Guild Member avatar - + Returns the Url of the User Avatar Decoration - Discord User ID - Guild Member avatar + Avatar Decoration Data Format the avatar is in Url of the Guild Member avatar @@ -18711,7 +19623,7 @@ Icon field from application Format the icon is in Url of the application icon - Throw if format is Gif + Throw if the format is GIF @@ -18721,7 +19633,7 @@ Icon field from application Format the icon is in Url of the application icon - Throw if format is Gif + Throw if the format is GIF @@ -18731,7 +19643,7 @@ Asset ID for the application Format the icon is in Url of the application asset icon - Throw if format is Gif + Throw if the format is GIF @@ -18741,7 +19653,7 @@ Achievement ID Achievement Icon Hash Url of the achievement icon - Throw if format is Gif + Throw if the format is GIF @@ -18751,7 +19663,7 @@ Asset ID Format the icon is in Url of the achievement icon - Throw if format is Gif + Throw if the format is GIF @@ -18761,7 +19673,7 @@ Icon field from Team Format the icon is in Url of the achievement icon - Throw if format is Gif + Throw if the format is GIF @@ -18771,7 +19683,7 @@ Banner Asset ID for the stickers Image Formatting for the banner Url to the sticker pack banner - Thrown if image type is not PNG,JPEG, or WebP + Thrown if the image type is not PNG, JPEG, or WebP @@ -18787,7 +19699,7 @@ ID of the role Format for the icon to be returned in Return url for the role icon - Thrown if image type is not PNG or Lottie + Thrown if the image type is not PNG or Lottie @@ -18796,7 +19708,7 @@ Scheduled Event ID Format for the icon to be returned in Return url for the guild schedule event cover icon - Thrown if image type is not PNG or Lottie + Thrown if the image type is not PNG or Lottie @@ -18806,7 +19718,7 @@ User ID of the user Format for the icon to be returned in Return url for the guild member banner - Thrown if image type is not PNG or Lottie + Thrown if the image type is not PNG or Lottie @@ -18839,21 +19751,21 @@ - Mention the the channel with the given ID + Mention the channel with the given ID Channel ID to mention Mention channel formatted string - Mention the the role with the given ID + Mention the role with the given ID Role ID to mention Mention role formatted string - Mention the the Application command + Mention the Application command Application Command ID Name of the command @@ -18975,7 +19887,7 @@ - Will display the message as a one line code block + Will display the message as a one-line code block Message to make code block Code block formatted message @@ -19356,7 +20268,7 @@ - Id of the entity + ID of the entity @@ -19390,7 +20302,7 @@ Validates data being passed to the discord API. - Throws an exception with base type of if the validation fails + Throws an exception with a base type of if the validation fails @@ -19690,6 +20602,18 @@ The state of the returning promise will be based on the new value promise, not the preceding (rejected or resolved) promise. + + + returns the task for this promise + + + + + + returns the task awaiter for this promise + + + Implements a C# promise. @@ -19792,6 +20716,18 @@ The state of the returning promise will be based on the new value promise, not the preceding (rejected or resolved) promise. + + + returns the task for this promise + + + + + + returns the task awaiter for this promise + + + Interface for a promise that can be rejected. @@ -19878,12 +20814,12 @@ - Check if can convert + Check if it can convert - Handles deserializing JSON values as strings. If the value doesn't exist return the default value. + Handles deserializing JSON values as strings. If the value doesn't exist, return the default value. @@ -20012,7 +20948,7 @@ - Converter for list of message components + Converter for a list of message components @@ -20116,7 +21052,7 @@ - Converts a snowflake to and from it's JSON string value + Converts a snowflake to and from its JSON string value @@ -20147,7 +21083,7 @@ - Converter for list of message components + Converter for a list of message components @@ -20184,7 +21120,7 @@ - Json Template Key Converter + JSON Template Key Converter @@ -20405,7 +21341,7 @@ Sub Command for the command Thrown if command is null or empty - + @@ -20424,12 +21360,17 @@ Constructor - + + + Called on the library when a plugin is loaded + + Client for the loaded plugin + + Called on the library when a plugin is loaded - Plugin that was loaded - Connection for the plugin + Client for the connecting bot @@ -20522,7 +21463,7 @@ Lang Key on the plugin that contains the command Plugin to add the localized command for - Channel or Category Id's this command is allowed in + Channel or Category ID's this command is allowed in Method name of the callback @@ -20532,7 +21473,7 @@ Name of the command Plugin to add the localized command for - Channel or Category Id's this command is allowed in + Channel or Category ID's this command is allowed in Method name of the callback @@ -20572,7 +21513,7 @@ - + @@ -20682,14 +21623,14 @@ Returns the Player ID of the given Discord ID if there is a link Discord ID to get player ID for - Player ID of the given given discord ID if linked; null otherwise + Player ID of the given discord ID if linked; null otherwise Returns the Player ID of the given Discord ID if there is a link - to get player Id for - Player ID of the given given discord ID if linked; null otherwise + to get player ID for + Player ID of the given discord ID if linked; null otherwise @@ -20774,7 +21715,7 @@ - Called by a link plugin when an unlink occured + Called by a link plugin when an unlink has occured Plugin that is unlinking Player being unlinked @@ -20828,15 +21769,6 @@ IPlayer for the ID Thrown if the IPlayer is null - - - - - - - - - Represents a Locale in Discord @@ -20865,31 +21797,6 @@ Locale to Parse Parsed Discord Locale - - - - - - - - - - - - Returns if two Discord Locales are equal to each other - - - - - - - - Returns if two Discord Locales are not equal to each other - - - - - Returns the ID of the Locale @@ -21043,31 +21950,6 @@ - - - - - - - - - - - - Returns if two Server Locales are equal to each other - - - - - - - - Returns if two Server Locales are not equal to each other - - - - - Returns the ID of the ServerLocale @@ -21850,7 +22732,7 @@ Text to process placeholders for Placeholder Data for the placeholders - string with placeholders replaced. If no placeholders are found the original string is returned + String with placeholders replaced. If no placeholders are found, the original string is returned @@ -23009,7 +23891,7 @@ - Adds a IP + Adds an IP @@ -23088,15 +23970,6 @@ Value of the key - - - - - - - - - Formatting Helpers for Placeholders @@ -23104,7 +23977,7 @@ - Replace the with the the string value + Replace the with the string value for the placeholder for the placeholder @@ -23188,15 +24061,6 @@ - - - - - - - - - @@ -23260,7 +24124,7 @@ Thrown if the plugin is null - + @@ -24508,31 +25372,6 @@ Placeholder Value - - - - - - - - - - - - Template Key == operator - - - - - - - - Template Key != operator - - - - - Returns the template name @@ -24624,34 +25463,9 @@ Minor Version Revision Version - - - - - - - - - - - - Returns if the template versions are equal - - - - - - - - Returns if the template versions are not equal - - - - - Returns if the left template version is less than the right @@ -24996,27 +25810,27 @@ - Debug log level display all messages up to and include Debug + Debug log level display all messages up to and including Debug - Info log level display all messages up to and include Info + Info log level display all messages up to and including Info - Warning log level display all messages up to and include Warning + Warning log level display all messages up to and including Warning - Error log level display all messages up to and include Error + Error log level display all messages up to and including Error - Exception log level display all messages up to and include Exception + Exception log level display all messages up to and including Exception @@ -25039,31 +25853,6 @@ Returns if the PluginId is valid - - - - - - - - - - - - - - - - - - - - - - - - - Returns the PluginName @@ -25114,7 +25903,7 @@ Creates a new bucket for the given - ID of the bucket. If not a known bucket then will be part of the route. If know bucket will be the Discord bucket ID + ID of the bucket. If not a known bucket, then it will be part of the route. If known bucket, it will be the Discord bucket ID The handler that owns this Bucket Logger for this bucket @@ -25155,34 +25944,9 @@ ID of the bucket Thrown if ID is null or empty - - - - - - - - - - - - - - - - - - - - - - - - - Represents a base request class for REST API calls @@ -25309,7 +26073,7 @@ - The request was cancelled. The was disconnected while making the request + The request was canceled. The was disconnected while making the request @@ -25403,12 +26167,12 @@ - Request completed and was not cancelled + Request completed and was not canceled - Request was cancelled + Request was canceled @@ -25470,6 +26234,12 @@ Route to Bucket ID + + + Creates a new REST handler for bot / webhook clients + + + Creates a new REST handler for a bot client @@ -25479,7 +26249,7 @@ - Performs a HTTP Get Request with TResult response + Performs ann HTTP Get Request with TResult response Client for the request Url for the request @@ -25497,7 +26267,7 @@ - Performs a HTTP Post Request with TResult response + Performs an HTTP Post Request with TResult response Client for the request Url for the request @@ -25507,7 +26277,7 @@ - Performs a HTTP Put Request + Performs an HTTP Put Request Client for the request Url for the request @@ -25516,7 +26286,7 @@ - Performs a HTTP Put Request with TResult response + Performs an HTTP Put Request with TResult response Client for the request Url for the request @@ -25526,7 +26296,7 @@ - Performs a HTTP Patch Request + Performs an HTTP Patch Request Client for the request Url for the request @@ -25535,7 +26305,7 @@ - Performs a HTTP Patch Request with TResult response + Performs an HTTP Patch Request with TResult response Client for the request Url for the request @@ -25553,7 +26323,7 @@ - Performs a HTTP Delete Request with TResult response + Performs an HTTP Delete Request with TResult response Client for the request Url for the request @@ -25562,7 +26332,7 @@ - Creates a new request and queues it to be ran + Creates a new request and queues it to be run Client making the request URL of the request @@ -25572,7 +26342,7 @@ - Creates a new request and queues it to be ran + Creates a new request and queues it to be run Client making the request URL of the request @@ -25689,7 +26459,7 @@ - Creates new type of T + Creates a new type of T Newly created type of T @@ -25723,7 +26493,7 @@ Returns if an item can be freed to the pool Item to be freed - True if can be freed; false otherwise + True if the item can be freed; false otherwise @@ -25934,7 +26704,7 @@ - Returns the pooled type back to the pool + Returns the pooled type to the pool @@ -26126,7 +26896,7 @@ - Implements a non-generic C# promise, this is a promise that simply resolves without delivering a value. + Implements a non-generic C# promise; this is a promise that simply resolves without delivering a value. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise @@ -26159,7 +26929,7 @@ - Helper function clear out all handlers after resolution or rejection. + Helper function to clear out all handlers after resolution or rejection. @@ -26170,6 +26940,9 @@ + + + @@ -26244,6 +27017,12 @@ + + + + + + @@ -26314,6 +27093,9 @@ + + + Invoke all resolve handlers. @@ -26362,7 +27144,7 @@ - Returns a promise that resolves when all of the promises in the enumerable argument have resolved. + Returns a promise that resolves when all the promises in the enumerable argument have resolved. Returns a promise of a collection of the resolved results. @@ -26381,6 +27163,12 @@ + + + + + + @@ -26666,6 +27454,39 @@ Key for the record Value of the record + + + Get a pinnable reference to the builder. + Does not ensure there is a null char after + This overload is pattern matched in the C# 7.3+ compiler so you can omit + the explicit method call, and write eg "fixed (char* c = builder)" + + + + + Get a pinnable reference to the builder. + + Ensures that the builder has a null char after + + + Returns the underlying storage of the builder. + + + + Returns a span around the contents of the builder. + + Ensures that the builder has a null char after + + + + Resize the internal buffer either by doubling current buffer size or + by adding to + whichever is greater. + + + Number of chars requested beyond current position. + + Represents a websocket that connects to discord @@ -26860,7 +27681,7 @@ - The session would have handled too many guilds - you are required to shard your connection in order to connect. + The session would have handled too many guilds - you are required to shard your connection to connect. @@ -26875,7 +27696,7 @@ - You sent a disallowed intent for a Gateway Intent. You may have tried to specify an intent that you have not enabled or are not whitelisted for. + You sent a disallowed intent for a Gateway Intent. You may have tried to specify an intent that you have not enabled or are not allowlisted for. @@ -27218,6 +28039,16 @@ Represents the AUTO_MODERATION_ACTION_EXECUTION gateway event + + + Represents the MESSAGE_POLL_VOTE_ADD gateway event + + + + + Represents the MESSAGE_POLL_VOTE_REMOVE gateway event + + Handles the heartbeating for the websocket connection @@ -27250,7 +28081,7 @@ Sends a heartbeat to discord. - If the previous heartbeat wasn't acknowledged then we will attempt to reconnect + If the previous heartbeat wasn't acknowledged, then we will attempt to reconnect @@ -27320,7 +28151,7 @@ Called when a socket receives a message ID of the web socket - Json Reader containing the message + JSON Reader containing the message @@ -27377,7 +28208,7 @@ Disconnects from the websocket with the given code and reason - Client for the websockk + Client for the websocket Status to close with Reason for the close If we received a close from the websocket @@ -27423,12 +28254,12 @@ - Socket is in the process of connecting + Websocket is in the process of connecting - Socket is connect and functioning normally + Websocket is connected and functioning normally diff --git a/Oxide.Ext.Discord/Plugins/BaseDiscordPlugin.cs b/Oxide.Ext.Discord/Plugins/BaseDiscordPlugin.cs index 058c8eca7..5ce4c7787 100644 --- a/Oxide.Ext.Discord/Plugins/BaseDiscordPlugin.cs +++ b/Oxide.Ext.Discord/Plugins/BaseDiscordPlugin.cs @@ -5,47 +5,46 @@ using Oxide.Core.Plugins; using Oxide.Ext.Discord.Cache; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal class BaseDiscordPlugin : CSPlugin { - internal class BaseDiscordPlugin : CSPlugin - { - protected readonly Covalence Covalence = OxideLibrary.Instance.Covalence; - protected readonly Lang Lang = OxideLibrary.Instance.Lang; - protected readonly Oxide.Core.Libraries.Plugins Plugins = OxideLibrary.Instance.Plugins; - protected readonly Permission Permission = OxideLibrary.Instance.Permission; - //internal readonly PluginTimers Timer; + protected readonly Covalence Covalence = OxideLibrary.Instance.Covalence; + protected readonly Lang Lang = OxideLibrary.Instance.Lang; + protected readonly Oxide.Core.Libraries.Plugins Plugins = OxideLibrary.Instance.Plugins; + protected readonly Permission Permission = OxideLibrary.Instance.Permission; + //internal readonly PluginTimers Timer; - protected BaseDiscordPlugin() - { - Author = DiscordExtension.Authors; - Version = DiscordExtension.ExtensionVersion; - //Timer = new PluginTimers(this); - } + protected BaseDiscordPlugin() + { + Author = DiscordExtension.Authors; + Version = DiscordExtension.ExtensionVersion; + //Timer = new PluginTimers(this); + } - #region Helper Methods - protected void Chat(IPlayer player, string key) => player.Reply(GetLang(LangKeys.Chat, player, player.IsServer ? Formatter.ToPlaintext(GetLang(key, player)) : GetLang(key, player))); - protected void Chat(IPlayer player, string key, params object[] args) => player.Reply(GetLang(LangKeys.Chat, player, player.IsServer ? Formatter.ToPlaintext(GetLang(key, player, args)) : GetLang(key, player, args))); + #region Helper Methods + protected void Chat(IPlayer player, string key) => player.Reply(GetLang(LangKeys.Chat, player, player.IsServer ? Formatter.ToPlaintext(GetLang(key, player)) : GetLang(key, player))); + protected void Chat(IPlayer player, string key, params object[] args) => player.Reply(GetLang(LangKeys.Chat, player, player.IsServer ? Formatter.ToPlaintext(GetLang(key, player, args)) : GetLang(key, player, args))); - protected string GetLang(string key, IPlayer player = null) => Lang.GetMessage(key, this, player?.Id); + protected string GetLang(string key, IPlayer player = null) => Lang.GetMessage(key, this, player?.Id); - protected string GetLang(string key, IPlayer player = null, params object[] args) + protected string GetLang(string key, IPlayer player = null, params object[] args) + { + try + { + return string.Format(GetLang(key, player), args); + } + catch(Exception ex) { - try - { - return string.Format(GetLang(key, player), args); - } - catch(Exception ex) - { - PrintError($"Lang Key '{key}' threw exception\n:{ex.Message}"); - throw; - } + PrintError($"Lang Key '{key}' threw exception\n:{ex.Message}"); + throw; } + } - protected void Puts(string format, params object[] args) => Interface.Oxide.LogInfo("[{0}] {1}", Title, args.Length != 0 ? string.Format(format, args) : (object) format); + protected void Puts(string format, params object[] args) => Interface.Oxide.LogInfo("[{0}] {1}", Title, args.Length != 0 ? string.Format(format, args) : (object) format); - protected void PrintWarning(string format, params object[] args) => Interface.Oxide.LogWarning("[{0}] {1}", Title, args.Length != 0 ? string.Format(format, args) : (object) format); + protected void PrintWarning(string format, params object[] args) => Interface.Oxide.LogWarning("[{0}] {1}", Title, args.Length != 0 ? string.Format(format, args) : (object) format); - protected void PrintError(string format, params object[] args) => Interface.Oxide.LogError("[{0}] {1}", Title, args.Length != 0 ? string.Format(format, args) : (object) format); - #endregion - } + protected void PrintError(string format, params object[] args) => Interface.Oxide.LogError("[{0}] {1}", Title, args.Length != 0 ? string.Format(format, args) : (object) format); + #endregion } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Core/AppCommands/AppCommandKeys.cs b/Oxide.Ext.Discord/Plugins/Core/AppCommands/AppCommandKeys.cs index d1cb50029..1b317210e 100644 --- a/Oxide.Ext.Discord/Plugins/Core/AppCommands/AppCommandKeys.cs +++ b/Oxide.Ext.Discord/Plugins/Core/AppCommands/AppCommandKeys.cs @@ -1,11 +1,10 @@ -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal static class AppCommandKeys { - internal static class AppCommandKeys - { - public const string DeCommand = "de"; + public const string DeCommand = "de"; - public const string AppCommandGroup = "commands"; - public const string DeleteAppCommand = "delete"; - public const string DeleteAppCommandArgument = "command"; - } + public const string AppCommandGroup = "commands"; + public const string DeleteAppCommand = "delete"; + public const string DeleteAppCommandArgument = "command"; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Core/AppCommands/CommandCache.cs b/Oxide.Ext.Discord/Plugins/Core/AppCommands/CommandCache.cs index 4622ff83c..ae0a251fb 100644 --- a/Oxide.Ext.Discord/Plugins/Core/AppCommands/CommandCache.cs +++ b/Oxide.Ext.Discord/Plugins/Core/AppCommands/CommandCache.cs @@ -2,30 +2,29 @@ using System.Collections.Generic; using Oxide.Ext.Discord.Entities; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal class CommandCache { - internal class CommandCache - { - public readonly List Commands; - private readonly DateTime _cachedDateTime = DateTime.UtcNow; + public readonly List Commands; + private readonly DateTime _cachedDateTime = DateTime.UtcNow; - public CommandCache(List commands) - { - Commands = commands; - } + public CommandCache(List commands) + { + Commands = commands; + } - public bool IsExpired => _cachedDateTime + TimeSpan.FromSeconds(15) < DateTime.UtcNow; + public bool IsExpired => _cachedDateTime + TimeSpan.FromSeconds(15) < DateTime.UtcNow; - public void RemoveCommand(Snowflake id) + public void RemoveCommand(Snowflake id) + { + for (int index = 0; index < Commands.Count; index++) { - for (int index = 0; index < Commands.Count; index++) + DiscordApplicationCommand command = Commands[index]; + if (command.Id == id) { - DiscordApplicationCommand command = Commands[index]; - if (command.Id == id) - { - Commands.RemoveAt(index); - break; - } + Commands.RemoveAt(index); + break; } } } diff --git a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.AppCommands.cs b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.AppCommands.cs index 9dfd80763..dfa00965a 100644 --- a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.AppCommands.cs +++ b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.AppCommands.cs @@ -11,172 +11,171 @@ using Oxide.Ext.Discord.Logging; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal partial class DiscordExtensionCore { - internal partial class DiscordExtensionCore + private readonly Hash _commandCache = new(); + private CommandCreate _create; + private PluginSetup _setup; + + private void RegisterApplicationCommands() { - private readonly Hash _commandCache = new Hash(); - private CommandCreate _create; - private PluginSetup _setup; + _setup = new PluginSetup(this, DiscordExtension.GlobalLogger); + ApplicationCommandBuilder builder = new ApplicationCommandBuilder(AppCommandKeys.DeCommand, "Discord Extension Commands", ApplicationCommandType.ChatInput) + .AddDefaultPermissions(PermissionFlags.Administrator) + .AddSubCommandGroup(AppCommandKeys.AppCommandGroup, "Application Commands", + group => group.AddSubCommand(AppCommandKeys.DeleteAppCommand, "Delete a registered application command", + sub => sub.AddOption(CommandOptionType.String, AppCommandKeys.DeleteAppCommandArgument, "Application Command To Delete", + options => options.AutoComplete().Required()))); + builder.AllowInDirectMessages(false); - private void RegisterApplicationCommands() + CommandCreate create = builder.Build(); + DiscordCommandLocalization localization = builder.BuildCommandLocalization(); + TemplateKey template = new(nameof(DiscordExtension)); + DiscordExtension.DiscordCommandLocalizations.RegisterCommandLocalizationAsync(this, template, localization, new TemplateVersion(1, 0, 0), new TemplateVersion(1, 0, 0)).Then(_ => { - _setup = new PluginSetup(this, DiscordExtension.GlobalLogger); - ApplicationCommandBuilder builder = new ApplicationCommandBuilder(AppCommandKeys.DeCommand, "Discord Extension Commands", ApplicationCommandType.ChatInput) - .AddDefaultPermissions(PermissionFlags.Administrator) - .AddSubCommandGroup(AppCommandKeys.AppCommandGroup, "Application Commands", - group => group.AddSubCommand(AppCommandKeys.DeleteAppCommand, "Delete a registered application command", - sub => sub.AddOption(CommandOptionType.String, AppCommandKeys.DeleteAppCommandArgument, "Application Command To Delete", - options => options.AutoComplete().Required()))); - builder.AllowInDirectMessages(false); - - CommandCreate create = builder.Build(); - DiscordCommandLocalization localization = builder.BuildCommandLocalization(); - TemplateKey template = new TemplateKey(nameof(DiscordExtension)); - DiscordExtension.DiscordCommandLocalizations.RegisterCommandLocalizationAsync(this, template, localization, new TemplateVersion(1, 0, 0), new TemplateVersion(1, 0, 0)).Then(_ => + DiscordExtension.DiscordCommandLocalizations.ApplyCommandLocalizationsAsync(this, create, template).Then(() => { - DiscordExtension.DiscordCommandLocalizations.ApplyCommandLocalizationsAsync(this, create, template).Then(() => + _create = create; + foreach (BotClient client in BotClientFactory.Instance.Clients.ToList()) { - _create = create; - foreach (BotClient client in BotClientFactory.Instance.Clients.ToList()) - { - ApplyApplicationCommands(client); - } - }); + ApplyApplicationCommands(client); + } }); - } + }); + } - public void ApplyApplicationCommands(BotClient client) + public void ApplyApplicationCommands(BotClient client) + { + _logger.Verbose($"{nameof(DiscordExtensionCore)}.{nameof(ApplyApplicationCommands)} Create Exists: {{0}} Client Is Ready: {{1}}", _create != null, client.IsReady); + if (_create != null && client.IsReady) { - _logger.Verbose($"{nameof(DiscordExtensionCore)}.{nameof(ApplyApplicationCommands)} Create Exists: {{0}} Client Is Ready: {{1}}", _create != null, client.IsReady); - if (_create != null && client.IsReady) - { - client.Application.CreateGlobalCommand(client.GetFirstClient(), _create); - DiscordAppCommand.Instance.RegisterApplicationCommands(_setup, client.Connection); - } + client.Application.CreateGlobalCommand(client.GetFirstClient(), _create); + DiscordAppCommand.Instance.RegisterApplicationCommands(this, _setup, client.Connection); } + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(HandleDeleteApplicationCommand))] - [DiscordApplicationCommand(AppCommandKeys.DeCommand, AppCommandKeys.DeleteAppCommand, AppCommandKeys.AppCommandGroup)] - private void HandleDeleteApplicationCommand(DiscordInteraction interaction, InteractionDataParsed parsed) + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(HandleDeleteApplicationCommand))] + [DiscordApplicationCommand(AppCommandKeys.DeCommand, AppCommandKeys.DeleteAppCommand, AppCommandKeys.AppCommandGroup)] + private void HandleDeleteApplicationCommand(DiscordInteraction interaction, InteractionDataParsed parsed) + { + DiscordClient client = BotClientFactory.Instance.GetByApplicationId(interaction.ApplicationId)?.GetFirstClient(); + if (client == null) { - DiscordClient client = BotClientFactory.Instance.GetByApplicationId(interaction.ApplicationId)?.GetFirstClient(); - if (client == null) - { - return; - } + return; + } - string argString = parsed.Args.GetString(AppCommandKeys.DeleteAppCommandArgument); - string[] args = argString.Split(':'); + string argString = parsed.Args.GetString(AppCommandKeys.DeleteAppCommandArgument); + string[] args = argString.Split(':'); - if (!Snowflake.TryParse(args.Length == 1 ? args[0] : args[1], out Snowflake commandId)) - { - SendTemplateMessage(client, TemplateKeys.Commands.Delete.Errors.InvalidSelection, interaction); - return; - } + if (!Snowflake.TryParse(args.Length == 1 ? args[0] : args[1], out Snowflake commandId)) + { + SendTemplateMessage(client, TemplateKeys.Commands.Delete.Errors.InvalidSelection, interaction); + return; + } - Snowflake guildId = default(Snowflake); - if (args.Length == 2 && !Snowflake.TryParse(args[0], out guildId)) - { - SendTemplateMessage(client, TemplateKeys.Commands.Delete.Errors.InvalidSelection, interaction); - return; - } - - if (guildId.IsValid()) - { - client.Bot.Application.GetGuildCommand(client, guildId, commandId) - .Then(command => DeleteGetSuccess(client, interaction, command)) - .Catch(ex => DeleteGetError(client, interaction, ex)); - } - else - { - client.Bot.Application.GetGlobalCommand(client, commandId) - .Then(command => DeleteGetSuccess(client, interaction, command)) - .Catch(ex => DeleteGetError(client, interaction, ex)); - } + Snowflake guildId = default; + if (args.Length == 2 && !Snowflake.TryParse(args[0], out guildId)) + { + SendTemplateMessage(client, TemplateKeys.Commands.Delete.Errors.InvalidSelection, interaction); + return; } - public void DeleteGetSuccess(DiscordClient client, DiscordInteraction interaction, DiscordApplicationCommand command) + if (guildId.IsValid()) { - command.Delete(client).Then(() => - { - SendTemplateMessage(client, TemplateKeys.Commands.Delete.Success, interaction, GetPlaceholderData().AddCommand(command)); - _commandCache[interaction.ApplicationId]?.RemoveCommand(command.Id); - }).Catch(error => - { - SendTemplateMessage(client, TemplateKeys.Commands.Delete.Errors.DeleteCommandError, interaction, GetPlaceholderData().AddCommand(command)); - }); + client.Bot.Application.GetGuildCommand(client, guildId, commandId) + .Then(command => DeleteGetSuccess(client, interaction, command)) + .Catch(ex => DeleteGetError(client, interaction, ex)); } - - public void DeleteGetError(DiscordClient client, DiscordInteraction interaction, ResponseError error) + else { - SendTemplateMessage(client, TemplateKeys.Commands.Delete.Success, interaction, GetPlaceholderData().AddRequestError(error)); + client.Bot.Application.GetGlobalCommand(client, commandId) + .Then(command => DeleteGetSuccess(client, interaction, command)) + .Catch(ex => DeleteGetError(client, interaction, ex)); } + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(HandleDeleteApplicationAutoComplete))] - [DiscordAutoCompleteCommand(AppCommandKeys.DeCommand, AppCommandKeys.DeleteAppCommandArgument, AppCommandKeys.DeleteAppCommand, AppCommandKeys.AppCommandGroup)] - private void HandleDeleteApplicationAutoComplete(DiscordInteraction interaction, InteractionDataOption focused) + private void DeleteGetSuccess(DiscordClient client, DiscordInteraction interaction, DiscordApplicationCommand command) + { + command.Delete(client).Then(() => { - string search = focused.GetString(); - CommandCache cache = _commandCache[interaction.ApplicationId]; - InteractionAutoCompleteBuilder builder = new InteractionAutoCompleteBuilder(interaction); - BotClient client = BotClientFactory.Instance.GetByApplicationId(interaction.ApplicationId); - if (client == null) - { - return; - } - - if (cache != null && !cache.IsExpired) - { - AddCommands(builder, search, cache.Commands); - interaction.CreateResponse(client.GetFirstClient(), builder.Build()); - return; - } + SendTemplateMessage(client, TemplateKeys.Commands.Delete.Success, interaction, GetPlaceholderData().AddCommand(command)); + _commandCache[interaction.ApplicationId]?.RemoveCommand(command.Id); + }).Catch(error => + { + SendTemplateMessage(client, TemplateKeys.Commands.Delete.Errors.DeleteCommandError, interaction, GetPlaceholderData().AddCommand(command).AddRequestError(error)); + }); + } - CacheCommands(client, commandCache => - { - AddCommands(builder, search, commandCache.Commands); - interaction.CreateResponse(client.GetFirstClient(), builder.Build()); - }); + private void DeleteGetError(DiscordClient client, DiscordInteraction interaction, ResponseError error) + { + SendTemplateMessage(client, TemplateKeys.Commands.Delete.Success, interaction, GetPlaceholderData().AddRequestError(error)); + } + + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(HandleDeleteApplicationAutoComplete))] + [DiscordAutoCompleteCommand(AppCommandKeys.DeCommand, AppCommandKeys.DeleteAppCommandArgument, AppCommandKeys.DeleteAppCommand, AppCommandKeys.AppCommandGroup)] + private void HandleDeleteApplicationAutoComplete(DiscordInteraction interaction, InteractionDataOption focused) + { + string search = focused.GetString(); + CommandCache cache = _commandCache[interaction.ApplicationId]; + InteractionAutoCompleteBuilder builder = new(interaction); + BotClient client = BotClientFactory.Instance.GetByApplicationId(interaction.ApplicationId); + if (client == null) + { + return; } + + if (cache is {IsExpired: false}) + { + AddCommands(builder, search, cache.Commands); + interaction.CreateResponse(client.GetFirstClient(), builder.Build()); + return; + } + + CacheCommands(client, commandCache => + { + AddCommands(builder, search, commandCache.Commands); + interaction.CreateResponse(client.GetFirstClient(), builder.Build()); + }); + } - private static void AddCommands(InteractionAutoCompleteBuilder builder, string search, List commands) + private static void AddCommands(InteractionAutoCompleteBuilder builder, string search, List commands) + { + for (int index = 0; index < commands.Count && builder.CanAddChoice(); index++) { - for (int index = 0; index < commands.Count && builder.CanAddChoice(); index++) + DiscordApplicationCommand command = commands[index]; + if (!string.IsNullOrEmpty(search) && command.Name.IndexOf(search, StringComparison.OrdinalIgnoreCase) == -1) { - DiscordApplicationCommand command = commands[index]; - if (!string.IsNullOrEmpty(search) && command.Name.IndexOf(search, StringComparison.OrdinalIgnoreCase) == -1) - { - continue; - } + continue; + } - if (command.GuildId.HasValue && command.GuildId.Value.IsValid()) - { - builder.AddChoice($"[Guild] {command.Name}", $"{command.GuildId.Value}:{command.Id}"); - } - else - { - builder.AddChoice($"[Global] {command.Name}", command.Id.ToString()); - } + if (command.GuildId.HasValue && command.GuildId.Value.IsValid()) + { + builder.AddChoice($"[Guild] {command.Name}", $"{command.GuildId.Value}:{command.Id}"); + } + else + { + builder.AddChoice($"[Global] {command.Name}", command.Id.ToString()); } } + } - private void CacheCommands(BotClient bot, Action callback) - { - bot.Application.GetAllCommands(bot.GetFirstClient()) - .Then(commands => - { - CommandCache cache = new CommandCache(commands); - _commandCache[bot.Application.Id] = cache; - callback.Invoke(cache); - }); - } + private void CacheCommands(BotClient bot, Action callback) + { + bot.Application.GetAllCommands(bot.GetFirstClient()) + .Then(commands => + { + CommandCache cache = new(commands); + _commandCache[bot.Application.Id] = cache; + callback.Invoke(cache); + }); + } - private PlaceholderData GetPlaceholderData() - { - return DiscordPlaceholders.Instance.CreateData(this); - } + private PlaceholderData GetPlaceholderData() + { + return DiscordPlaceholders.Instance.CreateData(this); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.Helpers.cs b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.Helpers.cs index ceea0a4ea..4c35a0219 100644 --- a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.Helpers.cs +++ b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.Helpers.cs @@ -1,9 +1,8 @@ using Oxide.Core.Plugins; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal partial class DiscordExtensionCore { - internal partial class DiscordExtensionCore - { - private static bool IsPluginLoaded(Plugin plugin) => plugin != null && plugin.IsLoaded; - } + private static bool IsPluginLoaded(Plugin plugin) => plugin != null && plugin.IsLoaded; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.ImageLibrary.cs b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.ImageLibrary.cs index ccbbc376f..965d9e788 100644 --- a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.ImageLibrary.cs +++ b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.ImageLibrary.cs @@ -1,17 +1,16 @@ using Oxide.Core.Plugins; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal partial class DiscordExtensionCore { - internal partial class DiscordExtensionCore - { - [PluginReference] + [PluginReference] #pragma warning disable CS0649 - public Plugin ImageLibrary; + public Plugin ImageLibrary; #pragma warning restore CS0649 - public string GetPlayerAvatarUrl(string playerId) => IsPluginLoaded(ImageLibrary) ? ImageLibrary.Call("GetImageURL", playerId, 0ul) : string.Empty; + public string GetPlayerAvatarUrl(string playerId) => IsPluginLoaded(ImageLibrary) ? ImageLibrary.Call("GetImageURL", playerId, 0ul) : string.Empty; - public string GetImageUrl(string imageName, ulong imageId) => IsPluginLoaded(ImageLibrary) ? ImageLibrary.Call("GetImageURL", imageName, imageId) : string.Empty; - } + public string GetImageUrl(string imageName, ulong imageId) => IsPluginLoaded(ImageLibrary) ? ImageLibrary.Call("GetImageURL", imageName, imageId) : string.Empty; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.PlaceholderApi.cs b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.PlaceholderApi.cs index c8493c04e..d8cb44286 100644 --- a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.PlaceholderApi.cs +++ b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.PlaceholderApi.cs @@ -3,17 +3,16 @@ using Oxide.Core.Libraries.Covalence; using Oxide.Core.Plugins; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal partial class DiscordExtensionCore { - internal partial class DiscordExtensionCore - { - private Action _replacer; + private Action _replacer; - public Action GetReplacer() => _replacer; + public Action GetReplacer() => _replacer; - private void HandlePlaceholderApi(Plugin plugin) - { - _replacer = plugin?.Call("GetProcessPlaceholders", 1) as Action; - } + private void HandlePlaceholderApi(Plugin plugin) + { + _replacer = plugin?.Call("GetProcessPlaceholders", 1) as Action; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.PlayerName.cs b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.PlayerName.cs index 40d9f24bf..29b33a9d0 100644 --- a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.PlayerName.cs +++ b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.PlayerName.cs @@ -1,120 +1,117 @@ using System.Collections.Generic; -using System.Text; using Oxide.Core.Libraries.Covalence; using Oxide.Core.Plugins; using Oxide.Ext.Discord.Builders; -using Oxide.Ext.Discord.Libraries; +using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal partial class DiscordExtensionCore { - internal partial class DiscordExtensionCore - { - private Plugin _clans; - private readonly Hash> _playerNameCache = new Hash>(); + private Plugin _clans; + private readonly Hash> _playerNameCache = new(); - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnClanCreate))] - private void OnClanCreate() - { - ClearClanCache(); - } + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnClanCreate))] + private void OnClanCreate() + { + ClearClanCache(); + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnClanUpdate))] - private void OnClanUpdate() - { - ClearClanCache(); - } + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnClanUpdate))] + private void OnClanUpdate() + { + ClearClanCache(); + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnClanDestroy))] - private void OnClanDestroy() - { - ClearClanCache(); - } + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnClanDestroy))] + private void OnClanDestroy() + { + ClearClanCache(); + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnUserNameUpdated))] - private void OnUserNameUpdated(string playerId, string oldName, string newName) + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnUserNameUpdated))] + private void OnUserNameUpdated(string playerId, string oldName, string newName) + { + if (oldName != newName) { - if (oldName != newName) + foreach (KeyValuePair> cache in _playerNameCache) { - foreach (KeyValuePair> cache in _playerNameCache) - { - cache.Value.Remove(playerId); - } + cache.Value.Remove(playerId); } } + } - private void ClearClanCache() + private void ClearClanCache() + { + foreach (KeyValuePair> cache in _playerNameCache) { - foreach (KeyValuePair> cache in _playerNameCache) + if (HasFlag(cache.Key, PlayerDisplayNameMode.Clan)) { - if (HasFlag(cache.Key, PlayerDisplayNameMode.Clan)) - { - cache.Value.Clear(); - } + cache.Value.Clear(); } } + } - internal string GetClanTag(IPlayer player) + internal string GetClanTag(IPlayer player) + { + if (!IsPluginLoaded(_clans)) { - if (!IsPluginLoaded(_clans)) - { - return string.Empty; - } - - string tag = _clans.Call("GetClanOf", player.Id); - return !string.IsNullOrEmpty(tag) ? tag : string.Empty; + return string.Empty; } + + string tag = _clans.Call("GetClanOf", player.Id); + return !string.IsNullOrEmpty(tag) ? tag : string.Empty; + } - public string GetPlayerName(IPlayer player, PlayerDisplayNameMode options) + public string GetPlayerName(IPlayer player, PlayerDisplayNameMode options) + { + Hash cache = _playerNameCache[options]; + if (cache == null) { - Hash cache = _playerNameCache[options]; - if (cache == null) - { - cache = new Hash(); - _playerNameCache[options] = cache; - } + cache = new Hash(); + _playerNameCache[options] = cache; + } - string name = cache[player.Id]; - if (!string.IsNullOrEmpty(name)) - { - return name; - } - - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); + string name = cache[player.Id]; + if (!string.IsNullOrEmpty(name)) + { + return name; + } - sb.Clear(); - if (_clans != null && _clans.IsLoaded && HasFlag(options, PlayerDisplayNameMode.Clan)) + ValueStringBuilder sb = new(); + + if (_clans is {IsLoaded: true} && HasFlag(options, PlayerDisplayNameMode.Clan)) + { + string clan = _clans.Call("GetClanOf", player.Id); + if (!string.IsNullOrEmpty(clan)) { - string clan = _clans.Call("GetClanOf", player.Id); - if (!string.IsNullOrEmpty(clan)) - { - sb.Append('['); - sb.Append(clan); - sb.Append("] "); - } + sb.Append('['); + sb.Append(clan); + sb.Append("] "); } + } - sb.Append(player.Name); - - if (HasFlag(options, PlayerDisplayNameMode.PlayerId)) - { - sb.Append(" ("); - sb.Append(player.Id); - sb.Append(')'); - } + sb.Append(player.Name); - name = DiscordPool.Internal.ToStringAndFree(sb); - cache[player.Id] = name; - return name; - } - - private bool HasFlag(PlayerDisplayNameMode options, PlayerDisplayNameMode flag) + if (HasFlag(options, PlayerDisplayNameMode.PlayerId)) { - return (options & flag) == flag; + sb.Append(" ("); + sb.Append(player.Id); + sb.Append(')'); } + + name = sb.ToString(); + cache[player.Id] = name; + return name; + } + + private bool HasFlag(PlayerDisplayNameMode options, PlayerDisplayNameMode flag) + { + return (options & flag) == flag; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.Templates.cs b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.Templates.cs index 424d54bde..aaa0e3251 100644 --- a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.Templates.cs +++ b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.Templates.cs @@ -1,51 +1,49 @@ -using System.Collections.Generic; using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal partial class DiscordExtensionCore { - internal partial class DiscordExtensionCore + private void CreateTemplates() { - public void CreateTemplates() - { - DiscordMessageTemplate success = CreateTemplateEmbed($"You have successfully deleted application command {DefaultKeys.AppCommand.Name}", DiscordColor.Success); - DiscordExtension.DiscordMessageTemplates.RegisterLocalizedTemplateAsync(this, TemplateKeys.Commands.Delete.Success, success, new TemplateVersion(1, 0, 0), new TemplateVersion(1, 0, 0)); + DiscordMessageTemplate success = CreateTemplateEmbed($"You have successfully deleted application command {DefaultKeys.AppCommand.Name}", DiscordColor.Success); + DiscordExtension.DiscordMessageTemplates.RegisterLocalizedTemplateAsync(this, TemplateKeys.Commands.Delete.Success, success, new TemplateVersion(1, 0, 0), new TemplateVersion(1, 0, 0)); - DiscordMessageTemplate deleteError = CreateTemplateEmbed($"An error occured deleting command {DefaultKeys.AppCommand.Name}. Please try the command again. \nError: {DefaultKeys.ResponseError.Message}", DiscordColor.Danger); - DiscordExtension.DiscordMessageTemplates.RegisterLocalizedTemplateAsync(this, TemplateKeys.Commands.Delete.Errors.DeleteCommandError, deleteError, new TemplateVersion(1, 0, 0), new TemplateVersion(1, 0, 0)); + DiscordMessageTemplate deleteError = CreateTemplateEmbed($"An error occured deleting command {DefaultKeys.AppCommand.Name}. Please try the command again. \nError: {DefaultKeys.ResponseError.Message}", DiscordColor.Danger); + DiscordExtension.DiscordMessageTemplates.RegisterLocalizedTemplateAsync(this, TemplateKeys.Commands.Delete.Errors.DeleteCommandError, deleteError, new TemplateVersion(1, 0, 0), new TemplateVersion(1, 0, 0)); - DiscordMessageTemplate commandNotFound = CreateTemplateEmbed("We failed to find a matching command. Please make sure you select a command from the drop down.", DiscordColor.Danger); - DiscordExtension.DiscordMessageTemplates.RegisterLocalizedTemplateAsync(this, TemplateKeys.Commands.Delete.Errors.CommandIdNotFound, commandNotFound, new TemplateVersion(1, 0, 0), new TemplateVersion(1, 0, 0)); + DiscordMessageTemplate commandNotFound = CreateTemplateEmbed("We failed to find a matching command. Please make sure you select a command from the drop down.", DiscordColor.Danger); + DiscordExtension.DiscordMessageTemplates.RegisterLocalizedTemplateAsync(this, TemplateKeys.Commands.Delete.Errors.CommandIdNotFound, commandNotFound, new TemplateVersion(1, 0, 0), new TemplateVersion(1, 0, 0)); - DiscordMessageTemplate invalidSelection = CreateTemplateEmbed("You have selected an invalid command. Please try the command again and be sure to select an option from the drop down.", DiscordColor.Danger); - DiscordExtension.DiscordMessageTemplates.RegisterLocalizedTemplateAsync(this, TemplateKeys.Commands.Delete.Errors.InvalidSelection, invalidSelection, new TemplateVersion(1, 0, 0), new TemplateVersion(1, 0, 0)); - } - - public DiscordMessageTemplate CreateTemplateEmbed(string description, DiscordColor color) + DiscordMessageTemplate invalidSelection = CreateTemplateEmbed("You have selected an invalid command. Please try the command again and be sure to select an option from the drop down.", DiscordColor.Danger); + DiscordExtension.DiscordMessageTemplates.RegisterLocalizedTemplateAsync(this, TemplateKeys.Commands.Delete.Errors.InvalidSelection, invalidSelection, new TemplateVersion(1, 0, 0), new TemplateVersion(1, 0, 0)); + } + + private DiscordMessageTemplate CreateTemplateEmbed(string description, DiscordColor color) + { + return new DiscordMessageTemplate { - return new DiscordMessageTemplate - { - Embeds = new List + Embeds = + [ + new DiscordEmbedTemplate { - new DiscordEmbedTemplate - { - Description = description, - Color = color.ToHex() - } - }, - }; - } + Description = description, + Color = color.ToHex() + } + ], + }; + } - public void SendTemplateMessage(DiscordClient client, TemplateKey key, DiscordInteraction interaction, PlaceholderData placeholders = null) + private void SendTemplateMessage(DiscordClient client, TemplateKey key, DiscordInteraction interaction, PlaceholderData placeholders = null) + { + InteractionCallbackData message = new() { - InteractionCallbackData message = new InteractionCallbackData - { - Flags = interaction.GuildId.HasValue ? MessageFlags.Ephemeral : (MessageFlags?)null - }; - DiscordMessageTemplate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(this, key, interaction); - template.ToMessage(placeholders, message); - interaction.CreateResponse(client, InteractionResponseType.ChannelMessageWithSource, message); - } + Flags = interaction.GuildId.HasValue ? MessageFlags.Ephemeral : null + }; + DiscordMessageTemplate template = DiscordExtension.DiscordMessageTemplates.GetLocalizedTemplate(this, key, interaction); + template.ToMessage(placeholders, message); + interaction.CreateResponse(client, InteractionResponseType.ChannelMessageWithSource, message); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.cs b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.cs index 875332d32..3824dc1c7 100644 --- a/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.cs +++ b/Oxide.Ext.Discord/Plugins/Core/DiscordExtensionCore.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using System.Threading; using Oxide.Core; using Oxide.Core.Libraries.Covalence; @@ -17,365 +16,372 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Logging; +using Oxide.Ext.Discord.Rest; +using Oxide.Ext.Discord.Types; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal partial class DiscordExtensionCore : BaseDiscordPlugin { - internal partial class DiscordExtensionCore : BaseDiscordPlugin - { - #region Fields - public readonly PluginId PluginId; - public static DiscordExtensionCore Instance; - private ILogger _logger; + #region Fields + public readonly PluginId PluginId; + public static DiscordExtensionCore Instance; + private ILogger _logger; - internal bool IsServerLoaded; + internal bool IsServerLoaded; - private readonly Hash> _pluginReferences; - #endregion + private readonly Hash> _pluginReferences; + #endregion - #region Setup & Loading - public DiscordExtensionCore() + #region Setup & Loading + public DiscordExtensionCore() + { + Name = "DiscordExtension"; + Title = "Discord Extension"; + PluginId = new PluginId(this); + _pluginReferences = new Hash> { - Name = "DiscordExtension"; - Title = "Discord Extension"; - PluginId = new PluginId(this); - _pluginReferences = new Hash> - { - ["PlaceholderAPI"] = HandlePlaceholderApi, - ["Clans"] = plugin => _clans = plugin, - }; - } + ["PlaceholderAPI"] = HandlePlaceholderApi, + ["Clans"] = plugin => _clans = plugin, + }; + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(Init))] - private void Init() - { - Instance = this; - _logger = DiscordLoggerFactory.Instance.CreateExtensionLogger(DiscordLogLevel.Info); - DiscordPool.Instance.CreateInternal(this); - DataHandler.Instance.LoadAll(); - AddCovalenceCommand(new[] { "de.version" }, nameof(VersionCommand), "de.version"); - AddCovalenceCommand(new[] { "de.websocket.reset" }, nameof(ResetWebSocketCommand), "de.websocket.reset"); - AddCovalenceCommand(new[] { "de.websocket.reconnect" }, nameof(ReconnectWebSocketCommand), "de.websocket.reconnect"); - AddCovalenceCommand(new[] { "de.rest.reset" }, nameof(ResetRestApiCommand), "de.rest.reset"); - AddCovalenceCommand(new[] { "de.search.highperformance.enable" }, nameof(SearchHighPerformanceEnabled), "de.search.highperformance.enable"); - AddCovalenceCommand(new[] { "de.placeholders.list" }, nameof(PlaceholdersList), "de.placeholders.list"); - AddCovalenceCommand(new[] { "de.pool.clearentities" }, nameof(ClearEntitiesDiscordPool), "de.pool.clearentities"); - AddCovalenceCommand(new[] { "de.pool.remove" }, nameof(RemoveDiscordPool), "de.pool.remove"); - AddCovalenceCommand(new[] { "de.log.console" }, nameof(ConsoleLogCommand), "de.log.console"); - AddCovalenceCommand(new[] { "de.log.file" }, nameof(FileLogCommand), "de.log.file"); - AddCovalenceCommand(new[] { "de.validation.enable" }, nameof(ValidationEnableCommand), "de.validation.enable"); - AddCovalenceCommand(new[] { "de.debug" }, nameof(DiscordDebugCommand), "de.debug"); - AddCovalenceCommand(new[] { "de.help" }, nameof(DiscordHelpCommand), "de.help"); + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(Init))] + private void Init() + { + Instance = this; + _logger = DiscordLoggerFactory.Instance.CreateExtensionLogger(DiscordLogLevel.Info); + DiscordPool.Instance.CreateInternal(this); + DataHandler.Instance.LoadAll(); + AddCovalenceCommand(["de.version"], nameof(VersionCommand), "de.version"); + AddCovalenceCommand(["de.websocket.reset"], nameof(ResetWebSocketCommand), "de.websocket.reset"); + AddCovalenceCommand(["de.websocket.reconnect"], nameof(ReconnectWebSocketCommand), "de.websocket.reconnect"); + AddCovalenceCommand(["de.rest.reset"], nameof(ResetRestApiCommand), "de.rest.reset"); + AddCovalenceCommand(["de.search.highperformance.enable"], nameof(SearchHighPerformanceEnabled), "de.search.highperformance.enable"); + AddCovalenceCommand(["de.placeholders.list"], nameof(PlaceholdersList), "de.placeholders.list"); + AddCovalenceCommand(["de.pool.clearentities"], nameof(ClearEntitiesDiscordPool), "de.pool.clearentities"); + AddCovalenceCommand(["de.pool.remove"], nameof(RemoveDiscordPool), "de.pool.remove"); + AddCovalenceCommand(["de.log.console"], nameof(ConsoleLogCommand), "de.log.console"); + AddCovalenceCommand(["de.log.file"], nameof(FileLogCommand), "de.log.file"); + AddCovalenceCommand(["de.validation.enable"], nameof(ValidationEnableCommand), "de.validation.enable"); + AddCovalenceCommand(["de.debug"], nameof(DiscordDebugCommand), "de.debug"); + AddCovalenceCommand(["de.help"], nameof(DiscordHelpCommand), "de.help"); - foreach (KeyValuePair> language in Localization.Languages) - { - Lang.RegisterMessages(language.Value, this, language.Key); - } + foreach (KeyValuePair> language in Localization.Languages) + { + Lang.RegisterMessages(language.Value, this, language.Key); + } - DiscordPlaceholders.Instance.RegisterPlaceholders(); - ServerPlayerCache.Instance.SetSearchService(); + DiscordPlaceholders.Instance.RegisterPlaceholders(); + ServerPlayerCache.Instance.SetSearchService(); - CreateTemplates(); - RegisterApplicationCommands(); - } + CreateTemplates(); + RegisterApplicationCommands(); + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnServerInitialized))] - private void OnServerInitialized() - { - IsServerLoaded = true; - } + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnServerInitialized))] + private void OnServerInitialized() + { + IsServerLoaded = true; + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnServerSave))] - private void OnServerSave() - { - DataHandler.Instance.OnServerSave(); - } + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnServerSave))] + private void OnServerSave() + { + DataHandler.Instance.OnServerSave(); + } + + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnServerShutdown))] + private void OnServerShutdown() + { + DiscordExtension.IsShuttingDown = true; + } + + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(Unload))] + private void Unload() + { + Instance = null; + } + #endregion + + #region Commands + [HookMethod(nameof(VersionCommand))] + private void VersionCommand(IPlayer player) + { + Chat(player, LangKeys.Version, DiscordExtension.FullExtensionVersion); + } + + [HookMethod(nameof(ResetWebSocketCommand))] + private void ResetWebSocketCommand(IPlayer player) + { + BotClientFactory.Instance.ResetAllWebSockets(); + Chat(player, LangKeys.Websocket.Reset); + } + + [HookMethod(nameof(ReconnectWebSocketCommand))] + private void ReconnectWebSocketCommand(IPlayer player) + { + BotClientFactory.Instance.ReconnectAllWebSockets(); + Chat(player, LangKeys.Websocket.Reconnect); + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnServerShutdown))] - private void OnServerShutdown() + [HookMethod(nameof(ResetRestApiCommand))] + private void ResetRestApiCommand(IPlayer player) + { + BotClientFactory.Instance.ResetAllRestApis(); + Chat(player, LangKeys.RestApi.Reset); + } + + [HookMethod(nameof(SearchHighPerformanceEnabled))] + // ReSharper disable once UnusedParameter.Local + private void SearchHighPerformanceEnabled(IPlayer player, string cmd, string[] args) + { + DiscordSearchConfig config = DiscordConfig.Instance.Search; + if (args.Length == 0) { - DiscordExtension.IsShuttingDown = true; + Chat(player, LangKeys.Search.HighPerformance.Show, GetLang(config.EnablePlayerNameSearchTrie ? LangKeys.Enabled : LangKeys.Disabled)); + return; } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(Unload))] - private void Unload() + if (!args[0].ParseBool(out bool state)) { - Instance = null; + Chat(player, LangKeys.Search.HighPerformance.Invalid, args[0]); + return; } - #endregion - - #region Commands - [HookMethod(nameof(VersionCommand))] - private void VersionCommand(IPlayer player) + + Chat(player, LangKeys.Search.HighPerformance.Set, GetLang(state ? LangKeys.Enabled : LangKeys.Disabled)); + + if (config.EnablePlayerNameSearchTrie != state) { - Chat(player, LangKeys.Version, DiscordExtension.FullExtensionVersion); + config.EnablePlayerNameSearchTrie = state; + ServerPlayerCache.Instance.SetSearchService(); + DiscordConfig.Instance.Save(); } + } - [HookMethod(nameof(ResetWebSocketCommand))] - private void ResetWebSocketCommand(IPlayer player) + [HookMethod(nameof(PlaceholdersList))] + private void PlaceholdersList(IPlayer player) + { + ValueStringBuilder sb = new(); + string extensionName = this.PluginName(); + foreach (KeyValuePair placeholder in DiscordPlaceholders.Instance.GetPlaceholders().OrderBy(p => p.Key)) { - BotClientFactory.Instance.ResetAllWebSockets(); - Chat(player, LangKeys.Websocket.Reset); + sb.Append('{'); + sb.Append(placeholder.Key.Placeholder); + sb.Append("} - Return Type: "); + sb.Append(placeholder.Value.GetReturnType().Name); + sb.Append(" Plugin: "); + sb.Append(placeholder.Value.IsExtensionPlaceholder ? extensionName : placeholder.Value.PluginName); + sb.AppendLine(); } + + Chat(player, LangKeys.Placeholders.List, sb.ToString()); + } - [HookMethod(nameof(ReconnectWebSocketCommand))] - private void ReconnectWebSocketCommand(IPlayer player) - { - BotClientFactory.Instance.ReconnectAllWebSockets(); - Chat(player, LangKeys.Websocket.Reconnect); - } + [HookMethod(nameof(ClearEntitiesDiscordPool))] + private void ClearEntitiesDiscordPool(IPlayer player) + { + Chat(player, LangKeys.Pool.ClearEntities); + DiscordPool.Instance.Clear(); + } - [HookMethod(nameof(ResetRestApiCommand))] - private void ResetRestApiCommand(IPlayer player) - { - BotClientFactory.Instance.ResetAllRestApis(); - Chat(player, LangKeys.RestApi.Reset); - } + [HookMethod(nameof(RemoveDiscordPool))] + private void RemoveDiscordPool(IPlayer player) + { + Chat(player, LangKeys.Pool.Remove); + DiscordPool.Instance.Wipe(); + } - [HookMethod(nameof(SearchHighPerformanceEnabled))] - // ReSharper disable once UnusedParameter.Local - private void SearchHighPerformanceEnabled(IPlayer player, string cmd, string[] args) + [HookMethod(nameof(ConsoleLogCommand))] + // ReSharper disable once UnusedParameter.Local + private void ConsoleLogCommand(IPlayer player, string cmd, string[] args) + { + if (args.Length == 0) { - DiscordSearchConfig config = DiscordConfig.Instance.Search; - if (args.Length == 0) - { - Chat(player, LangKeys.Search.HighPerformance.Show, GetLang(config.EnablePlayerNameSearchTrie ? LangKeys.Enabled : LangKeys.Disabled)); - return; - } - - if (!args[0].ParseBool(out bool state)) - { - Chat(player, LangKeys.Search.HighPerformance.Invalid, args[0]); - return; - } - - Chat(player, LangKeys.Search.HighPerformance.Set, GetLang(state ? LangKeys.Enabled : LangKeys.Disabled)); - - if (config.EnablePlayerNameSearchTrie != state) - { - config.EnablePlayerNameSearchTrie = state; - ServerPlayerCache.Instance.SetSearchService(); - DiscordConfig.Instance.Save(); - } + Chat(player, LangKeys.Log.Show, "Console", DiscordConfig.Instance.Logging.ConsoleLogLevel); + return; } - [HookMethod(nameof(PlaceholdersList))] - private void PlaceholdersList(IPlayer player) + try { - StringBuilder sb = DiscordPool.Internal.GetStringBuilder(); - string extensionName = this.PluginName(); - foreach (KeyValuePair placeholder in DiscordPlaceholders.Instance.GetPlaceholders().OrderBy(p => p.Key)) - { - sb.Append('{'); - sb.Append(placeholder.Key.Placeholder); - sb.Append("} - Return Type: "); - sb.Append(placeholder.Value.GetReturnType().Name); - sb.Append(" Plugin: "); - sb.AppendLine(placeholder.Value.IsExtensionPlaceholder ? extensionName : placeholder.Value.PluginName); - } - - Chat(player, LangKeys.Placeholders.List, DiscordPool.Internal.ToStringAndFree(sb)); + DiscordLogLevel log = (DiscordLogLevel)Enum.Parse(typeof(DiscordLogLevel), args[0], true); + DiscordConfig.Instance.Logging.ConsoleLogLevel = log; + DiscordConfig.Instance.Save(); + + Chat(player, LangKeys.Log.Set, "Console", log); + + BotClientFactory.Instance.UpdateLogLevel(); + WebhookClientFactory.Instance.UpdateLogLevel(); } - - [HookMethod(nameof(ClearEntitiesDiscordPool))] - private void ClearEntitiesDiscordPool(IPlayer player) + catch { - Chat(player, LangKeys.Pool.ClearEntities); - DiscordPool.Instance.Clear(); + Chat(player, LangKeys.Log.InvalidEnum, args[0]); } + } - [HookMethod(nameof(RemoveDiscordPool))] - private void RemoveDiscordPool(IPlayer player) + [HookMethod(nameof(FileLogCommand))] + // ReSharper disable once UnusedParameter.Local + private void FileLogCommand(IPlayer player, string cmd, string[] args) + { + if (args.Length == 0) { - Chat(player, LangKeys.Pool.Remove); - DiscordPool.Instance.Wipe(); + Chat(player, LangKeys.Log.Show, "File", DiscordConfig.Instance.Logging.FileLogLevel); + return; } - - [HookMethod(nameof(ConsoleLogCommand))] - // ReSharper disable once UnusedParameter.Local - private void ConsoleLogCommand(IPlayer player, string cmd, string[] args) + + try { - if (args.Length == 0) - { - Chat(player, LangKeys.Log.Show, "Console", DiscordConfig.Instance.Logging.ConsoleLogLevel); - return; - } - - try - { - DiscordLogLevel log = (DiscordLogLevel)Enum.Parse(typeof(DiscordLogLevel), args[0], true); - DiscordConfig.Instance.Logging.ConsoleLogLevel = log; - DiscordConfig.Instance.Save(); + DiscordLogLevel log = (DiscordLogLevel)Enum.Parse(typeof(DiscordLogLevel), args[0], true); + DiscordConfig.Instance.Logging.FileLogLevel = log; + DiscordConfig.Instance.Save(); - Chat(player, LangKeys.Log.Set, "Console", log); + Chat(player, LangKeys.Log.Set, "File", log); - BotClientFactory.Instance.UpdateLogLevel(); - } - catch - { - Chat(player, LangKeys.Log.InvalidEnum, args[0]); - } + BotClientFactory.Instance.UpdateLogLevel(); + WebhookClientFactory.Instance.UpdateLogLevel(); + DiscordClientFactory.Instance.UpdateLogLevel(); } - - [HookMethod(nameof(FileLogCommand))] - // ReSharper disable once UnusedParameter.Local - private void FileLogCommand(IPlayer player, string cmd, string[] args) + catch { - if (args.Length == 0) - { - Chat(player, LangKeys.Log.Show, "File", DiscordConfig.Instance.Logging.FileLogLevel); - return; - } - - try - { - DiscordLogLevel log = (DiscordLogLevel)Enum.Parse(typeof(DiscordLogLevel), args[0], true); - DiscordConfig.Instance.Logging.FileLogLevel = log; - DiscordConfig.Instance.Save(); - - Chat(player, LangKeys.Log.Set, "File", log); - - BotClientFactory.Instance.UpdateLogLevel(); - DiscordClientFactory.Instance.UpdateLogLevel(); - } - catch - { - Chat(player, LangKeys.Log.InvalidEnum, args[0]); - } + Chat(player, LangKeys.Log.InvalidEnum, args[0]); } + } - [HookMethod(nameof(ValidationEnableCommand))] - // ReSharper disable once UnusedParameter.Local - private void ValidationEnableCommand(IPlayer player, string cmd, string[] args) + [HookMethod(nameof(ValidationEnableCommand))] + // ReSharper disable once UnusedParameter.Local + private void ValidationEnableCommand(IPlayer player, string cmd, string[] args) + { + if (args.Length == 0) { - if (args.Length == 0) - { - Chat(player, LangKeys.Validation.Show, GetLang(DiscordConfig.Instance.Validation.EnableValidation ? LangKeys.Enabled : LangKeys.Disabled)); - return; - } - - if (!args[0].ParseBool(out bool state)) - { - Chat(player, LangKeys.Validation.InvalidEnum, args[0]); - return; - } - - DiscordConfig.Instance.Validation.EnableValidation = state; - Chat(player, LangKeys.Validation.Set, GetLang(state ? LangKeys.Enabled : LangKeys.Disabled)); - DiscordConfig.Instance.Save(); + Chat(player, LangKeys.Validation.Show, GetLang(DiscordConfig.Instance.Validation.EnableValidation ? LangKeys.Enabled : LangKeys.Disabled)); + return; } - [HookMethod(nameof(DiscordDebugCommand))] - // ReSharper disable once UnusedParameter.Local - private void DiscordDebugCommand(IPlayer player, string cmd, string[] args) + if (!args[0].ParseBool(out bool state)) { - DebugLogger logger = new DebugLogger(); + Chat(player, LangKeys.Validation.InvalidEnum, args[0]); + return; + } - ThreadPool.GetAvailableThreads(out int worker, out int port); - ThreadPool.GetMaxThreads(out int maxWorker, out int maxPort); + DiscordConfig.Instance.Validation.EnableValidation = state; + Chat(player, LangKeys.Validation.Set, GetLang(state ? LangKeys.Enabled : LangKeys.Disabled)); + DiscordConfig.Instance.Save(); + } + + [HookMethod(nameof(DiscordDebugCommand))] + // ReSharper disable once UnusedParameter.Local + private void DiscordDebugCommand(IPlayer player, string cmd, string[] args) + { + DebugLogger logger = new(); - logger.AppendList("Bot Clients", BotClientFactory.Instance.Clients); - logger.StartObject("Threads"); - logger.AppendFieldOutOf("Worker", worker, maxWorker); - logger.AppendFieldOutOf("Port", port, maxPort); - logger.EndObject(); - logger.StartObject("Libraries"); - logger.AppendObject("Discord Application Command", DiscordAppCommand.Instance); - logger.AppendObject("Discord Command", DiscordCommand.Instance); - logger.AppendObject("Discord Subscriptions", DiscordSubscriptions.Instance); - DiscordAppCommand.Instance.LogDebug(logger); - DiscordCommand.Instance.LogDebug(logger); - DiscordSubscriptions.Instance.LogDebug(logger); - logger.AppendObject("Discord Pool", DiscordPool.Instance); - logger.EndObject(); + ThreadPool.GetAvailableThreads(out int worker, out int port); + ThreadPool.GetMaxThreads(out int maxWorker, out int maxPort); - string message = logger.ToString(); + logger.AppendLine($"Discord Extension Version: {DiscordExtension.FullExtensionVersion}"); + logger.AppendList("Bot Clients", BotClientFactory.Instance.Clients); + logger.AppendList("Webhook Clients", WebhookClientFactory.Instance.Clients); + logger.AppendObject("Global Rest", RestHandler.Global); + logger.StartObject("Threads"); + logger.AppendFieldOutOf("Worker", worker, maxWorker); + logger.AppendFieldOutOf("Port", port, maxPort); + logger.EndObject(); + logger.StartObject("Libraries"); + logger.AppendObject("Discord Application Command", DiscordAppCommand.Instance); + logger.AppendObject("Discord Command", DiscordCommand.Instance); + logger.AppendObject("Discord Subscriptions", DiscordSubscriptions.Instance); + DiscordAppCommand.Instance.LogDebug(logger); + DiscordCommand.Instance.LogDebug(logger); + DiscordSubscriptions.Instance.LogDebug(logger); + logger.AppendObject("Discord Pool", DiscordPool.Instance); + logger.EndObject(); + + string message = logger.ToString(); - if (args.Length != 0 && args[0].Equals("file", StringComparison.OrdinalIgnoreCase)) - { - string path = Path.Combine(Interface.Oxide.LogDirectory, "DiscordExtension"); - string filePath = Path.Combine(path, $"DEBUG-{DateTime.Now:yyyy-MM-dd_h-mm-ss-tt}.txt"); - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } - - File.WriteAllText(filePath, message); - player.Message($"Debug Saved to File. Path: {filePath.Replace(Interface.Oxide.RootDirectory, "").Substring(1)}"); - } - else + if (args.Length != 0 && args[0].Equals("file", StringComparison.OrdinalIgnoreCase)) + { + string path = Path.Combine(Interface.Oxide.LogDirectory, "DiscordExtension"); + string filePath = Path.Combine(path, $"DEBUG-{DateTime.Now:yyyy-MM-dd_h-mm-ss-tt}.txt"); + if (!Directory.Exists(path)) { - player.Message(message); - _logger.Info(message); + Directory.CreateDirectory(path); } + + File.WriteAllText(filePath, message); + player.Message($"Debug Saved to File. Path: {filePath.Replace(Interface.Oxide.RootDirectory, "").Substring(1)}"); } - - [HookMethod(nameof(DiscordHelpCommand))] - private void DiscordHelpCommand(IPlayer player) + else { - Chat(player, LangKeys.Help, DiscordExtension.FullExtensionVersion); + player.Message(message); + _logger.Info(message); } - #endregion + } - #region Hooks - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnPluginLoaded))] - private void OnPluginLoaded(Plugin plugin) - { - _pluginReferences[plugin.Name]?.Invoke(plugin); - } + [HookMethod(nameof(DiscordHelpCommand))] + private void DiscordHelpCommand(IPlayer player) + { + Chat(player, LangKeys.Help, DiscordExtension.FullExtensionVersion); + } + #endregion + + #region Hooks + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnPluginLoaded))] + private void OnPluginLoaded(Plugin plugin) + { + _pluginReferences[plugin.Name]?.Invoke(plugin); + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnPluginUnloaded))] - private void OnPluginUnloaded(Plugin plugin) - { - _pluginReferences[plugin.Name]?.Invoke(null); - } + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnPluginUnloaded))] + private void OnPluginUnloaded(Plugin plugin) + { + _pluginReferences[plugin.Name]?.Invoke(null); + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnUserApproved))] - // ReSharper disable twice UnusedParameter.Local - private void OnUserApproved(string name, string id, string ipAddress) + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnUserApproved))] + // ReSharper disable twice UnusedParameter.Local + private void OnUserApproved(string name, string id, string ipAddress) + { + if (!DiscordIpData.Instance.HasData(ipAddress)) { - if (!DiscordIpData.Instance.HasData(ipAddress)) - { - _logger.Verbose($"{nameof(DiscordExtensionCore)}.{nameof(OnUserConnected)} No data found for IP: {{0}}. Requesting Data.", ipAddress); - GetIpDataCallback.Start(ipAddress); - } + _logger.Verbose($"{nameof(DiscordExtensionCore)}.{nameof(OnUserConnected)} No data found for IP: {{0}}. Requesting Data.", ipAddress); + GetIpDataCallback.Start(ipAddress); } + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnUserConnected))] - private void OnUserConnected(IPlayer player) - { - ServerPlayerCache.Instance.OnUserConnected(player); - } + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnUserConnected))] + private void OnUserConnected(IPlayer player) + { + ServerPlayerCache.Instance.OnUserConnected(player); + } - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnUserDisconnected))] - private void OnUserDisconnected(IPlayer player) + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnUserDisconnected))] + private void OnUserDisconnected(IPlayer player) + { + try { - try - { - ServerPlayerCache.Instance.OnUserDisconnected(player); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An error occured", ex); - } + ServerPlayerCache.Instance.OnUserDisconnected(player); } - - // ReSharper disable once UnusedMember.Local - [HookMethod(nameof(OnUserNameUpdated))] - private void OnUserNameUpdated(IPlayer player, string oldName, string newName) + catch (Exception ex) { - ServerPlayerCache.Instance.OnUserNameUpdated(player, oldName, newName); + DiscordExtension.GlobalLogger.Exception("An error occured", ex); } - #endregion } + + // ReSharper disable once UnusedMember.Local + [HookMethod(nameof(OnUserNameUpdated))] + private void OnUserNameUpdated(IPlayer player, string oldName, string newName) + { + ServerPlayerCache.Instance.OnUserNameUpdated(player, oldName, newName); + } + #endregion } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Core/Templates/TemplateKeys.cs b/Oxide.Ext.Discord/Plugins/Core/Templates/TemplateKeys.cs index ae58d3ee3..0bcac4b9f 100644 --- a/Oxide.Ext.Discord/Plugins/Core/Templates/TemplateKeys.cs +++ b/Oxide.Ext.Discord/Plugins/Core/Templates/TemplateKeys.cs @@ -1,29 +1,28 @@ using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal static class TemplateKeys { - internal static class TemplateKeys + public static class Commands { - public static class Commands - { - private const string Base = nameof(Commands) + "."; + private const string Base = nameof(Commands) + "."; - public static class Delete - { - // ReSharper disable once MemberHidesStaticFromOuterClass - private const string Base = Commands.Base + nameof(Delete) + "."; + public static class Delete + { + // ReSharper disable once MemberHidesStaticFromOuterClass + private const string Base = Commands.Base + nameof(Delete) + "."; - public static readonly TemplateKey Success = new TemplateKey( Base + nameof(Success)); + public static readonly TemplateKey Success = new( Base + nameof(Success)); - public static class Errors - { - // ReSharper disable once MemberHidesStaticFromOuterClass - private const string Base = Delete.Base + nameof(Errors) + "."; + public static class Errors + { + // ReSharper disable once MemberHidesStaticFromOuterClass + private const string Base = Delete.Base + nameof(Errors) + "."; - public static readonly TemplateKey InvalidSelection = new TemplateKey(Base + nameof(InvalidSelection)); - public static readonly TemplateKey CommandIdNotFound = new TemplateKey(Base + nameof(CommandIdNotFound)); - public static readonly TemplateKey DeleteCommandError = new TemplateKey(Base + nameof(DeleteCommandError)); - } + public static readonly TemplateKey InvalidSelection = new(Base + nameof(InvalidSelection)); + public static readonly TemplateKey CommandIdNotFound = new(Base + nameof(CommandIdNotFound)); + public static readonly TemplateKey DeleteCommandError = new(Base + nameof(DeleteCommandError)); } } } diff --git a/Oxide.Ext.Discord/Plugins/DiscordDummyPlayer.cs b/Oxide.Ext.Discord/Plugins/DiscordDummyPlayer.cs index cec7e139d..ac0f9a695 100644 --- a/Oxide.Ext.Discord/Plugins/DiscordDummyPlayer.cs +++ b/Oxide.Ext.Discord/Plugins/DiscordDummyPlayer.cs @@ -4,85 +4,84 @@ using Oxide.Core.Libraries.Covalence; using Oxide.Ext.Discord.Cache; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal class DiscordDummyPlayer : IPlayer { - internal class DiscordDummyPlayer : IPlayer - { - private static readonly GenericPosition Default = new GenericPosition(); - private static readonly Permission Permission = OxideLibrary.Instance.Permission; + private static readonly GenericPosition Default = new(); + private static readonly Permission Permission = OxideLibrary.Instance.Permission; - public string Id { get; } + public string Id { get; } - public string Name { get; set; } = "Unknown Player"; - public object Object => null; - public string Address { get; set; } = "0.0.0.0"; - public int Ping => 0; - public CultureInfo Language => CultureInfo.GetCultureInfo("en"); - public bool IsConnected => false; - public bool IsSleeping => false; - public bool IsServer => false; - public bool IsAdmin => false; - public bool IsBanned => false; - public TimeSpan BanTimeRemaining => TimeSpan.Zero; + public string Name { get; set; } = "Unknown Player"; + public object Object => null; + public string Address { get; set; } = "0.0.0.0"; + public int Ping => 0; + public CultureInfo Language => CultureInfo.GetCultureInfo("en"); + public bool IsConnected => false; + public bool IsSleeping => false; + public bool IsServer => false; + public bool IsAdmin => false; + public bool IsBanned => false; + public TimeSpan BanTimeRemaining => TimeSpan.Zero; - public float Health - { - get => 0; - set {} - } + public float Health + { + get => 0; + set {} + } - public float MaxHealth - { - get => 0; - set {} - } + public float MaxHealth + { + get => 0; + set {} + } - public CommandType LastCommand - { - get => CommandType.Chat; - set { } - } + public CommandType LastCommand + { + get => CommandType.Chat; + set { } + } - public DiscordDummyPlayer(string id) - { - Id = id; - } + public DiscordDummyPlayer(string id) + { + Id = id; + } - public DiscordDummyPlayer(string id, string name, string ip) - { - Id = id; - Name = name ?? "Unknown Player"; - Address = ip ?? "0.0.0.0"; - } + public DiscordDummyPlayer(string id, string name, string ip) + { + Id = id; + Name = name ?? "Unknown Player"; + Address = ip ?? "0.0.0.0"; + } - public void Ban(string reason, TimeSpan duration = new TimeSpan()) {} - public void Heal(float amount) {} - public void Hurt(float amount) {} - public void Kick(string reason) {} - public void Kill() {} - public void Rename(string name) {} - public void Teleport(float x, float y, float z) {} - public void Teleport(GenericPosition pos) {} - public void Unban() {} - public void Message(string message, string prefix, params object[] args) {} - public void Message(string message) {} - public void Reply(string message, string prefix, params object[] args) {} - public void Reply(string message) {} - public void Command(string command, params object[] args) {} - public bool HasPermission(string perm) => Permission.UserHasPermission(Id, perm); - public void GrantPermission(string perm) => Permission.GrantUserPermission(Id, perm, null); - public void RevokePermission(string perm) => Permission.RevokeUserPermission(Id, perm); - public bool BelongsToGroup(string group) => Permission.UserHasGroup(Id, group); - public void AddToGroup(string group) => Permission.AddUserGroup(Id, group); - public void RemoveFromGroup(string group) => Permission.RemoveUserGroup(Id, group); + public void Ban(string reason, TimeSpan duration = new()) {} + public void Heal(float amount) {} + public void Hurt(float amount) {} + public void Kick(string reason) {} + public void Kill() {} + public void Rename(string name) {} + public void Teleport(float x, float y, float z) {} + public void Teleport(GenericPosition pos) {} + public void Unban() {} + public void Message(string message, string prefix, params object[] args) {} + public void Message(string message) {} + public void Reply(string message, string prefix, params object[] args) {} + public void Reply(string message) {} + public void Command(string command, params object[] args) {} + public bool HasPermission(string perm) => Permission.UserHasPermission(Id, perm); + public void GrantPermission(string perm) => Permission.GrantUserPermission(Id, perm, null); + public void RevokePermission(string perm) => Permission.RevokeUserPermission(Id, perm); + public bool BelongsToGroup(string group) => Permission.UserHasGroup(Id, group); + public void AddToGroup(string group) => Permission.AddUserGroup(Id, group); + public void RemoveFromGroup(string group) => Permission.RemoveUserGroup(Id, group); - public void Position(out float x, out float y, out float z) - { - x = 0; - y = 0; - z = 0; - } - - public GenericPosition Position() => Default; + public void Position(out float x, out float y, out float z) + { + x = 0; + y = 0; + z = 0; } + + public GenericPosition Position() => Default; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/DiscordExtPluginLoader.cs b/Oxide.Ext.Discord/Plugins/DiscordExtPluginLoader.cs index 1b10dda14..da6984e99 100644 --- a/Oxide.Ext.Discord/Plugins/DiscordExtPluginLoader.cs +++ b/Oxide.Ext.Discord/Plugins/DiscordExtPluginLoader.cs @@ -1,10 +1,9 @@ using System; using Oxide.Core.Plugins; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal class DiscordExtPluginLoader : PluginLoader { - internal class DiscordExtPluginLoader : PluginLoader - { - public override Type[] CorePlugins => new[] { typeof(DiscordExtensionCore) }; - } + public override Type[] CorePlugins => [typeof(DiscordExtensionCore)]; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Localization.cs b/Oxide.Ext.Discord/Plugins/Localization.cs index 4a10247c1..77c109eab 100644 --- a/Oxide.Ext.Discord/Plugins/Localization.cs +++ b/Oxide.Ext.Discord/Plugins/Localization.cs @@ -1,155 +1,154 @@ using System.Collections.Generic; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal static class LangKeys { - internal static class LangKeys - { - public const string Chat = nameof(Chat); - public const string Version = nameof(Version); - public const string Enabled = nameof(Enabled); - public const string Disabled = nameof(Disabled); - public const string Help = nameof(Help); + public const string Chat = nameof(Chat); + public const string Version = nameof(Version); + public const string Enabled = nameof(Enabled); + public const string Disabled = nameof(Disabled); + public const string Help = nameof(Help); - internal static class Websocket - { - private const string Base = nameof(Websocket) + "."; + internal static class Websocket + { + private const string Base = nameof(Websocket) + "."; - public const string Reconnect = Base + nameof(Reconnect); - public const string Reset = Base + nameof(Reset); - } + public const string Reconnect = Base + nameof(Reconnect); + public const string Reset = Base + nameof(Reset); + } - internal static class RestApi - { - private const string Base = nameof(RestApi) + "."; + internal static class RestApi + { + private const string Base = nameof(RestApi) + "."; - public const string Reset = Base + nameof(Reset); - } + public const string Reset = Base + nameof(Reset); + } - internal static class Pool - { - private const string Base = nameof(Pool) + "."; + internal static class Pool + { + private const string Base = nameof(Pool) + "."; - public const string ClearEntities = Base + nameof(ClearEntities); - public const string Remove = Base + nameof(Remove); - } + public const string ClearEntities = Base + nameof(ClearEntities); + public const string Remove = Base + nameof(Remove); + } - internal static class Placeholders - { - private const string Base = nameof(Placeholders) + "."; + internal static class Placeholders + { + private const string Base = nameof(Placeholders) + "."; - public const string List = Base + nameof(List); - } + public const string List = Base + nameof(List); + } - internal static class Log - { - private const string Base = nameof(Log) + "."; + internal static class Log + { + private const string Base = nameof(Log) + "."; - public const string Show = Base + nameof(Show); - public const string Set = Base + nameof(Set); - public const string InvalidEnum = Base + nameof(InvalidEnum); - } + public const string Show = Base + nameof(Show); + public const string Set = Base + nameof(Set); + public const string InvalidEnum = Base + nameof(InvalidEnum); + } - internal static class Validation - { - private const string Base = nameof(Validation) + "."; + internal static class Validation + { + private const string Base = nameof(Validation) + "."; - public const string Show = Base + nameof(Show); - public const string Set = Base + nameof(Set); - public const string InvalidEnum = Base + nameof(InvalidEnum); - } + public const string Show = Base + nameof(Show); + public const string Set = Base + nameof(Set); + public const string InvalidEnum = Base + nameof(InvalidEnum); + } - internal static class Search - { - private const string Base = nameof(Search) + "."; + internal static class Search + { + private const string Base = nameof(Search) + "."; - internal static class HighPerformance - { - // ReSharper disable once MemberHidesStaticFromOuterClass - private const string Base = Search.Base + nameof(HighPerformance) + "."; + internal static class HighPerformance + { + // ReSharper disable once MemberHidesStaticFromOuterClass + private const string Base = Search.Base + nameof(HighPerformance) + "."; - public const string Show = Base + nameof(Show); - public const string Set = Base + nameof(Set); - public const string Invalid = Base + nameof(Invalid); - } + public const string Show = Base + nameof(Show); + public const string Set = Base + nameof(Set); + public const string Invalid = Base + nameof(Invalid); } + } - internal static class TimeSpan - { - private const string Base = nameof(TimeSpan) + "."; + internal static class TimeSpan + { + private const string Base = nameof(TimeSpan) + "."; - public const string Infinity = Base + nameof(Infinity); + public const string Infinity = Base + nameof(Infinity); - public const string Days = Base + nameof(Days); - public const string Day = Base + nameof(Day); + public const string Days = Base + nameof(Days); + public const string Day = Base + nameof(Day); - public const string Hours = Base + nameof(Hours); - public const string Hour = Base + nameof(Hour); + public const string Hours = Base + nameof(Hours); + public const string Hour = Base + nameof(Hour); - public const string Minutes = Base + nameof(Minutes); - public const string Minute = Base + nameof(Minute); + public const string Minutes = Base + nameof(Minutes); + public const string Minute = Base + nameof(Minute); - public const string Seconds = Base + nameof(Seconds); - public const string Second = Base + nameof(Second); - } + public const string Seconds = Base + nameof(Seconds); + public const string Second = Base + nameof(Second); } +} - internal static class Localization +internal static class Localization +{ + internal static readonly Dictionary> Languages = new() { - internal static readonly Dictionary> Languages = new Dictionary> + ["en"] = new Dictionary { - ["en"] = new Dictionary - { - [LangKeys.Chat] = "[Discord Extension] {0}", - [LangKeys.Version] = "Server is running Discord Extension v{0}", - [LangKeys.Websocket.Reconnect] = "Requested reconnect for all web sockets", - [LangKeys.Websocket.Reset] = "All websockets have been reset", - [LangKeys.RestApi.Reset] = "All REST API's have been reset", - [LangKeys.Pool.ClearEntities] = "All Discord Pool Entities have been cleared", - [LangKeys.Pool.Remove] = "All Discord Pools have been removed", - [LangKeys.Placeholders.List] = "Placeholders:\n{0}", - [LangKeys.Log.Show] = "{0} log is currently set to {1}", - [LangKeys.Log.Set] = "{0} log has been set to {1}", - [LangKeys.Log.InvalidEnum] = "'{0}' is not a valid DiscordLogLevel enum. Valid values are Off, Error, Warning, Info, Debug, Verbose", - [LangKeys.Validation.Show] = "Discord Validation is currently set to {0}", - [LangKeys.Validation.Set] = "Discord Validation has been set to {0}", - [LangKeys.Validation.InvalidEnum] = "'{0}' is not a valid boolean value. Valid values are false, true, 0, or 1", - [LangKeys.Search.HighPerformance.Show] = "Discord Search High Performance is currently set to {0}", - [LangKeys.Search.HighPerformance.Set] = "Discord Search High Performance has been set to {0}", - [LangKeys.Search.HighPerformance.Invalid] = "'{0}' is not a valid boolean value. Valid values are false, true, 0, or 1", - [LangKeys.Enabled] = "Enabled", - [LangKeys.Disabled] = "Disabled", - [LangKeys.TimeSpan.Infinity] = "\u221E", - [LangKeys.TimeSpan.Day] = "Day", - [LangKeys.TimeSpan.Days] = "Days", - [LangKeys.TimeSpan.Hour] = "Hour", - [LangKeys.TimeSpan.Hours] = "Hours", - [LangKeys.TimeSpan.Minute] = "Minute", - [LangKeys.TimeSpan.Minutes] = "Minutes", - [LangKeys.TimeSpan.Second] = "Second", - [LangKeys.TimeSpan.Seconds] = "Seconds", - [LangKeys.Help] = "Discord Extension v{0} Commands:\n" + - " * de.version - displays the current Discord Extension version\n" + - " * de.reset.reset - resets all rest handlers\n" + - " * de.websocket.reset - resets all websockets\n" + - " * de.websocket.reconnect - reconnects all websockets\n" + - " * de.log.console - sets the console log level. Options (Verbose, Debug, Info, Warning, Error, Exception, Off)\n" + - " * de.log.file - sets the file log level. Options (Verbose, Debug, Info, Warning, Error, Exception, Off)\n" + - " * de.validation.enabled - sets if request validation is enabled\n" + - " * de.search.trie.enable - sets if player name search should use high performance trie mode\n" + - " * de.debug - prints debug information about the state of the Discord Extension" - }, - ["ru"] = new Dictionary - { - [LangKeys.TimeSpan.Infinity] = "\u221E", - [LangKeys.TimeSpan.Day] = "день ", - [LangKeys.TimeSpan.Days] = "дней ", - [LangKeys.TimeSpan.Hour] = "час ", - [LangKeys.TimeSpan.Hours] = "часов ", - [LangKeys.TimeSpan.Minute] = "минуту ", - [LangKeys.TimeSpan.Minutes] = "минут ", - [LangKeys.TimeSpan.Second] = "секунду", - [LangKeys.TimeSpan.Seconds] = "секунд", - } - }; - } + [LangKeys.Chat] = "[Discord Extension] {0}", + [LangKeys.Version] = "Server is running Discord Extension v{0}", + [LangKeys.Websocket.Reconnect] = "Requested reconnect for all web sockets", + [LangKeys.Websocket.Reset] = "All websockets have been reset", + [LangKeys.RestApi.Reset] = "All REST API's have been reset", + [LangKeys.Pool.ClearEntities] = "All Discord Pool Entities have been cleared", + [LangKeys.Pool.Remove] = "All Discord Pools have been removed", + [LangKeys.Placeholders.List] = "Placeholders:\n{0}", + [LangKeys.Log.Show] = "{0} log is currently set to {1}", + [LangKeys.Log.Set] = "{0} log has been set to {1}", + [LangKeys.Log.InvalidEnum] = "'{0}' is not a valid DiscordLogLevel enum. Valid values are Off, Error, Warning, Info, Debug, Verbose", + [LangKeys.Validation.Show] = "Discord Validation is currently set to {0}", + [LangKeys.Validation.Set] = "Discord Validation has been set to {0}", + [LangKeys.Validation.InvalidEnum] = "'{0}' is not a valid boolean value. Valid values are false, true, 0, or 1", + [LangKeys.Search.HighPerformance.Show] = "Discord Search High Performance is currently set to {0}", + [LangKeys.Search.HighPerformance.Set] = "Discord Search High Performance has been set to {0}", + [LangKeys.Search.HighPerformance.Invalid] = "'{0}' is not a valid boolean value. Valid values are false, true, 0, or 1", + [LangKeys.Enabled] = "Enabled", + [LangKeys.Disabled] = "Disabled", + [LangKeys.TimeSpan.Infinity] = "\u221E", + [LangKeys.TimeSpan.Day] = "Day", + [LangKeys.TimeSpan.Days] = "Days", + [LangKeys.TimeSpan.Hour] = "Hour", + [LangKeys.TimeSpan.Hours] = "Hours", + [LangKeys.TimeSpan.Minute] = "Minute", + [LangKeys.TimeSpan.Minutes] = "Minutes", + [LangKeys.TimeSpan.Second] = "Second", + [LangKeys.TimeSpan.Seconds] = "Seconds", + [LangKeys.Help] = "Discord Extension v{0} Commands:\n" + + " * de.version - displays the current Discord Extension version\n" + + " * de.reset.reset - resets all rest handlers\n" + + " * de.websocket.reset - resets all websockets\n" + + " * de.websocket.reconnect - reconnects all websockets\n" + + " * de.log.console - sets the console log level. Options (Verbose, Debug, Info, Warning, Error, Exception, Off)\n" + + " * de.log.file - sets the file log level. Options (Verbose, Debug, Info, Warning, Error, Exception, Off)\n" + + " * de.validation.enabled - sets if request validation is enabled\n" + + " * de.search.trie.enable - sets if player name search should use high performance trie mode\n" + + " * de.debug - prints debug information about the state of the Discord Extension" + }, + ["ru"] = new Dictionary + { + [LangKeys.TimeSpan.Infinity] = "\u221E", + [LangKeys.TimeSpan.Day] = "день ", + [LangKeys.TimeSpan.Days] = "дней ", + [LangKeys.TimeSpan.Hour] = "час ", + [LangKeys.TimeSpan.Hours] = "часов ", + [LangKeys.TimeSpan.Minute] = "минуту ", + [LangKeys.TimeSpan.Minutes] = "минут ", + [LangKeys.TimeSpan.Second] = "секунду", + [LangKeys.TimeSpan.Seconds] = "секунд", + } + }; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/PluginId.cs b/Oxide.Ext.Discord/Plugins/PluginId.cs index 9a2342b06..825d8ae28 100644 --- a/Oxide.Ext.Discord/Plugins/PluginId.cs +++ b/Oxide.Ext.Discord/Plugins/PluginId.cs @@ -4,71 +4,45 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +/// +/// Represents a Plugin ID +/// +public readonly record struct PluginId : IDebugLoggable { /// - /// Represents a Plugin ID + /// Hashcode value of the Plugin Name /// - public struct PluginId : IEquatable, IDebugLoggable - { - /// - /// Hashcode value of the Plugin Name - /// - public readonly int Id; - - /// - /// Returns if the PluginId is valid - /// - public bool IsValid => Id != 0; - - internal bool IsExtensionPlugin => IsValid && this == DiscordExtensionCore.Instance.PluginId; - - internal PluginId(Plugin plugin) - { - Id = plugin?.Name.GetHashCode() ?? throw new ArgumentNullException(nameof(plugin)); - } + public readonly int Id; - internal PluginId(string id) - { - Id = id?.GetHashCode() ?? throw new ArgumentNullException(nameof(id)); - } - - /// - public bool Equals(PluginId other) => Id == other.Id; - - /// - public override bool Equals(object obj) => obj is PluginId other && Equals(other); + /// + /// Returns if the PluginId is valid + /// + public bool IsValid => Id != 0; - /// - public override int GetHashCode() => Id; + internal bool IsExtensionPlugin => IsValid && this == DiscordExtensionCore.Instance.PluginId; - /// - /// - /// - /// - /// - /// - public static bool operator == (PluginId left, PluginId right) => left.Equals(right); + internal PluginId(Plugin plugin) + { + Id = plugin?.Name.GetHashCode() ?? throw new ArgumentNullException(nameof(plugin)); + } - /// - /// - /// - /// - /// - /// - public static bool operator !=(PluginId left, PluginId right) => !(left == right); + internal PluginId(string id) + { + Id = id?.GetHashCode() ?? throw new ArgumentNullException(nameof(id)); + } - /// - /// Returns the PluginName - /// - /// - public override string ToString() => this.PluginName(); + /// + /// Returns the PluginName + /// + /// + public override string ToString() => this.PluginName(); - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendField("ID", Id); - logger.AppendField("Name", this.PluginName()); - } + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("ID", Id); + logger.AppendField("Name", this.PluginName()); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Setup/PluginCallback.cs b/Oxide.Ext.Discord/Plugins/Setup/PluginCallback.cs index 178ad8bdd..129a9947a 100644 --- a/Oxide.Ext.Discord/Plugins/Setup/PluginCallback.cs +++ b/Oxide.Ext.Discord/Plugins/Setup/PluginCallback.cs @@ -3,38 +3,37 @@ using System.Reflection; using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal readonly struct PluginCallback { - internal struct PluginCallback - { - public readonly string Name; - public readonly MethodInfo Method; - public readonly List Attributes; + public readonly string Name; + public readonly MethodInfo Method; + public readonly List Attributes; - public PluginCallback(string name, MethodInfo method, Attribute[] attributes) + public PluginCallback(string name, MethodInfo method, Attribute[] attributes) + { + Name = name; + Method = method; + Attributes = new List(0); + for (int index = 0; index < attributes.Length; index++) { - Name = name; - Method = method; - Attributes = new List(0); - for (int index = 0; index < attributes.Length; index++) + Attribute attribute = attributes[index]; + if (attribute is BaseDiscordAttribute) { - Attribute attribute = attributes[index]; - if (attribute is BaseDiscordAttribute) - { - Attributes.Add(attribute); - } + Attributes.Add(attribute); } } + } - public IEnumerable GetAttributes() where T : Attribute + public IEnumerable GetAttributes() where T : Attribute + { + for (int index = 0; index < Attributes.Count; index++) { - for (int index = 0; index < Attributes.Count; index++) + Attribute attribute = Attributes[index]; + if (attribute is T tAttribute) { - Attribute attribute = Attributes[index]; - if (attribute is T tAttribute) - { - yield return tAttribute; - } + yield return tAttribute; } } } diff --git a/Oxide.Ext.Discord/Plugins/Setup/PluginField.cs b/Oxide.Ext.Discord/Plugins/Setup/PluginField.cs index 12d70bbce..75d4906bd 100644 --- a/Oxide.Ext.Discord/Plugins/Setup/PluginField.cs +++ b/Oxide.Ext.Discord/Plugins/Setup/PluginField.cs @@ -3,39 +3,38 @@ using System.Reflection; using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal readonly struct PluginField { - internal struct PluginField - { - public readonly MemberInfo Member; - private readonly List _attributes; + public readonly MemberInfo Member; + private readonly List _attributes; - public PluginField(MemberInfo member, Attribute[] attributes) + public PluginField(MemberInfo member, Attribute[] attributes) + { + Member = member; + _attributes = new List(0); + for (int index = 0; index < attributes.Length; index++) { - Member = member; - _attributes = new List(0); - for (int index = 0; index < attributes.Length; index++) + Attribute attribute = attributes[index]; + if (attribute is BaseDiscordAttribute) { - Attribute attribute = attributes[index]; - if (attribute is BaseDiscordAttribute) - { - _attributes.Add(attribute); - } + _attributes.Add(attribute); } } + } - public T GetAttribute() where T : Attribute + public T GetAttribute() where T : Attribute + { + for (int index = 0; index < _attributes.Count; index++) { - for (int index = 0; index < _attributes.Count; index++) + Attribute attribute = _attributes[index]; + if (attribute is T tAttribute) { - Attribute attribute = _attributes[index]; - if (attribute is T tAttribute) - { - return tAttribute; - } + return tAttribute; } - - return default(T); } + + return default; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Setup/PluginFieldResult.cs b/Oxide.Ext.Discord/Plugins/Setup/PluginFieldResult.cs index f9cd6252b..1a9d9469b 100644 --- a/Oxide.Ext.Discord/Plugins/Setup/PluginFieldResult.cs +++ b/Oxide.Ext.Discord/Plugins/Setup/PluginFieldResult.cs @@ -2,20 +2,19 @@ using Oxide.Ext.Discord.Attributes; using Oxide.Ext.Discord.Extensions; -namespace Oxide.Ext.Discord.Plugins -{ - internal struct PluginFieldResult where T : BaseDiscordAttribute - { - private readonly MemberInfo _member; - private readonly T _attribute; - public bool IsValid => _member != null && _attribute != null; +namespace Oxide.Ext.Discord.Plugins; - public PluginFieldResult(MemberInfo member, T attribute) - { - _member = member; - _attribute = attribute; - } +internal readonly struct PluginFieldResult where T : BaseDiscordAttribute +{ + private readonly MemberInfo _member; + private readonly T _attribute; + public bool IsValid => _member != null && _attribute != null; - public void SetValue(object instance, object value) => _member.SetMemberValue(instance, value); + public PluginFieldResult(MemberInfo member, T attribute) + { + _member = member; + _attribute = attribute; } + + public void SetValue(object instance, object value) => _member.SetMemberValue(instance, value); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Setup/PluginHookResult.cs b/Oxide.Ext.Discord/Plugins/Setup/PluginHookResult.cs index 266b7ebc0..fe400ea81 100644 --- a/Oxide.Ext.Discord/Plugins/Setup/PluginHookResult.cs +++ b/Oxide.Ext.Discord/Plugins/Setup/PluginHookResult.cs @@ -1,20 +1,19 @@ using System.Reflection; using Oxide.Ext.Discord.Attributes; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +internal readonly struct PluginHookResult where T : BaseDiscordAttribute { - internal struct PluginHookResult where T : BaseDiscordAttribute - { - public readonly string Name; - public readonly MethodInfo Method; - public readonly T Attribute; - public bool IsValid => !string.IsNullOrEmpty(Name) && Attribute != null; + public readonly string Name; + public readonly MethodInfo Method; + public readonly T Attribute; + public bool IsValid => !string.IsNullOrEmpty(Name) && Attribute != null; - public PluginHookResult(PluginCallback callback, T attribute) - { - Name = callback.Name; - Method = callback.Method; - Attribute = attribute; - } + public PluginHookResult(PluginCallback callback, T attribute) + { + Name = callback.Name; + Method = callback.Method; + Attribute = attribute; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Plugins/Setup/PluginSetup.cs b/Oxide.Ext.Discord/Plugins/Setup/PluginSetup.cs index 315c3bb5b..8f6851b68 100644 --- a/Oxide.Ext.Discord/Plugins/Setup/PluginSetup.cs +++ b/Oxide.Ext.Discord/Plugins/Setup/PluginSetup.cs @@ -7,165 +7,157 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Plugins +namespace Oxide.Ext.Discord.Plugins; + +/// +/// Build Discord Extension Setup Data for a plugin +/// +public class PluginSetup { + internal readonly string PluginName; + + internal readonly List PluginHooks = []; + private readonly List _callbacks = []; + //private readonly List _fields = new List(0); + /// - /// Build Discord Extension Setup Data for a plugin + /// Constructor /// - public class PluginSetup + /// Plugin the data is for + /// Logger + public PluginSetup(Plugin plugin, ILogger logger) { - internal readonly Plugin Plugin; - internal readonly string PluginName; - - internal readonly List PluginHooks = new List(0); - internal readonly List GlobalHooks = new List(0); - private readonly List _callbacks = new List(0); - //private readonly List _fields = new List(0); - - /// - /// Constructor - /// - /// Plugin the data is for - /// Logger - public PluginSetup(Plugin plugin, ILogger logger) + if (plugin == null) throw new ArgumentNullException(nameof(plugin)); + PluginName = plugin.Name; + MemberInfo[] methods = plugin.GetType().GetMembers(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + for (int index = 0; index < methods.Length; index++) { - Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin)); - PluginName = Plugin.Name; - MemberInfo[] methods = plugin.GetType().GetMembers(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - for (int index = 0; index < methods.Length; index++) + MemberInfo member = methods[index]; + Attribute[] attributes = Attribute.GetCustomAttributes(member); + switch (member) { - MemberInfo member = methods[index]; - Attribute[] attributes = Attribute.GetCustomAttributes(member); - switch (member) + case MethodInfo hook: { - case MethodInfo hook: - { - ProcessMethod(hook, attributes, logger); - break; - } - - // case FieldInfo _: - // case PropertyInfo _: - // if (IsFieldAttribute(attributes)) - // { - // logger.Verbose("Adding Plugin Field: {0}.{1}", Plugin.Name, member.Name); - // _fields.Add(new PluginField(member, attributes)); - // } - // break; + ProcessMethod(plugin, hook, attributes, logger); + break; } + + // case FieldInfo _: + // case PropertyInfo _: + // if (IsFieldAttribute(attributes)) + // { + // logger.Verbose("Adding Plugin Field: {0}.{1}", Plugin.Name, member.Name); + // _fields.Add(new PluginField(member, attributes)); + // } + // break; } } + } - private void ProcessMethod(MethodInfo hook, Attribute[] attributes, ILogger logger) + private void ProcessMethod(Plugin plugin, MethodInfo hook, Attribute[] attributes, ILogger logger) + { + if (!ParseHook(hook, attributes, out string name)) { - if (!ParseHook(hook, attributes, out string name)) - { - return; - } + return; + } - if (DiscordExtHooks.IsDiscordHook(name)) + if (DiscordExtHooks.IsDiscordHook(name)) + { + if (!DiscordExtHooks.IsGlobalHook(name)) { - if (DiscordExtHooks.IsGlobalHook(name)) - { - GlobalHooks.Add(name); - logger.Verbose("Adding Global Hook: {0}.{1}", Plugin.Name, name); - } - else - { - PluginHooks.Add(name); - logger.Verbose("Adding Plugin Hook: {0}.{1}", Plugin.Name, name); - } + PluginHooks.Add(name); + logger.Verbose("Adding Plugin Hook: {0}.{1}", plugin.Name, name); } + } - if (IsCallbackMethod(attributes)) - { - logger.Verbose("Adding Callback Hook: {0}.{1}", Plugin.Name, name); - _callbacks.Add(new PluginCallback(name, hook, attributes)); - } + if (IsCallbackMethod(attributes)) + { + logger.Verbose("Adding Callback Hook: {0}.{1}", plugin.Name, name); + _callbacks.Add(new PluginCallback(name, hook, attributes)); } + } - private bool ParseHook(MethodInfo info, Attribute[] attributes, out string name) + private bool ParseHook(MethodInfo info, Attribute[] attributes, out string name) + { + name = !info.IsPublic ? info.Name : null; + HookMethodAttribute hook = GetAttribute(attributes); + if (hook != null) { - name = !info.IsPublic ? info.Name : null; - HookMethodAttribute hook = GetAttribute(attributes); - if (hook != null) - { - name = hook.Name; - } - - return name != null; + name = hook.Name; } - private T GetAttribute(Attribute[] attributes) where T : Attribute + return name != null; + } + + private T GetAttribute(Attribute[] attributes) where T : Attribute + { + for (int index = 0; index < attributes.Length; index++) { - for (int index = 0; index < attributes.Length; index++) + Attribute attribute = attributes[index]; + if (attribute is T type) { - Attribute attribute = attributes[index]; - if (attribute is T type) - { - return type; - } + return type; } - - return null; } - private bool IsCallbackMethod(Attribute[] attributes) + return null; + } + + private bool IsCallbackMethod(Attribute[] attributes) + { + for (int index = 0; index < attributes.Length; index++) { - for (int index = 0; index < attributes.Length; index++) + Attribute attribute = attributes[index]; + switch (attribute) { - Attribute attribute = attributes[index]; - switch (attribute) - { - case BaseApplicationCommandAttribute _: - case BaseCommandAttribute _: - return true; - } + case BaseApplicationCommandAttribute _: + case BaseCommandAttribute _: + return true; } - - return false; } - // private bool IsFieldAttribute(Attribute[] attributes) - // { - // for (int index = 0; index < attributes.Length; index++) - // { - // Attribute attribute = attributes[index]; - // switch (attribute) - // { - // case DiscordPoolAttribute _: - // return true; - // } - // } - // - // return false; - // } + return false; + } + + // private bool IsFieldAttribute(Attribute[] attributes) + // { + // for (int index = 0; index < attributes.Length; index++) + // { + // Attribute attribute = attributes[index]; + // switch (attribute) + // { + // case DiscordPoolAttribute _: + // return true; + // } + // } + // + // return false; + // } - internal IEnumerable> GetCallbacksWithAttribute() where T : BaseDiscordAttribute + internal IEnumerable> GetCallbacksWithAttribute() where T : BaseDiscordAttribute + { + for (int index = 0; index < _callbacks.Count; index++) { - for (int index = 0; index < _callbacks.Count; index++) + PluginCallback callback = _callbacks[index]; + foreach (T attribute in callback.GetAttributes()) { - PluginCallback callback = _callbacks[index]; - foreach (T attribute in callback.GetAttributes()) - { - yield return new PluginHookResult(callback, attribute); - } + yield return new PluginHookResult(callback, attribute); } } - - // internal PluginFieldResult GetFieldWthAttribute() where T : BaseDiscordAttribute - // { - // for (int index = 0; index < _fields.Count; index++) - // { - // PluginField field = _fields[index]; - // T attribute = field.GetAttribute(); - // if (attribute != null) - // { - // return new PluginFieldResult(field.Member, attribute); - // } - // } - // - // return default(PluginFieldResult); - // } } + + // internal PluginFieldResult GetFieldWthAttribute() where T : BaseDiscordAttribute + // { + // for (int index = 0; index < _fields.Count; index++) + // { + // PluginField field = _fields[index]; + // T attribute = field.GetAttribute(); + // if (attribute != null) + // { + // return new PluginFieldResult(field.Member, attribute); + // } + // } + // + // return default(PluginFieldResult); + // } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Rest/Buckets/Bucket.cs b/Oxide.Ext.Discord/Rest/Buckets/Bucket.cs index 6ee4280c6..b5333c4f0 100644 --- a/Oxide.Ext.Discord/Rest/Buckets/Bucket.cs +++ b/Oxide.Ext.Discord/Rest/Buckets/Bucket.cs @@ -12,376 +12,375 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Rest +namespace Oxide.Ext.Discord.Rest; + +/// +/// Contains bucket information for a REST API Bucket +/// +public class Bucket : BasePoolable, IDebugLoggable { /// - /// Contains bucket information for a REST API Bucket + /// The ID of this bucket which is based on the route /// - public class Bucket : BasePoolable, IDebugLoggable - { - /// - /// The ID of this bucket which is based on the route - /// - internal BucketId Id; - - /// - /// The number of requests that can be made per rate limit reset - /// - internal int Limit; - - /// - /// How many requests are remaining before hitting the rate limit for the bucket - /// - internal volatile int Remaining; - - /// - /// How long until the rate limit resets - /// - internal DateTimeOffset ResetAt; - - internal bool IsKnownBucket; - - private RestRateLimit _rateLimit; - private ILogger _logger; - private RestHandler _rest; + internal BucketId Id; + + /// + /// The number of requests that can be made per rate limit reset + /// + internal int Limit; + + /// + /// How many requests are remaining before hitting the rate limit for the bucket + /// + internal volatile int Remaining; + + /// + /// How long until the rate limit resets + /// + internal DateTimeOffset ResetAt; + + internal bool IsKnownBucket; + + private RestRateLimit _rateLimit; + private ILogger _logger; + private RestHandler _rest; - private readonly SemaphoreSlim _requestSync = new SemaphoreSlim(1, 1); - private readonly object _completedSync = new object(); - internal readonly AdjustableSemaphore ActiveRequestsSemaphore = new AdjustableSemaphore(1); - private readonly DiscordConcurrentQueue _requestQueue = new DiscordConcurrentQueue(); - private readonly ConcurrentDictionary _activeRequests = new ConcurrentDictionary(); - private readonly HashSet _routes = new HashSet(); - - private bool _isShutdown; - - /// - /// Creates a new bucket for the given - /// - /// ID of the bucket. If not a known bucket then will be part of the route. If know bucket will be the Discord bucket ID - /// The handler that owns this Bucket - /// Logger for this bucket - public void Init(BucketId bucketId, RestHandler rest, ILogger logger) + private readonly SemaphoreSlim _requestSync = new(1, 1); + private readonly object _completedSync = new(); + internal readonly AdjustableSemaphore ActiveRequestsSemaphore = new(1); + private readonly DiscordConcurrentQueue _requestQueue = new(); + private readonly ConcurrentDictionary _activeRequests = new(); + private readonly HashSet _routes = new(); + + private bool _isShutdown; + + /// + /// Creates a new bucket for the given + /// + /// ID of the bucket. If not a known bucket, then it will be part of the route. If known bucket, it will be the Discord bucket ID + /// The handler that owns this Bucket + /// Logger for this bucket + public void Init(BucketId bucketId, RestHandler rest, ILogger logger) + { + Id = bucketId; + _rest = rest; + _rateLimit = rest.RateLimit; + _logger = logger; + _logger.Debug($"{nameof(Bucket)}.{nameof(Init)} Bucket Created: {{0}}", Id); + ActiveRequestsSemaphore.Reset(); + Limit = 1; + Remaining = 1; + ResetAt = DateTimeOffset.MinValue; + _routes.Add(bucketId.Id); + } + + /// + /// Queues a new request for the bucket + /// + /// to be queued + public void QueueRequest(RequestHandler handler) + { + BaseRequest request = handler.Request; + request.Bucket?.DequeueRequest(handler); + request.Bucket = this; + if (handler.Request.Status == RequestStatus.InQueue) { - Id = bucketId; - _rest = rest; - _rateLimit = rest.RateLimit; - _logger = logger; - _logger.Debug($"{nameof(Bucket)}.{nameof(Init)} Bucket Created: {{0}}", Id); - ActiveRequestsSemaphore.Reset(); - Limit = 1; - Remaining = 1; - ResetAt = DateTimeOffset.MinValue; - _routes.Add(bucketId.Id); + _requestQueue.Add(handler); } - - /// - /// Queues a new request for the bucket - /// - /// to be queued - public void QueueRequest(RequestHandler handler) + else { - BaseRequest request = handler.Request; - request.Bucket?.DequeueRequest(handler); - request.Bucket = this; - if (handler.Request.Status == RequestStatus.InQueue) - { - _requestQueue.Add(handler); - } - else - { - _activeRequests.TryAdd(handler.Request.Id, handler); - } - - if (ResetAt < DateTimeOffset.UtcNow) - { - Remaining = Limit; - } - - CheckPendingRequests(); - _logger.Debug("Queued Request Bucket ID: {0} Request ID: {1} Requests: {2} Queued: {3}", Id, request.Id, request.Method, request.Route, _activeRequests.Count, _requestQueue.Count); + _activeRequests.TryAdd(handler.Request.Id, handler); } - private void CheckPendingRequests() + if (ResetAt < DateTimeOffset.UtcNow) { - while(_activeRequests.Count < Limit && _requestQueue.TryTake(out RequestHandler handler)) - { - _activeRequests[handler.Request.Id] = handler; - handler.StartRequest(); - } + Remaining = Limit; } + + CheckPendingRequests(); + _logger.Debug("Queued Request Bucket ID: {0} Request ID: {1} Requests: {2} Queued: {3}", Id, request.Id, request.Method, request.Route, _activeRequests.Count, _requestQueue.Count); + } - private void DequeueRequest(RequestHandler handler) + private void CheckPendingRequests() + { + while(_activeRequests.Count < Limit && _requestQueue.TryTake(out RequestHandler handler)) { - _activeRequests.TryRemove(handler.Request.Id, out RequestHandler _); - _requestQueue.Remove(handler); + _activeRequests[handler.Request.Id] = handler; + handler.StartRequest(); } + } + + private void DequeueRequest(RequestHandler handler) + { + _activeRequests.TryRemove(handler.Request.Id, out RequestHandler _); + _requestQueue.Remove(handler); + } - internal void Merge(Bucket data) - { - List handlers = DiscordPool.Internal.GetList(); - handlers.AddRange(data._activeRequests.Values); + internal void Merge(Bucket data) + { + List handlers = DiscordPool.Internal.GetList(); + handlers.AddRange(data._activeRequests.Values); - foreach (RequestHandler handler in handlers) - { - QueueRequest(handler); - } + foreach (RequestHandler handler in handlers) + { + QueueRequest(handler); + } - data._activeRequests.Clear(); + data._activeRequests.Clear(); - handlers.Clear(); - foreach (RequestHandler handler in data._requestQueue) - { - handlers.Add(handler); - } + handlers.Clear(); + foreach (RequestHandler handler in data._requestQueue) + { + handlers.Add(handler); + } - foreach (RequestHandler handler in handlers) - { - QueueRequest(handler); - } + foreach (RequestHandler handler in handlers) + { + QueueRequest(handler); + } - DiscordPool.Internal.FreeList(handlers); + DiscordPool.Internal.FreeList(handlers); - foreach (string route in data._routes) - { - _routes.Add(route); - } + foreach (string route in data._routes) + { + _routes.Add(route); } + } - internal async ValueTask WaitUntilBucketAvailable(RequestHandler handler, CancellationToken token) - { - BaseRequest request = handler.Request; - DiscordClient client = request.Client; + internal async ValueTask WaitUntilBucketAvailable(RequestHandler handler, CancellationToken token) + { + BaseRequest request = handler.Request; + DiscordClient client = request.Client; - if (_isShutdown) - { - return; - } + if (_isShutdown) + { + return; + } - if (request.Options.IgnoreRateLimit) - { - return; - } + if (request.Options.IgnoreRateLimit) + { + return; + } - await _requestSync.WaitAsync(token).ConfigureAwait(false); + await _requestSync.WaitAsync(token).ConfigureAwait(false); - try + try + { + while (true) { - while (true) + if (_rateLimit.HasReachedRateLimit) { - if (_rateLimit.HasReachedRateLimit) - { - DateTimeOffset resetAt = _rateLimit.NextReset(); - _logger.Debug($"{nameof(Bucket)}.{nameof(WaitUntilBucketAvailable)} Plugin: {{0}} Bucket ID: {{1}} Request ID: {{2}} Can't Start Request Due to Global Rate Limit Method: {{3}} Url: {{4}} Waiting For: {{5}} Seconds", client.PluginName, Id, request.Id, request.Method, request.Route, (resetAt - DateTimeOffset.UtcNow).TotalSeconds); - await resetAt.DelayUntil(token).ConfigureAwait(false); - continue; - } - - if ((Limit == 0 || Remaining == 0) && ResetAt > DateTimeOffset.UtcNow) - { - _logger.Debug($"{nameof(Bucket)}.{nameof(WaitUntilBucketAvailable)} Plugin: {{0}} Bucket ID: {{1}} Request ID: {{2}} Can't Start Request Due to Bucket Rate Limit Method: {{3}} Url: {{4}} Limit: {{5}} Remaining: {{6}} Waiting For: {{7}} Seconds", client.PluginName, Id, request.Id, request.Method, request.Route, Limit, Remaining, (ResetAt - DateTimeOffset.UtcNow).TotalSeconds); - await ResetAt.DelayUntil(token).ConfigureAwait(false); - continue; - } - - if (Remaining < 0) - { - _logger.Debug($"{nameof(Bucket)}.{nameof(WaitUntilBucketAvailable)} Plugin: {{0}} Bucket ID: {{1}} Request ID: {{2}} Can't Start Request Due to Remaining < 0: {{3}} Url: {{4}} Limit: {{5}} Remaining: {{6}} Waiting For: {{7}} Seconds", client.PluginName, Id, request.Id, request.Method, request.Route, Limit, Remaining, (ResetAt - DateTimeOffset.UtcNow).TotalSeconds); - await ResetAt.DelayUntil(100, token).ConfigureAwait(false); - continue; - } - - _logger.Debug($"{nameof(Bucket)}.{nameof(WaitUntilBucketAvailable)} Plugin: {{0}} Bucket ID: {{1}} Request ID: {{2}} Can Start Request: Bucket: {{3}}/{{4}} Reset In: {{5}}", client.PluginName, Id, request.Id, Remaining, Limit, (ResetAt - DateTimeOffset.UtcNow).TotalSeconds); - break; + DateTimeOffset resetAt = _rateLimit.NextReset(); + _logger.Debug($"{nameof(Bucket)}.{nameof(WaitUntilBucketAvailable)} Plugin: {{0}} Bucket ID: {{1}} Request ID: {{2}} Can't Start Request Due to Global Rate Limit Method: {{3}} Url: {{4}} Waiting For: {{5}} Seconds", client.PluginName, Id, request.Id, request.Method, request.Route, (resetAt - DateTimeOffset.UtcNow).TotalSeconds); + await resetAt.DelayUntil(token).ConfigureAwait(false); + continue; } - - OnRequestStarted(handler); - } - finally - { - _requestSync.Release(); + + if ((Limit == 0 || Remaining == 0) && ResetAt > DateTimeOffset.UtcNow) + { + _logger.Debug($"{nameof(Bucket)}.{nameof(WaitUntilBucketAvailable)} Plugin: {{0}} Bucket ID: {{1}} Request ID: {{2}} Can't Start Request Due to Bucket Rate Limit Method: {{3}} Url: {{4}} Limit: {{5}} Remaining: {{6}} Waiting For: {{7}} Seconds", client.PluginName, Id, request.Id, request.Method, request.Route, Limit, Remaining, (ResetAt - DateTimeOffset.UtcNow).TotalSeconds); + await ResetAt.DelayUntil(token).ConfigureAwait(false); + continue; + } + + if (Remaining < 0) + { + _logger.Debug($"{nameof(Bucket)}.{nameof(WaitUntilBucketAvailable)} Plugin: {{0}} Bucket ID: {{1}} Request ID: {{2}} Can't Start Request Due to Remaining < 0: {{3}} Url: {{4}} Limit: {{5}} Remaining: {{6}} Waiting For: {{7}} Seconds", client.PluginName, Id, request.Id, request.Method, request.Route, Limit, Remaining, (ResetAt - DateTimeOffset.UtcNow).TotalSeconds); + await ResetAt.DelayUntil(100, token).ConfigureAwait(false); + continue; + } + + _logger.Debug($"{nameof(Bucket)}.{nameof(WaitUntilBucketAvailable)} Plugin: {{0}} Bucket ID: {{1}} Request ID: {{2}} Can Start Request: Bucket: {{3}}/{{4}} Reset In: {{5}}", client.PluginName, Id, request.Id, Remaining, Limit, (ResetAt - DateTimeOffset.UtcNow).TotalSeconds); + break; } + + OnRequestStarted(handler); + } + finally + { + _requestSync.Release(); } + } - private void OnRequestStarted(RequestHandler handler) + private void OnRequestStarted(RequestHandler handler) + { + if (!handler.Request.Options.IgnoreRateLimit) { - if (!handler.Request.Options.IgnoreRateLimit) - { - Interlocked.Decrement(ref Remaining); - _rateLimit.FiredRequest(); - _logger.Debug($"{nameof(Bucket)}.{nameof(OnRequestStarted)} ID: {{0}} Has Started Bucket {{1}}/{{2}}", handler.Request.Id, Remaining, Limit); - } + Interlocked.Decrement(ref Remaining); + _rateLimit.FiredRequest(); + _logger.Debug($"{nameof(Bucket)}.{nameof(OnRequestStarted)} ID: {{0}} Has Started Bucket {{1}}/{{2}}", handler.Request.Id, Remaining, Limit); } + } - internal void OnRequestCompleted(RequestHandler handler, RequestResponse response) - { - RateLimitResponse rateLimit = response.RateLimit; + internal void OnRequestCompleted(RequestHandler handler, RequestResponse response) + { + RateLimitResponse rateLimit = response.RateLimit; - if (_isShutdown) - { - return; - } + if (_isShutdown) + { + return; + } - if (!_activeRequests.TryRemove(handler.Request.Id, out RequestHandler _)) - { - _logger.Warning("Failed to remove request from bucket!!! Bucket ID: {0} Request ID: {1} Method: {2} Route: {3} Status: {4}", Id, handler.Request.Id, handler.Request.Method, handler.Request.Route, handler.Request.Status); - } + if (!_activeRequests.TryRemove(handler.Request.Id, out RequestHandler _)) + { + _logger.Warning("Failed to remove request from bucket!!! Bucket ID: {0} Request ID: {1} Method: {2} Route: {3} Status: {4}", Id, handler.Request.Id, handler.Request.Method, handler.Request.Route, handler.Request.Status); + } - lock (_completedSync) + lock (_completedSync) + { + if (!handler.Request.Options.IgnoreRateLimit && !IsKnownBucket && rateLimit is {BucketId.IsValid: true}) { - if (!handler.Request.Options.IgnoreRateLimit && !IsKnownBucket && rateLimit != null && rateLimit.BucketId.IsValid) + _rest.UpgradeToKnownBucket(this, rateLimit.BucketId); + if (!IsKnownBucket) { - _rest.UpgradeToKnownBucket(this, rateLimit.BucketId); - if (!IsKnownBucket) - { - ActiveRequestsSemaphore.AllowAllThrough(); - } + ActiveRequestsSemaphore.AllowAllThrough(); } + } - CheckPendingRequests(); + CheckPendingRequests(); - if (_activeRequests.Count == 0) - { - OnBucketCompleted(); - } + if (_activeRequests.Count == 0) + { + OnBucketCompleted(); } } + } - internal void UpdateRateLimits(RequestHandler handler, RequestResponse response) - { - BaseRequest request = handler.Request; - RateLimitResponse rateLimit = response.RateLimit; + internal void UpdateRateLimits(RequestHandler handler, RequestResponse response) + { + BaseRequest request = handler.Request; + RateLimitResponse rateLimit = response.RateLimit; - if (rateLimit == null) - { - return; - } + if (rateLimit == null) + { + return; + } - if (request.Options.IgnoreRateLimit) - { - return; - } + if (request.Options.IgnoreRateLimit) + { + return; + } - if (rateLimit.IsGlobalRateLimit) - { - _rateLimit.ReachedRateLimit(rateLimit.ResetAt); - } + if (rateLimit.IsGlobalRateLimit) + { + _rateLimit.ReachedRateLimit(rateLimit.ResetAt); + } - if (request.Client.Logger.IsLogging(DiscordLogLevel.Verbose)) - { - request.Client.Logger.Verbose($"{nameof(Bucket)}.{nameof(UpdateRateLimits)} Pre Bucket ID: {{0}} Scope: {{1}} Request ID: {{2}} Limit: {{3}} Remaining: {{4}} Reset: {{5}} Reset In: {{6}}s Rate Limit Bucket ID: {{7}}", Id, rateLimit.Scope, request.Id, Limit, Remaining, ResetAt, (ResetAt - DateTimeOffset.UtcNow).TotalSeconds, rateLimit.BucketId); - } + if (request.Client.Logger.IsLogging(DiscordLogLevel.Verbose)) + { + request.Client.Logger.Verbose($"{nameof(Bucket)}.{nameof(UpdateRateLimits)} Pre Bucket ID: {{0}} Scope: {{1}} Request ID: {{2}} Limit: {{3}} Remaining: {{4}} Reset: {{5}} Reset In: {{6}}s Rate Limit Bucket ID: {{7}}", Id, rateLimit.Scope, request.Id, Limit, Remaining, ResetAt, (ResetAt - DateTimeOffset.UtcNow).TotalSeconds, rateLimit.BucketId); + } - DateTimeOffset currentResetAt = ResetAt; - if (rateLimit.ResetAt > currentResetAt) - { - ResetAt = rateLimit.ResetAt; - //Ensure the ResetAt really is Greater - if (rateLimit.ResetAt > currentResetAt + TimeSpan.FromMilliseconds(250) || Limit != rateLimit.Limit) - { - Limit = rateLimit.Limit; - Interlocked.Exchange(ref Remaining, rateLimit.Remaining); - } - } - else + DateTimeOffset currentResetAt = ResetAt; + if (rateLimit.ResetAt > currentResetAt) + { + ResetAt = rateLimit.ResetAt; + //Ensure the ResetAt really is Greater + if (rateLimit.ResetAt > currentResetAt + TimeSpan.FromMilliseconds(250) || Limit != rateLimit.Limit) { - Interlocked.Exchange(ref Remaining, Math.Min(Remaining, rateLimit.Remaining)); + Limit = rateLimit.Limit; + Interlocked.Exchange(ref Remaining, rateLimit.Remaining); } + } + else + { + Interlocked.Exchange(ref Remaining, Math.Min(Remaining, rateLimit.Remaining)); + } - if (ActiveRequestsSemaphore.MaximumCount != rateLimit.Limit) - { - ActiveRequestsSemaphore.MaximumCount = Math.Max(rateLimit.Limit, 1); - } + if (ActiveRequestsSemaphore.MaximumCount != rateLimit.Limit) + { + ActiveRequestsSemaphore.MaximumCount = Math.Max(rateLimit.Limit, 1); + } - if(request.Client.Logger.IsLogging(DiscordLogLevel.Verbose)) - { - request.Client.Logger.Verbose($"{nameof(Bucket)}.{nameof(UpdateRateLimits)} Post Bucket ID: {{0}} Scope: {{1}} Request ID: {{2}} Limit: {{3}} Remaining: {{4}} Reset: {{5}} Reset In: {{6}}s Rate Limit Bucket ID: {{7}}", Id, rateLimit.Scope, request.Id, Limit, Remaining, ResetAt, (ResetAt - DateTimeOffset.UtcNow).TotalSeconds, rateLimit.BucketId); - } + if(request.Client.Logger.IsLogging(DiscordLogLevel.Verbose)) + { + request.Client.Logger.Verbose($"{nameof(Bucket)}.{nameof(UpdateRateLimits)} Post Bucket ID: {{0}} Scope: {{1}} Request ID: {{2}} Limit: {{3}} Remaining: {{4}} Reset: {{5}} Reset In: {{6}}s Rate Limit Bucket ID: {{7}}", Id, rateLimit.Scope, request.Id, Limit, Remaining, ResetAt, (ResetAt - DateTimeOffset.UtcNow).TotalSeconds, rateLimit.BucketId); } + } - internal void AbortClientRequests(DiscordClient client) + internal void AbortClientRequests(DiscordClient client) + { + List handlers = DiscordPool.Internal.GetList(); + foreach (RequestHandler handler in _requestQueue) { - List handlers = DiscordPool.Internal.GetList(); - foreach (RequestHandler handler in _requestQueue) + if (handler.Request.Client.PluginId == client.PluginId) { - if (handler.Request.Client.PluginId == client.PluginId) - { - handlers.Add(handler); - } + handlers.Add(handler); } + } - _requestQueue.RemoveAll(r => handlers.Contains(r)); - foreach (RequestHandler handler in handlers) - { - handler.Abort(); - handler.Dispose(); - } + _requestQueue.RemoveAll(r => handlers.Contains(r)); + foreach (RequestHandler handler in handlers) + { + handler.Abort(); + handler.Dispose(); + } - DiscordPool.Internal.FreeList(handlers); + DiscordPool.Internal.FreeList(handlers); - _activeRequests.RemoveAll(h => h.Request.Client.PluginId == client.PluginId, h => - { - h.Abort(); - h.Dispose(); - }); - } + _activeRequests.RemoveAll(h => h.Request.Client.PluginId == client.PluginId, h => + { + h.Abort(); + h.Dispose(); + }); + } - private void OnBucketCompleted() + private void OnBucketCompleted() + { + if (!IsKnownBucket) { - if (!IsKnownBucket) - { - _logger.Debug($"{nameof(Bucket)}.{nameof(OnBucketCompleted)} Bucket Completed: {{0}}", Id); - _rest.RemoveBucket(this); - } + _logger.Debug($"{nameof(Bucket)}.{nameof(OnBucketCompleted)} Bucket Completed: {{0}}", Id); + _rest.RemoveBucket(this); } + } - internal void ShutDown() + internal void ShutDown() + { + _logger.Debug("Shutting down bucket ID: {0}", Id); + foreach (RequestHandler handler in _requestQueue) { - _logger.Debug("Shutting down bucket ID: {0}", Id); - foreach (RequestHandler handler in _requestQueue) - { - handler.Abort(); - handler.Dispose(); - } + handler.Abort(); + handler.Dispose(); + } - _requestQueue.Clear(); + _requestQueue.Clear(); - foreach (RequestHandler handler in _activeRequests.Values) - { - handler.Abort(); - handler.Dispose(); - } - - _activeRequests.Clear(); - _isShutdown = true; - } - - /// - protected override void LeavePool() + foreach (RequestHandler handler in _activeRequests.Values) { - _isShutdown = false; + handler.Abort(); + handler.Dispose(); } + + _activeRequests.Clear(); + _isShutdown = true; + } - /// - protected override void EnterPool() - { - ActiveRequestsSemaphore.AllowAllThrough(); - } + /// + protected override void LeavePool() + { + _isShutdown = false; + } - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendField("ID", Id.Id); - logger.AppendField("Known Bucket", IsKnownBucket); - logger.AppendField("Remaining", Remaining); - logger.AppendField("Limit", Limit); - logger.AppendField("Reset At", ResetAt.ToString()); - logger.AppendField("Reset In", ((ResetAt - DateTimeOffset.UtcNow).TotalSeconds).ToString(CultureInfo.InvariantCulture), "Seconds"); - logger.AppendField("Active Count", _activeRequests.Count); - logger.AppendField("Queue Count", _requestQueue.Count); - logger.AppendFieldOutOf("Semaphore", ActiveRequestsSemaphore.Available, ActiveRequestsSemaphore.MaximumCount); - logger.AppendList("Routes", _routes); - logger.AppendList("Active Requests", _activeRequests.Values); - logger.AppendList("Queued Requests", _requestQueue); - } + /// + protected override void EnterPool() + { + ActiveRequestsSemaphore.AllowAllThrough(); + } + + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("ID", Id.Id); + logger.AppendField("Known Bucket", IsKnownBucket); + logger.AppendField("Remaining", Remaining); + logger.AppendField("Limit", Limit); + logger.AppendField("Reset At", ResetAt.ToString()); + logger.AppendField("Reset In", ((ResetAt - DateTimeOffset.UtcNow).TotalSeconds).ToString(CultureInfo.InvariantCulture), "Seconds"); + logger.AppendField("Active Count", _activeRequests.Count); + logger.AppendField("Queue Count", _requestQueue.Count); + logger.AppendFieldOutOf("Semaphore", ActiveRequestsSemaphore.Available, ActiveRequestsSemaphore.MaximumCount); + logger.AppendList("Routes", _routes); + logger.AppendList("Active Requests", _activeRequests.Values); + logger.AppendList("Queued Requests", _requestQueue); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Rest/Buckets/BucketId.cs b/Oxide.Ext.Discord/Rest/Buckets/BucketId.cs index 74d6696fa..8bb119201 100644 --- a/Oxide.Ext.Discord/Rest/Buckets/BucketId.cs +++ b/Oxide.Ext.Discord/Rest/Buckets/BucketId.cs @@ -1,58 +1,32 @@ using System; -namespace Oxide.Ext.Discord.Rest +namespace Oxide.Ext.Discord.Rest; + +/// +/// Represents an ID for a bucket +/// +public readonly record struct BucketId { /// - /// Represents an ID for a bucket + /// ID of the bucket /// - public struct BucketId : IEquatable - { - /// - /// ID of the bucket - /// - public readonly string Id; + public readonly string Id; - /// - /// If the bucket ID is valid - /// - public bool IsValid => !string.IsNullOrEmpty(Id); - - /// - /// Constructor - /// - /// ID of the bucket - /// Thrown if ID is null or empty - public BucketId(string id) - { - Id = !string.IsNullOrEmpty(id) ? id : throw new ArgumentNullException(nameof(id)); - } - - /// - public bool Equals(BucketId other) => Id == other.Id; - - /// - public override bool Equals(object obj) => obj is BucketId other && Equals(other); - - /// - public override int GetHashCode() => Id != null ? Id.GetHashCode() : 0; + /// + /// If the bucket ID is valid + /// + public bool IsValid => !string.IsNullOrEmpty(Id); - /// - public override string ToString() => Id; - - /// - /// - /// - /// - /// - /// - public static bool operator == (BucketId left, BucketId right) => left.Equals(right); - - /// - /// - /// - /// - /// - /// - public static bool operator != (BucketId left, BucketId right) => !(left == right); + /// + /// Constructor + /// + /// ID of the bucket + /// Thrown if ID is null or empty + public BucketId(string id) + { + Id = !string.IsNullOrEmpty(id) ? id : throw new ArgumentNullException(nameof(id)); } + + /// + public override string ToString() => Id; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Rest/Requests/BaseRequest.cs b/Oxide.Ext.Discord/Rest/Requests/BaseRequest.cs index a17978d13..0d3e77588 100644 --- a/Oxide.Ext.Discord/Rest/Requests/BaseRequest.cs +++ b/Oxide.Ext.Discord/Rest/Requests/BaseRequest.cs @@ -11,174 +11,173 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Rest +namespace Oxide.Ext.Discord.Rest; + +/// +/// Represents a base request class for REST API calls +/// +public abstract class BaseRequest : BasePoolable, IDebugLoggable { /// - /// Represents a base request class for REST API calls + /// ID of the request. Generated from the DateTimeOffset when the request was created /// - public abstract class BaseRequest : BasePoolable, IDebugLoggable - { - /// - /// ID of the request. Generated from the DateTimeOffset when the request was created - /// - public Snowflake Id; + public Snowflake Id; - /// - /// HTTP request method - /// - public RequestMethod Method; - - /// - /// Current status of the request - /// - public RequestStatus Status; - - /// - /// Route on the API - /// - public string Route; - - /// - /// Data to be sent with the request - /// - public object Data; - - /// - /// Options for the request - /// - public RequestOptions Options; - - /// - /// Discord Client making the request - /// - internal DiscordClient Client; - internal HttpClient HttpClient; - internal CancellationTokenSource Source; - internal Bucket Bucket; - internal bool IsCancelled => Source.IsCancellationRequested; - - /// - /// How long to wait before retrying request since there was a web exception - /// - private DateTimeOffset _errorResetAt; + /// + /// HTTP request method + /// + public RequestMethod Method; + + /// + /// Current status of the request + /// + public RequestStatus Status; + + /// + /// Route on the API + /// + public string Route; + + /// + /// Data to be sent with the request + /// + public object Data; + + /// + /// Options for the request + /// + public RequestOptions Options; + + /// + /// Discord Client making the request + /// + internal DiscordClient Client; + internal HttpClient HttpClient; + internal CancellationTokenSource Source; + internal Bucket Bucket; + internal bool IsCancelled => Source.IsCancellationRequested; + + /// + /// How long to wait before retrying request since there was a web exception + /// + private DateTimeOffset _errorResetAt; - /// - /// Logger for the request - /// - protected ILogger Logger; - - /// - /// Initializes the request - /// - protected void Init(DiscordClient client, HttpClient httpClient, RequestMethod method, string route, object data, RequestOptions options) + /// + /// Logger for the request + /// + protected ILogger Logger; + + /// + /// Initializes the request + /// + protected void Init(DiscordClient client, HttpClient httpClient, RequestMethod method, string route, object data, RequestOptions options) + { + Id = SnowflakeIdFactory.Instance.Generate(); + Client = client; + HttpClient = httpClient; + Method = method; + Route = route; + Data = data; + Options = options; + Source = new CancellationTokenSource(); + Logger = client.Logger; + Logger.Debug($"{nameof(BaseRequest)}.{nameof(Init)} Request Created Plugin: {{0}} Request ID: {{1}} Method: {{2}} Route: {{3}}", client.PluginName, Id, Method, route); + } + + internal ValueTask WaitUntilRequestCanStart(CancellationToken token) + { + if (_errorResetAt > DateTimeOffset.UtcNow) { - Id = SnowflakeIdFactory.Instance.Generate(); - Client = client; - HttpClient = httpClient; - Method = method; - Route = route; - Data = data; - Options = options; - Source = new CancellationTokenSource(); - Logger = client.Logger; - Logger.Debug($"{nameof(BaseRequest)}.{nameof(Init)} Request Created Plugin: {{0}} Request ID: {{1}} Method: {{2}} Route: {{3}}", client.PluginName, Id, Method, route); + Logger.Debug($"{nameof(BaseRequest)}.{nameof(WaitUntilRequestCanStart)} Request ID: {{0}} Can't Start Request Due to Previous Error Reset Waiting For: {{1}} Seconds", Id, (_errorResetAt - DateTimeOffset.UtcNow).TotalSeconds); + return _errorResetAt.DelayUntil(token); } + return new ValueTask(); + } - internal ValueTask WaitUntilRequestCanStart(CancellationToken token) + internal void OnRequestCompleted(RequestHandler handler, RequestResponse response) + { + if (Status == RequestStatus.Cancelled) { - if (_errorResetAt > DateTimeOffset.UtcNow) - { - Logger.Debug($"{nameof(BaseRequest)}.{nameof(WaitUntilRequestCanStart)} Request ID: {{0}} Can't Start Request Due to Previous Error Reset Waiting For: {{1}} Seconds", Id, (_errorResetAt - DateTimeOffset.UtcNow).TotalSeconds); - return _errorResetAt.DelayUntil(token); - } - return new ValueTask(); + return; } + + Status = RequestStatus.Completed; - internal void OnRequestCompleted(RequestHandler handler, RequestResponse response) + BaseRequest request = handler.Request; + switch (response.Status) { - if (Status == RequestStatus.Cancelled) - { - return; - } - - Status = RequestStatus.Completed; - - BaseRequest request = handler.Request; - switch (response.Status) - { - case RequestCompletedStatus.Success: - OnRequestSuccess(response); - break; - case RequestCompletedStatus.Cancelled: - Client.Logger.Debug($"{nameof(BaseRequest)}.{nameof(OnRequestCompleted)} Request Cancelled Bucket ID: {{0}} Request ID: {{1}} Plugin: {{2}} Method: {{3}} Route: {{4}}", Bucket.Id, request.Id, request.Client.PluginName, request.Method, request.Route); - break; - case RequestCompletedStatus.ErrorFatal: - case RequestCompletedStatus.ErrorRetry: - OnRequestError(response); - break; - } - - Bucket.OnRequestCompleted(handler, response); - Client.Logger.Debug($"{nameof(BaseRequest)}.{nameof(OnRequestCompleted)} Bucket ID: {{0}} Request ID: {{1}} Plugin: {{2}} Method: {{3}} Route: {{4}}", Bucket.Id, request.Id, request.Client.PluginName, request.Method, request.Route); + case RequestCompletedStatus.Success: + OnRequestSuccess(response); + break; + case RequestCompletedStatus.Cancelled: + Client.Logger.Debug($"{nameof(BaseRequest)}.{nameof(OnRequestCompleted)} Request Cancelled Bucket ID: {{0}} Request ID: {{1}} Plugin: {{2}} Method: {{3}} Route: {{4}}", Bucket.Id, request.Id, request.Client.PluginName, request.Method, request.Route); + break; + case RequestCompletedStatus.ErrorFatal: + case RequestCompletedStatus.ErrorRetry: + OnRequestError(response); + break; } + + Bucket.OnRequestCompleted(handler, response); + Client.Logger.Debug($"{nameof(BaseRequest)}.{nameof(OnRequestCompleted)} Bucket ID: {{0}} Request ID: {{1}} Plugin: {{2}} Method: {{3}} Route: {{4}}", Bucket.Id, request.Id, request.Client.PluginName, request.Method, request.Route); + } - /// - /// Callback for successful API Calls - /// - /// Response for the API Call - protected abstract void OnRequestSuccess(RequestResponse response); + /// + /// Callback for successful API Calls + /// + /// Response for the API Call + protected abstract void OnRequestSuccess(RequestResponse response); - /// - /// Callback for API calls that error - /// - /// Response for the error - protected abstract void OnRequestError(RequestResponse response); + /// + /// Callback for API calls that error + /// + /// Response for the error + protected abstract void OnRequestError(RequestResponse response); - internal void OnRequestErrored() - { - _errorResetAt = MathExt.Max(_errorResetAt, DateTimeOffset.UtcNow + TimeSpan.FromSeconds(1)); - Logger.Debug($"{nameof(BaseRequest)}.{nameof(OnRequestErrored)} Request ID: {{0}} Waiting For {{1}} Seconds", Id, (_errorResetAt - DateTimeOffset.UtcNow).TotalSeconds); - } + internal void OnRequestErrored() + { + _errorResetAt = MathExt.Max(_errorResetAt, DateTimeOffset.UtcNow + TimeSpan.FromSeconds(1)); + Logger.Debug($"{nameof(BaseRequest)}.{nameof(OnRequestErrored)} Request ID: {{0}} Waiting For {{1}} Seconds", Id, (_errorResetAt - DateTimeOffset.UtcNow).TotalSeconds); + } - internal virtual void Abort() + internal virtual void Abort() + { + if (!Source.IsCancellationRequested) { - if (!Source.IsCancellationRequested) - { - Source.Cancel(); - Status = RequestStatus.Cancelled; - } + Source.Cancel(); + Status = RequestStatus.Cancelled; } + } - /// - protected override void EnterPool() - { - Id = default(Snowflake); - Method = default(RequestMethod); - Status = default(RequestStatus); - Route = null; - HttpClient = null; - Data = null; - Client = null; - Source = null; - Bucket = null; - _errorResetAt = DateTimeOffset.MinValue; - Logger = null; - } + /// + protected override void EnterPool() + { + Id = default; + Method = default; + Status = default; + Route = null; + HttpClient = null; + Data = null; + Client = null; + Source = null; + Bucket = null; + _errorResetAt = DateTimeOffset.MinValue; + Logger = null; + } - /// - protected override void LeavePool() - { - Status = RequestStatus.InQueue; - } + /// + protected override void LeavePool() + { + Status = RequestStatus.InQueue; + } - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendField("ID", Id); - logger.AppendFieldEnum("Method", Method); - logger.AppendField("Route", Route); - logger.AppendFieldEnum("Status", Status); - logger.AppendField("Type", GetType().GetRealTypeName()); - } + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendField("ID", Id); + logger.AppendFieldEnum("Method", Method); + logger.AppendField("Route", Route); + logger.AppendFieldEnum("Status", Status); + logger.AppendField("Type", GetType().GetRealTypeName()); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Rest/Requests/Request.cs b/Oxide.Ext.Discord/Rest/Requests/Request.cs index e7f0ca699..96ed9a7e1 100644 --- a/Oxide.Ext.Discord/Rest/Requests/Request.cs +++ b/Oxide.Ext.Discord/Rest/Requests/Request.cs @@ -6,61 +6,60 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Rest +namespace Oxide.Ext.Discord.Rest; + +/// +/// Represents a Request that does not return data +/// +public class Request : BaseRequest { + private IPendingPromise _promise; + /// - /// Represents a Request that does not return data + /// Creates a REST API request that returns type of T from the response /// - public class Request : BaseRequest + /// for the request + /// Client making the request + /// for the request + /// HTTP web method + /// Route for the request + /// Data being passed into the request. Null if no data is passed + /// Promise for the request + /// Options for the request + /// A + public static Request CreateRequest(DiscordPluginPool pluginPool, DiscordClient client, HttpClient httpClient, RequestMethod method, string route, object data, IPendingPromise promise, RequestOptions options) { - private IPendingPromise _promise; - - /// - /// Creates a REST API request that returns type of T from the response - /// - /// for the request - /// Client making the request - /// for the request - /// HTTP web method - /// Route for the request - /// Data being passed into the request. Null if no data is passed - /// Promise for the request - /// Options for the request - /// A - public static Request CreateRequest(DiscordPluginPool pluginPool, DiscordClient client, HttpClient httpClient, RequestMethod method, string route, object data, IPendingPromise promise, RequestOptions options) - { - Request request = pluginPool.Get(); - request.Init(client, httpClient, method, route, data, options); - request._promise = promise; - return request; - } + Request request = pluginPool.Get(); + request.Init(client, httpClient, method, route, data, options); + request._promise = promise; + return request; + } - /// - protected override void OnRequestSuccess(RequestResponse response) - { - _promise.Resolve(); - } + /// + protected override void OnRequestSuccess(RequestResponse response) + { + _promise.Resolve(); + } - /// - protected override void OnRequestError(RequestResponse response) - { - _promise.Finally(response.Error.LogError); - _promise.Reject(response.Error); - } + /// + protected override void OnRequestError(RequestResponse response) + { + _promise.Finally(response.Error.LogError); + _promise.Reject(response.Error); + } - internal override void Abort() + internal override void Abort() + { + if (Status != RequestStatus.Cancelled) { - if (Status != RequestStatus.Cancelled) - { - _promise.Reject(new RequestCancelledException()); - base.Abort(); - } + _promise.Reject(new RequestCancelledException()); + base.Abort(); } + } - /// - protected override void EnterPool() - { - _promise = null; - } + /// + protected override void EnterPool() + { + _promise = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Rest/Requests/RequestCompletedStatus.cs b/Oxide.Ext.Discord/Rest/Requests/RequestCompletedStatus.cs index 7492fbec6..3c69e9e10 100644 --- a/Oxide.Ext.Discord/Rest/Requests/RequestCompletedStatus.cs +++ b/Oxide.Ext.Discord/Rest/Requests/RequestCompletedStatus.cs @@ -1,30 +1,29 @@ using Oxide.Ext.Discord.Clients; -namespace Oxide.Ext.Discord.Rest +namespace Oxide.Ext.Discord.Rest; + +/// +/// Represents the completed status for the request +/// +public enum RequestCompletedStatus : byte { /// - /// Represents the completed status for the request + /// The request completed successfully /// - public enum RequestCompletedStatus : byte - { - /// - /// The request completed successfully - /// - Success, + Success, - /// - /// The request encountered a fatal error - /// - ErrorFatal, + /// + /// The request encountered a fatal error + /// + ErrorFatal, - /// - /// The error attempt multiple times to complete the request and was unsuccessful - /// - ErrorRetry, + /// + /// The error attempt multiple times to complete the request and was unsuccessful + /// + ErrorRetry, - /// - /// The request was cancelled. The was disconnected while making the request - /// - Cancelled - } + /// + /// The request was canceled. The was disconnected while making the request + /// + Cancelled } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Rest/Requests/RequestHandler.cs b/Oxide.Ext.Discord/Rest/Requests/RequestHandler.cs index b1a3611da..7baecd2fd 100644 --- a/Oxide.Ext.Discord/Rest/Requests/RequestHandler.cs +++ b/Oxide.Ext.Discord/Rest/Requests/RequestHandler.cs @@ -11,323 +11,318 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Rest +namespace Oxide.Ext.Discord.Rest; + +/// +/// Represent a Discord API request +/// +public class RequestHandler : BasePoolable, IDebugLoggable { + internal BaseRequest Request; + + private RequestResponse _response; + private CancellationToken _token; + private ILogger _logger; + private readonly Func _runner; + /// - /// Represent a Discord API request + /// Constructor /// - public class RequestHandler : BasePoolable, IDebugLoggable + public RequestHandler() { - internal BaseRequest Request; - - private RequestResponse _response; - private CancellationToken _token; - private ILogger _logger; - private readonly Func _runner; - - /// - /// Constructor - /// - public RequestHandler() - { - _runner = RunRequest; - } + _runner = RunRequest; + } - /// - /// Creates a new - /// - /// Request to be handled by this handler - public static RequestHandler CreateRequest(BaseRequest request) - { - RequestHandler handler = request.PluginPool.Get(); - handler.Init(request, request.Client.Logger); - return handler; - } + /// + /// Creates a new + /// + /// Request to be handled by this handler + public static RequestHandler CreateRequest(BaseRequest request) + { + RequestHandler handler = request.PluginPool.Get(); + handler.Init(request, request.Client.Logger); + return handler; + } - private void Init(BaseRequest request, ILogger logger) - { - Request = request; - _token = Request.Source.Token; - _logger = logger; - } + private void Init(BaseRequest request, ILogger logger) + { + Request = request; + _token = Request.Source.Token; + _logger = logger; + } - /// - /// Starts the Request - /// - public void StartRequest() + /// + /// Starts the Request + /// + public void StartRequest() + { + if (Request.Status == RequestStatus.InQueue) { - if (Request.Status == RequestStatus.InQueue) - { - Request.Status = RequestStatus.Started; - Task.Run(_runner, _token); - } + Request.Status = RequestStatus.Started; + Task.Run(_runner, _token); } + } - private async ValueTask RunRequest() + private async ValueTask RunRequest() + { + AdjustableSemaphore semaphore = null; + try { - AdjustableSemaphore semaphore = null; - try - { - Bucket bucket = Request.Bucket; - BucketId bucketId = bucket.Id; - semaphore = bucket.ActiveRequestsSemaphore; - Request.Status = RequestStatus.PendingBucket; + Bucket bucket = Request.Bucket; + BucketId bucketId = bucket.Id; + semaphore = bucket.ActiveRequestsSemaphore; + Request.Status = RequestStatus.PendingBucket; - _logger.Debug("Waiting for bucket availability Bucket ID: {0} Request ID: {1}", bucket.Id, Request.Id); - - await semaphore.WaitOneAsync().ConfigureAwait(false); - bucket = Request.Bucket; - if (bucketId != bucket.Id) - { - _logger.Debug("Bucket ID Changed. Waiting for bucket availability again for ID: {0} Old Bucket ID: {1} New Bucket ID: {2}", Request.Id, bucketId, bucket.Id); - semaphore.Release(); - semaphore = bucket.ActiveRequestsSemaphore; - await semaphore.WaitOneAsync().ConfigureAwait(false); - } - - _logger.Debug("Request started for Bucket ID: {0} Request ID: {1}", bucket.Id, Request.Id); - _response = await FireRequest().ConfigureAwait(false); - if (_response != null) - { - Request.OnRequestCompleted(this, _response); - } + _logger.Debug("Waiting for bucket availability Bucket ID: {0} Request ID: {1}", bucket.Id, Request.Id); - _logger.Debug("Request callback completed successfully for Bucket ID: {0} Request ID: {1}", bucket.Id, Request.Id); - } - catch (Exception ex) + await semaphore.WaitOneAsync().ConfigureAwait(false); + bucket = Request.Bucket; + if (bucketId != bucket.Id) { - _logger.Exception("Request callback threw exception for Bucket ID: {0} Request ID: {1}", Request.Id, Request.Id, ex); + _logger.Debug("Bucket ID Changed. Waiting for bucket availability again for ID: {0} Old Bucket ID: {1} New Bucket ID: {2}", Request.Id, bucketId, bucket.Id); + semaphore.Release(); + semaphore = bucket.ActiveRequestsSemaphore; + await semaphore.WaitOneAsync().ConfigureAwait(false); } - finally + + _logger.Debug("Request started for Bucket ID: {0} Request ID: {1}", bucket.Id, Request.Id); + _response = await FireRequest().ConfigureAwait(false); + if (_response != null) { - semaphore?.Release(); + Request.OnRequestCompleted(this, _response); } - - Dispose(); + + _logger.Debug("Request callback completed successfully for Bucket ID: {0} Request ID: {1}", bucket.Id, Request.Id); } - - /// - /// Fires the request off - /// - private ValueTask FireRequest() + catch (Exception ex) { - try - { - return FireRequestInternal(); - } - catch (Exception ex) - { - return RequestResponse.CreateExceptionResponse(GetResponseError(RequestErrorType.Generic, DiscordLogLevel.Exception).WithException(ex), null, RequestCompletedStatus.ErrorFatal); - } + _logger.Exception("Request callback threw exception for Bucket ID: {0} Request ID: {1}", Request.Id, Request.Id, ex); } - - private async ValueTask FireRequestInternal() + finally { - _logger.Verbose($"{nameof(RequestHandler)}.{nameof(FireRequestInternal)} Starting REST Request. Request ID: {{0}} Method: {{1}} Url: {{2}}", Request.Id, Request.Method, Request.Route); - - RequestResponse response = null; - byte retries = 0; - while(CanSendRequest(response, retries)) - { - response?.Dispose(); - Request.Status = RequestStatus.PendingStart; - await Request.WaitUntilRequestCanStart(_token).ConfigureAwait(false); - await Request.Bucket.WaitUntilBucketAvailable(this, _token).ConfigureAwait(false); - Request.Status = RequestStatus.InProgress; - - if (Request.IsCancelled) - { - _logger.Verbose($"{nameof(RequestHandler)}.{nameof(FireRequestInternal)} Cancel REST Request. Request ID: {{0}} Method: {{1}} Url: {{2}}", Request.Id, Request.Method, Request.Route); - return await RequestResponse.CreateCancelledResponse().ConfigureAwait(false); - } - - response = await SendRequest(_token).ConfigureAwait(false); - - //Request was cancelled - if (response == null) - { - return null; - } - - Request.Bucket.UpdateRateLimits(this, response); - - switch (response.Status) - { - case RequestCompletedStatus.Success: - case RequestCompletedStatus.Cancelled: - case RequestCompletedStatus.ErrorFatal: - return response; - } - - if (response.Code == DiscordHttpStatusCode.BadRequest) - { - return response; - } - - retries++; - } + semaphore?.Release(); + } - return response; + Dispose(); + } + + /// + /// Fires the request off + /// + private ValueTask FireRequest() + { + try + { + return FireRequestInternal(); } - - private bool CanSendRequest(RequestResponse response, byte retries) + catch (Exception ex) { - if (retries >= DiscordConfig.Instance.Rest.ApiRateLimitRetries) - { - return false; - } - - if (response != null && response.Code != DiscordHttpStatusCode.TooManyRequests) - { - return retries < DiscordConfig.Instance.Rest.ApiErrorRetries; - } - - return true; + return RequestResponse.CreateExceptionResponse(GetResponseError(RequestErrorType.Generic, DiscordLogLevel.Exception).WithException(ex), null, RequestCompletedStatus.ErrorFatal); } + } + + private async ValueTask FireRequestInternal() + { + _logger.Verbose($"{nameof(RequestHandler)}.{nameof(FireRequestInternal)} Starting REST Request. Request ID: {{0}} Method: {{1}} Url: {{2}}", Request.Id, Request.Method, Request.Route); - private async ValueTask SendRequest(CancellationToken token) + RequestResponse response = null; + byte retries = 0; + while(CanSendRequest(response, retries)) { - try + response?.Dispose(); + Request.Status = RequestStatus.PendingStart; + await Request.WaitUntilRequestCanStart(_token).ConfigureAwait(false); + await Request.Bucket.WaitUntilBucketAvailable(this, _token).ConfigureAwait(false); + Request.Status = RequestStatus.InProgress; + + if (Request.IsCancelled) { - using (HttpRequestMessage request = CreateRequest()) - { - using (HttpResponseMessage webResponse = await Request.HttpClient.SendAsync(request, token).ConfigureAwait(false)) - { - if (token.IsCancellationRequested) - { - return null; - } - - if (webResponse.IsSuccessStatusCode) - { - return await RequestResponse.CreateSuccessResponse(webResponse).ConfigureAwait(false); - } - - return await HandleWebException(request, webResponse).ConfigureAwait(false); - } - } + _logger.Verbose($"{nameof(RequestHandler)}.{nameof(FireRequestInternal)} Cancel REST Request. Request ID: {{0}} Method: {{1}} Url: {{2}}", Request.Id, Request.Method, Request.Route); + return await RequestResponse.CreateCancelledResponse().ConfigureAwait(false); } - catch (OperationCanceledException) + + response = await SendRequest(_token).ConfigureAwait(false); + + //Request was canceled + if (response == null) { - return await RequestResponse.CreateCancelledResponse().ConfigureAwait(false); + return null; } - catch (JsonSerializationException ex) + + Request.Bucket.UpdateRateLimits(this, response); + + switch (response.Status) { - return await RequestResponse.CreateExceptionResponse(GetResponseError(RequestErrorType.Serialization, DiscordLogLevel.Error).WithException(ex), null, RequestCompletedStatus.ErrorFatal).ConfigureAwait(false); + case RequestCompletedStatus.Success: + case RequestCompletedStatus.Cancelled: + case RequestCompletedStatus.ErrorFatal: + return response; } - catch (Exception ex) + + if (response.Code == DiscordHttpStatusCode.BadRequest) { - return await RequestResponse.CreateExceptionResponse(GetResponseError(RequestErrorType.Generic, DiscordLogLevel.Error).WithException(ex), null, RequestCompletedStatus.ErrorFatal).ConfigureAwait(false); + return response; } + + retries++; } + + return response; + } - private async ValueTask HandleWebException(HttpRequestMessage request, HttpResponseMessage webResponse) + private bool CanSendRequest(RequestResponse response, byte retries) + { + if (retries >= DiscordConfig.Instance.Rest.ApiRateLimitRetries) { - RequestResponse response; + return false; + } - if (Request.Client.Logger.IsLogging(DiscordLogLevel.Verbose)) - { - string content = request.Content != null ? await request.Content.ReadAsStringAsync().ConfigureAwait(false) : "No Content"; - Request.Client.Logger.Verbose("Web Exception Occured. Request ID: {0} Plugin: {1} Method: {2} Route: {3} HTTP Code: {4}\nBody:\n{5}", - Request.Id, Request.Client.PluginName, Request.Method, Request.Route, webResponse.StatusCode, content); - } + if (response != null && response.Code != DiscordHttpStatusCode.TooManyRequests) + { + return retries < DiscordConfig.Instance.Rest.ApiErrorRetries; + } - DiscordHttpStatusCode statusCode = (DiscordHttpStatusCode)webResponse.StatusCode; - if (statusCode == DiscordHttpStatusCode.TooManyRequests) + return true; + } + + private async ValueTask SendRequest(CancellationToken token) + { + try + { + using HttpRequestMessage request = CreateRequest(); + using HttpResponseMessage webResponse = await Request.HttpClient.SendAsync(request, token).ConfigureAwait(false); + if (token.IsCancellationRequested) { - response = await RequestResponse.CreateExceptionResponse(await GetResponseError(RequestErrorType.RateLimit, DiscordLogLevel.Warning).WithRequest(request).ConfigureAwait(false), webResponse, RequestCompletedStatus.ErrorRetry).ConfigureAwait(false); + return null; } - else + + if (webResponse.IsSuccessStatusCode) { - response = await RequestResponse.CreateExceptionResponse(await GetResponseError(RequestErrorType.GenericWeb, DiscordLogLevel.Error).WithRequest(request).ConfigureAwait(false), webResponse, RequestCompletedStatus.ErrorFatal).ConfigureAwait(false); + return await RequestResponse.CreateSuccessResponse(webResponse).ConfigureAwait(false); } - - Request.OnRequestErrored(); - if (Request.Client.Logger.IsLogging(DiscordLogLevel.Verbose)) - { - string content = request.Content != null ? await request.Content.ReadAsStringAsync().ConfigureAwait(false) : "No Content"; - Request.Client.Logger.Verbose("Web Exception Occured. Type: {0} Request ID: {1} Plugin: {2} Method: {3} Route: {4} HTTP Code: {5}\nBody:\n{6}", - response.Error?.ErrorType, Request.Id, Request.Client.PluginName, Request.Method, Request.Route, response.Code, content); - } + return await HandleWebException(request, webResponse).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + return await RequestResponse.CreateCancelledResponse().ConfigureAwait(false); + } + catch (JsonSerializationException ex) + { + return await RequestResponse.CreateExceptionResponse(GetResponseError(RequestErrorType.Serialization, DiscordLogLevel.Error).WithException(ex), null, RequestCompletedStatus.ErrorFatal).ConfigureAwait(false); + } + catch (Exception ex) + { + return await RequestResponse.CreateExceptionResponse(GetResponseError(RequestErrorType.Generic, DiscordLogLevel.Error).WithException(ex), null, RequestCompletedStatus.ErrorFatal).ConfigureAwait(false); + } + } - return response; + private async ValueTask HandleWebException(HttpRequestMessage request, HttpResponseMessage webResponse) + { + RequestResponse response; + + if (Request.Client.Logger.IsLogging(DiscordLogLevel.Verbose)) + { + string content = request.Content != null ? await request.Content.ReadAsStringAsync().ConfigureAwait(false) : "No Content"; + Request.Client.Logger.Verbose("Web Exception Occured. Request ID: {0} Plugin: {1} Method: {2} Route: {3} HTTP Code: {4}\nBody:\n{5}", + Request.Id, Request.Client.PluginName, Request.Method, Request.Route, webResponse.StatusCode, content); + } + + DiscordHttpStatusCode statusCode = (DiscordHttpStatusCode)webResponse.StatusCode; + if (statusCode == DiscordHttpStatusCode.TooManyRequests) + { + response = await RequestResponse.CreateExceptionResponse(await GetResponseError(RequestErrorType.RateLimit, DiscordLogLevel.Warning).WithRequest(request).ConfigureAwait(false), webResponse, RequestCompletedStatus.ErrorRetry).ConfigureAwait(false); + } + else + { + response = await RequestResponse.CreateExceptionResponse(await GetResponseError(RequestErrorType.GenericWeb, DiscordLogLevel.Error).WithRequest(request).ConfigureAwait(false), webResponse, RequestCompletedStatus.ErrorFatal).ConfigureAwait(false); } + + Request.OnRequestErrored(); - private HttpRequestMessage CreateRequest() + if (Request.Client.Logger.IsLogging(DiscordLogLevel.Verbose)) { - HttpRequestMessage request = new HttpRequestMessage(DiscordHttpMethods.GetMethod(Request.Method), Request.Route); - CreateContent(request); - return request; + string content = request.Content != null ? await request.Content.ReadAsStringAsync().ConfigureAwait(false) : "No Content"; + Request.Client.Logger.Verbose("Web Exception Occured. Type: {0} Request ID: {1} Plugin: {2} Method: {3} Route: {4} HTTP Code: {5}\nBody:\n{6}", + response.Error?.ErrorType, Request.Id, Request.Client.PluginName, Request.Method, Request.Route, response.Code, content); } + + return response; + } + + private HttpRequestMessage CreateRequest() + { + HttpRequestMessage request = new(DiscordHttpMethods.GetMethod(Request.Method), Request.Route); + CreateContent(request); + return request; + } - private void CreateContent(HttpRequestMessage request) + private void CreateContent(HttpRequestMessage request) + { + object data = Request.Data; + switch (data) { - object data = Request.Data; - switch (data) + case null: + return; + case IFileAttachments {FileAttachments: not null} attachments when attachments.FileAttachments.Count != 0: { - case null: - return; - case IFileAttachments attachments when attachments.FileAttachments != null && attachments.FileAttachments.Count != 0: - { - MultipartFormDataContent content = new MultipartFormDataContent(); + MultipartFormDataContent content = new(); - HttpContent json = GetJsonContent(data); - content.Add(json, "payload_json"); + HttpContent json = GetJsonContent(data); + content.Add(json, "payload_json"); - for (int index = 0; index < attachments.FileAttachments.Count; index++) - { - MessageFileAttachment fileAttachment = attachments.FileAttachments[index]; - ByteArrayContent file = new ByteArrayContent(fileAttachment.Data); - content.Add(file, FileAttachmentCache.Instance.GetName(index), fileAttachment.FileName); - file.Headers.ContentType = MediaTypeHeaderCache.Instance.Get(fileAttachment.ContentType); - } - - request.Content = content; - break; + for (int index = 0; index < attachments.FileAttachments.Count; index++) + { + MessageFileAttachment fileAttachment = attachments.FileAttachments[index]; + ByteArrayContent file = new(fileAttachment.Data); + content.Add(file, FileAttachmentCache.Instance.GetName(index), fileAttachment.FileName); + file.Headers.ContentType = MediaTypeHeaderCache.Instance.Get(fileAttachment.ContentType); } - default: - request.Content = GetJsonContent(data); - break; + request.Content = content; + break; } + default: + request.Content = GetJsonContent(data); + break; } - private StringContent GetJsonContent(object data) - { - string json = JsonConvert.SerializeObject(data, Request.Client.Bot.JsonSettings); - _logger.Verbose($"{nameof(RequestHandler)}.{nameof(GetJsonContent)} Data: {{0}}", json); - StringContent content = new StringContent(json); - content.Headers.ContentType = MediaTypeHeaderCache.Instance.Get("application/json"); - return content; - } + } - /// - /// Aborts a currently running request - /// - public void Abort() - { - Request.Client.Logger.Debug($"{nameof(RequestHandler)}.{nameof(Abort)} Abort Request Bucket ID: {{0}} Request ID: {{1}} Plugin: {{2}} Method: {{3}} Route: {{4}}", Request.Bucket.Id, Request.Id, Request.Client.PluginName, Request.Method, Request.Route); - Request.Abort(); - } + private StringContent GetJsonContent(object data) + { + string json = JsonConvert.SerializeObject(data, Request.Client.JsonSettings); + _logger.Verbose($"{nameof(RequestHandler)}.{nameof(GetJsonContent)} Data: {{0}}", json); + StringContent content = new(json); + content.Headers.ContentType = MediaTypeHeaderCache.Instance.Get("application/json"); + return content; + } - private ResponseError GetResponseError(RequestErrorType type, DiscordLogLevel log) => new ResponseError(Request, type, log); + /// + /// Aborts a currently running request + /// + public void Abort() + { + Request.Client.Logger.Debug($"{nameof(RequestHandler)}.{nameof(Abort)} Abort Request Bucket ID: {{0}} Request ID: {{1}} Plugin: {{2}} Method: {{3}} Route: {{4}}", Request.Bucket.Id, Request.Id, Request.Client.PluginName, Request.Method, Request.Route); + Request.Abort(); + } - /// - protected override void EnterPool() - { - Request.Dispose(); - _response?.Dispose(); - Request = null; - _response = null; - _logger = null; - } + private ResponseError GetResponseError(RequestErrorType type, DiscordLogLevel log) => new(Request, type, log); - /// - public void LogDebug(DebugLogger logger) - { - Request.LogDebug(logger); - } + /// + protected override void EnterPool() + { + Request.Dispose(); + _response?.Dispose(); + Request = null; + _response = null; + _logger = null; + } + + /// + public void LogDebug(DebugLogger logger) + { + Request.LogDebug(logger); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Rest/Requests/RequestOptions.cs b/Oxide.Ext.Discord/Rest/Requests/RequestOptions.cs index fd1c4f87b..47cbdae0c 100644 --- a/Oxide.Ext.Discord/Rest/Requests/RequestOptions.cs +++ b/Oxide.Ext.Discord/Rest/Requests/RequestOptions.cs @@ -1,28 +1,27 @@ -namespace Oxide.Ext.Discord.Rest +namespace Oxide.Ext.Discord.Rest; + +/// +/// Options the the REST request +/// +public struct RequestOptions { /// - /// Options the the REST request + /// If the request should ignore global rate limits /// - public struct RequestOptions - { - /// - /// If the request should ignore global rate limits - /// - public readonly bool IgnoreRateLimit; - - /// - /// Constructor - /// - /// - public RequestOptions(bool ignoreRateLimit) - { - IgnoreRateLimit = ignoreRateLimit; - } + public readonly bool IgnoreRateLimit; - /// - /// The request should ignore rate limits - /// - /// - public static RequestOptions SkipRateLimit() => new RequestOptions(true); + /// + /// Constructor + /// + /// + public RequestOptions(bool ignoreRateLimit) + { + IgnoreRateLimit = ignoreRateLimit; } + + /// + /// The request should ignore rate limits + /// + /// + public static RequestOptions SkipRateLimit() => new(true); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Rest/Requests/RequestStatus.cs b/Oxide.Ext.Discord/Rest/Requests/RequestStatus.cs index f287611af..5548e402d 100644 --- a/Oxide.Ext.Discord/Rest/Requests/RequestStatus.cs +++ b/Oxide.Ext.Discord/Rest/Requests/RequestStatus.cs @@ -1,43 +1,42 @@ -namespace Oxide.Ext.Discord.Rest +namespace Oxide.Ext.Discord.Rest; + +/// +/// Discord API Request Status +/// +public enum RequestStatus : byte { /// - /// Discord API Request Status + /// Request is in the queue waiting to be processed /// - public enum RequestStatus : byte - { - /// - /// Request is in the queue waiting to be processed - /// - InQueue, + InQueue, - /// - /// Request has been started - /// - Started, + /// + /// Request has been started + /// + Started, - /// - /// Requesting is waiting for bucket to be ready - /// - PendingBucket, + /// + /// Requesting is waiting for bucket to be ready + /// + PendingBucket, - /// - /// Request is waiting to start - /// - PendingStart, + /// + /// Request is waiting to start + /// + PendingStart, - /// - /// Request is in progress - /// - InProgress, + /// + /// Request is in progress + /// + InProgress, - /// - /// Request completed and was not cancelled - /// - Completed, + /// + /// Request completed and was not canceled + /// + Completed, - /// - /// Request was cancelled - /// - Cancelled - } + /// + /// Request was canceled + /// + Cancelled } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Rest/Requests/Request{T}.cs b/Oxide.Ext.Discord/Rest/Requests/Request{T}.cs index 4f89fede6..6acf27197 100644 --- a/Oxide.Ext.Discord/Rest/Requests/Request{T}.cs +++ b/Oxide.Ext.Discord/Rest/Requests/Request{T}.cs @@ -9,74 +9,73 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Rest +namespace Oxide.Ext.Discord.Rest; + +/// +/// Represents a REST API request that returns {T} data +/// +/// Data to be returned +public class Request : BaseRequest { /// - /// Represents a REST API request that returns {T} data + /// Callback to call if the request completed successfully /// - /// Data to be returned - public class Request : BaseRequest + private IPendingPromise _promise; + + /// + /// Creates a REST API request that returns type of T from the response + /// + /// for the request + /// Client making the request + /// for the request + /// HTTP web method + /// Route for the request + /// Data being passed into the request. Null if no data is passed + /// Promise for the request + /// Options for the request + /// A + public static Request CreateRequest(DiscordPluginPool pluginPool, DiscordClient client, HttpClient httpClient, RequestMethod method, string route, object data, IPendingPromise promise, RequestOptions options) { - /// - /// Callback to call if the request completed successfully - /// - private IPendingPromise _promise; + Request request = pluginPool.Get>(); + request.Init(client, httpClient, method, route, data, options); + request._promise = promise; + return request; + } - /// - /// Creates a REST API request that returns type of T from the response - /// - /// for the request - /// Client making the request - /// for the request - /// HTTP web method - /// Route for the request - /// Data being passed into the request. Null if no data is passed - /// Promise for the request - /// Options for the request - /// A - public static Request CreateRequest(DiscordPluginPool pluginPool, DiscordClient client, HttpClient httpClient, RequestMethod method, string route, object data, IPendingPromise promise, RequestOptions options) + /// + protected override void OnRequestSuccess(RequestResponse response) + { + try { - Request request = pluginPool.Get>(); - request.Init(client, httpClient, method, route, data, options); - request._promise = promise; - return request; + T data = JsonConvert.DeserializeObject(response.Content, Client.JsonSettings); + _promise.Resolve(data); } - - /// - protected override void OnRequestSuccess(RequestResponse response) + catch (Exception ex) { - try - { - T data = JsonConvert.DeserializeObject(response.Content, Client.Bot.JsonSettings); - _promise.Resolve(data); - } - catch (Exception ex) - { - Logger.Exception("An error occured deserializing JSON response. Method: {0} Route: {1}\nResponse:\n{2}", Method, Route, response.Content, ex); - } + Logger.Exception("An error occured deserializing JSON response. Method: {0} Route: {1}\nResponse:\n{2}", Method, Route, response.Content, ex); } + } - /// - protected override void OnRequestError(RequestResponse response) - { - _promise.Finally(response.Error.LogError); - _promise.Reject(response.Error); - } + /// + protected override void OnRequestError(RequestResponse response) + { + _promise.Finally(response.Error.LogError); + _promise.Reject(response.Error); + } - internal override void Abort() + internal override void Abort() + { + if (Status != RequestStatus.Cancelled) { - if (Status != RequestStatus.Cancelled) - { - _promise.Reject(new RequestCancelledException()); - base.Abort(); - } + _promise.Reject(new RequestCancelledException()); + base.Abort(); } + } - /// - protected override void EnterPool() - { - base.EnterPool(); - _promise = null; - } + /// + protected override void EnterPool() + { + base.EnterPool(); + _promise = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Rest/RestHandler.cs b/Oxide.Ext.Discord/Rest/RestHandler.cs index a7ed0bce1..2a3548bd0 100644 --- a/Oxide.Ext.Discord/Rest/RestHandler.cs +++ b/Oxide.Ext.Discord/Rest/RestHandler.cs @@ -12,304 +12,309 @@ using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Factory; using Oxide.Ext.Discord.Interfaces; +using Oxide.Ext.Discord.Json; using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Rest +namespace Oxide.Ext.Discord.Rest; + +/// +/// Represents a REST handler for a bot +/// +public class RestHandler : IDebugLoggable { /// - /// Represents a REST handler for a bot + /// for API Requests /// - public class RestHandler : IDebugLoggable - { - /// - /// for API Requests - /// - public readonly HttpClient Client; + public readonly HttpClient Client; - /// - /// Global Rate Limit for the bot - /// - public readonly RestRateLimit RateLimit; + /// + /// Global Rate Limit for the bot + /// + public readonly RestRateLimit RateLimit; - /// - /// Buckets with Routes we don't know the Hash of yet - /// - public readonly ConcurrentDictionary Buckets = new ConcurrentDictionary(); + /// + /// Buckets with Routes we don't know the Hash of yet + /// + public readonly ConcurrentDictionary Buckets = new(); - /// - /// Route to Bucket ID - /// - public readonly ConcurrentDictionary RouteToBucketId = new ConcurrentDictionary(); + /// + /// Route to Bucket ID + /// + public readonly ConcurrentDictionary RouteToBucketId = new(); - private readonly ILogger _logger; + private readonly ILogger _logger; - /// - /// Creates a new REST handler for a bot client - /// - /// Client the request is for - /// Logger from the client - public RestHandler(BotClient client, ILogger logger) + internal static readonly RestHandler Global = new(DiscordExtension.GlobalLogger); + + /// + /// Creates a new REST handler for bot / webhook clients + /// + /// + public RestHandler(ILogger logger) + { + HttpClientHandler handler = new() { - HttpClientHandler handler = new HttpClientHandler - { - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, - UseCookies = false - }; - Client = new HttpClient(handler) - { - Timeout = TimeSpan.FromSeconds(15), - BaseAddress = new Uri(DiscordEndpoints.Rest.ApiUrl) - }; - Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bot", client.Connection.ApiToken); - Client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json")); - Client.DefaultRequestHeaders.AcceptEncoding.Add( StringWithQualityHeaderValue.Parse("gzip")); - Client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("deflate")); - Client.DefaultRequestHeaders.Add("user-agent", $"DiscordBot (https://github.com/dassjosh/Oxide.Ext.Discord, v{DiscordExtension.FullExtensionVersion})"); - _logger = logger; - RateLimit = new RestRateLimit(logger); - } + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, + UseCookies = false + }; + Client = new HttpClient(handler) + { + Timeout = TimeSpan.FromSeconds(15), + BaseAddress = new Uri(DiscordEndpoints.Rest.ApiUrl) + }; + Client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json")); + Client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("gzip")); + Client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("deflate")); + Client.DefaultRequestHeaders.Add("user-agent", $"DiscordBot (https://github.com/dassjosh/Oxide.Ext.Discord, v{DiscordExtension.FullExtensionVersion})"); + _logger = logger; + RateLimit = new RestRateLimit(logger); + } + + /// + /// Creates a new REST handler for a bot client + /// + /// Client the request is for + /// Logger from the client + public RestHandler(BotClient client, ILogger logger) : this(logger) + { + Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bot", client.Connection.ApiToken); + } - /// - /// Performs a HTTP Get Request with TResult response - /// - /// Client for the request - /// Url for the request - /// Options for the request - /// Result to be returned from the request - public IPromise Get(DiscordClient client, string url, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.GET, null, options); + /// + /// Performs ann HTTP Get Request with TResult response + /// + /// Client for the request + /// Url for the request + /// Options for the request + /// Result to be returned from the request + public IPromise Get(DiscordClient client, string url, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.GET, null, options); - /// - /// Performs a HTTP Post Request - /// - /// Client for the request - /// Url for the request - /// Data to post - /// Options for the request - public IPromise Post(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.POST, data, options); + /// + /// Performs a HTTP Post Request + /// + /// Client for the request + /// Url for the request + /// Data to post + /// Options for the request + public IPromise Post(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.POST, data, options); - /// - /// Performs a HTTP Post Request with TResult response - /// - /// Client for the request - /// Url for the request - /// Data to post - /// Options for the request - /// Result to be returned from the request - public IPromise Post(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.POST, data, options); + /// + /// Performs an HTTP Post Request with TResult response + /// + /// Client for the request + /// Url for the request + /// Data to post + /// Options for the request + /// Result to be returned from the request + public IPromise Post(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.POST, data, options); - /// - /// Performs a HTTP Put Request - /// - /// Client for the request - /// Url for the request - /// Data to put - /// Options for the request - public IPromise Put(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.PUT, data, options); + /// + /// Performs an HTTP Put Request + /// + /// Client for the request + /// Url for the request + /// Data to put + /// Options for the request + public IPromise Put(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.PUT, data, options); - /// - /// Performs a HTTP Put Request with TResult response - /// - /// Client for the request - /// Url for the request - /// Data to put - /// Result to be returned from the request - /// Options for the request - public IPromise Put(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.PUT, data, options); + /// + /// Performs an HTTP Put Request with TResult response + /// + /// Client for the request + /// Url for the request + /// Data to put + /// Result to be returned from the request + /// Options for the request + public IPromise Put(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.PUT, data, options); - /// - /// Performs a HTTP Patch Request - /// - /// Client for the request - /// Url for the request - /// Data to patch - /// Options for the request - public IPromise Patch(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.PATCH, data, options); + /// + /// Performs an HTTP Patch Request + /// + /// Client for the request + /// Url for the request + /// Data to patch + /// Options for the request + public IPromise Patch(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.PATCH, data, options); - /// - /// Performs a HTTP Patch Request with TResult response - /// - /// Client for the request - /// Url for the request - /// Data to patch - /// Options for the request - /// Result to be returned from the request - public IPromise Patch(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.PATCH, data, options); + /// + /// Performs an HTTP Patch Request with TResult response + /// + /// Client for the request + /// Url for the request + /// Data to patch + /// Options for the request + /// Result to be returned from the request + public IPromise Patch(DiscordClient client, string url, object data, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.PATCH, data, options); - /// - /// Performs a HTTP Delete Request - /// - /// Client for the request - /// Url for the request - /// Options for the request - public IPromise Delete(DiscordClient client, string url, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.DELETE, null, options); + /// + /// Performs a HTTP Delete Request + /// + /// Client for the request + /// Url for the request + /// Options for the request + public IPromise Delete(DiscordClient client, string url, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.DELETE, null, options); - /// - /// Performs a HTTP Delete Request with TResult response - /// - /// Client for the request - /// Url for the request - /// Options for the request - /// Result to be returned from the request - public IPromise Delete(DiscordClient client, string url, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.DELETE, null, options); + /// + /// Performs an HTTP Delete Request with TResult response + /// + /// Client for the request + /// Url for the request + /// Options for the request + /// Result to be returned from the request + public IPromise Delete(DiscordClient client, string url, RequestOptions? options = null) => CreateRequest(client, url, RequestMethod.DELETE, null, options); - /// - /// Creates a new request and queues it to be ran - /// - /// Client making the request - /// URL of the request - /// HTTP method of the request - /// Data to be sent with the request - /// Options for the request - private IPromise CreateRequest(DiscordClient client, string url, RequestMethod method, object data, RequestOptions? options) - { - PerformValidation(data); - IPendingPromise promise = Promise.Create(); - Request request = Request.CreateRequest(DiscordPool.Internal, client, Client, method, url, data, promise, options ?? default(RequestOptions)); - StartRequest(request); - return promise; - } + /// + /// Creates a new request and queues it to be run + /// + /// Client making the request + /// URL of the request + /// HTTP method of the request + /// Data to be sent with the request + /// Options for the request + private IPromise CreateRequest(DiscordClient client, string url, RequestMethod method, object data, RequestOptions? options) + { + PerformValidation(data); + IPendingPromise promise = Promise.Create(); + Request request = Request.CreateRequest(DiscordPool.Internal, client, Client, method, url, data, promise, options ?? default(RequestOptions)); + StartRequest(request); + return promise; + } - /// - /// Creates a new request and queues it to be ran - /// - /// Client making the request - /// URL of the request - /// HTTP method of the request - /// Data to be sent with the request - /// Options for the request - /// The type that is expected to be returned - private IPromise CreateRequest(DiscordClient client, string url, RequestMethod method, object data, RequestOptions? options) - { - PerformValidation(data); - IPendingPromise promise = Promise.Create(); - Request request = Request.CreateRequest(DiscordPool.Internal, client, Client, method, url, data, promise, options ?? default(RequestOptions)); - StartRequest(request); - return promise; - } + /// + /// Creates a new request and queues it to be run + /// + /// Client making the request + /// URL of the request + /// HTTP method of the request + /// Data to be sent with the request + /// Options for the request + /// The type that is expected to be returned + private IPromise CreateRequest(DiscordClient client, string url, RequestMethod method, object data, RequestOptions? options) + { + PerformValidation(data); + IPendingPromise promise = Promise.Create(); + Request request = Request.CreateRequest(DiscordPool.Internal, client, Client, method, url, data, promise, options ?? default(RequestOptions)); + StartRequest(request); + return promise; + } - private void PerformValidation(object data) + private void PerformValidation(object data) + { + if (!DiscordConfig.Instance.Validation.EnableValidation || data is not IDiscordValidation validate) { - if (!DiscordConfig.Instance.Validation.EnableValidation || !(data is IDiscordValidation validate)) - { - return; - } - - try - { - validate.Validate(); - } - catch (Exception) - { - JsonSerializerSettings settings = new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore, - Formatting = Formatting.Indented - }; - _logger.Error($"An error occured duration object validation.\n{JsonConvert.SerializeObject(data, settings)}"); - throw; - } + return; } - - /// - /// Starts the request - /// - /// Request to be started - public void StartRequest(BaseRequest request) + + try { - _logger.Debug($"{nameof(RestHandler)}.{nameof(StartRequest)} Method: {{0}} Route: {{1}}", request.Method, request.Route); - RequestHandler handler = RequestHandler.CreateRequest(request); - QueueBucket(handler, request); + validate.Validate(); } - - /// - /// Queues the request for the bucket - /// - public void QueueBucket(RequestHandler handler, BaseRequest request) + catch (Exception) { - BucketId bucketId = BucketIdFactory.GenerateId(request.Method, request.Route); - _logger.Debug("RestHandler Queuing Bucket for {0} bucket {1}", request.Route, bucketId); - Bucket bucket = GetBucket(bucketId); - bucket.QueueRequest(handler); + _logger.Error($"An error occured duration object validation.\n{JsonConvert.SerializeObject(data, DiscordJson.IndentedSettings)}"); + throw; } + } - internal void UpgradeToKnownBucket(Bucket bucket, BucketId newBucketId) - { - _logger.Debug("RestHandler Upgrading To Known Bucket for Old ID: {0} New ID: {1}", bucket.Id, newBucketId); - RouteToBucketId[bucket.Id] = newBucketId; - - if (Buckets.TryGetValue(newBucketId, out Bucket existing)) - { - existing.Merge(bucket); - bucket.Dispose(); - return; - } + /// + /// Starts the request + /// + /// Request to be started + public void StartRequest(BaseRequest request) + { + _logger.Debug($"{nameof(RestHandler)}.{nameof(StartRequest)} Method: {{0}} Route: {{1}}", request.Method, request.Route); + RequestHandler handler = RequestHandler.CreateRequest(request); + QueueBucket(handler, request); + } + + /// + /// Queues the request for the bucket + /// + public void QueueBucket(RequestHandler handler, BaseRequest request) + { + BucketId bucketId = BucketIdFactory.GenerateId(request.Method, request.Route); + _logger.Debug("RestHandler Queuing Bucket for {0} bucket {1}", request.Route, bucketId); + Bucket bucket = GetBucket(bucketId); + bucket.QueueRequest(handler); + } - Buckets.TryRemove(bucket.Id, out Bucket _); - bucket.Id = newBucketId; - bucket.IsKnownBucket = true; - Buckets[newBucketId] = bucket; - } + internal void UpgradeToKnownBucket(Bucket bucket, BucketId newBucketId) + { + _logger.Debug("RestHandler Upgrading To Known Bucket for Old ID: {0} New ID: {1}", bucket.Id, newBucketId); + RouteToBucketId[bucket.Id] = newBucketId; - internal void RemoveBucket(Bucket bucket) + if (Buckets.TryGetValue(newBucketId, out Bucket existing)) { - Buckets.TryRemove(bucket.Id, out Bucket _); - bucket.ShutDown(); + existing.Merge(bucket); bucket.Dispose(); + return; } - /// - /// Returns the bucket with the given ID - /// - /// - /// - public Bucket GetBucket(BucketId bucketId) - { - if (RouteToBucketId.TryGetValue(bucketId, out BucketId value)) - { - bucketId = value; - } + Buckets.TryRemove(bucket.Id, out Bucket _); + bucket.Id = newBucketId; + bucket.IsKnownBucket = true; + Buckets[newBucketId] = bucket; + } - if (!Buckets.TryGetValue(bucketId, out Bucket bucket)) - { - bucket = DiscordPool.Internal.Get(); - bucket.Init(bucketId, this, _logger); - Buckets[bucketId] = bucket; - } + internal void RemoveBucket(Bucket bucket) + { + Buckets.TryRemove(bucket.Id, out Bucket _); + bucket.ShutDown(); + bucket.Dispose(); + } - return bucket; + /// + /// Returns the bucket with the given ID + /// + /// + /// + public Bucket GetBucket(BucketId bucketId) + { + if (RouteToBucketId.TryGetValue(bucketId, out BucketId value)) + { + bucketId = value; } - internal void OnClientClosed(DiscordClient client) + if (!Buckets.TryGetValue(bucketId, out Bucket bucket)) { - _logger.Debug($"{nameof(RestHandler)}.{nameof(OnClientClosed)} Client: {{0}}", client.Plugin.FullName()); - foreach (Bucket bucket in Buckets.Values) - { - bucket.AbortClientRequests(client); - } + bucket = DiscordPool.Internal.Get(); + bucket.Init(bucketId, this, _logger); + Buckets[bucketId] = bucket; } - /// - /// Shutdown the REST handler - /// - public void Shutdown() + return bucket; + } + + internal void OnClientClosed(DiscordClient client) + { + _logger.Debug($"{nameof(RestHandler)}.{nameof(OnClientClosed)} Client: {{0}}", client.Plugin.FullName()); + foreach (Bucket bucket in Buckets.Values) { - foreach (KeyValuePair bucket in Buckets) - { - bucket.Value.ShutDown(); - bucket.Value.Dispose(); - } - - RouteToBucketId.Clear(); - Buckets.Clear(); - RateLimit.Shutdown(); + bucket.AbortClientRequests(client); } + } - /// - public void LogDebug(DebugLogger logger) + /// + /// Shutdown the REST handler + /// + public void Shutdown() + { + foreach (KeyValuePair bucket in Buckets) { - logger.AppendList("Buckets", Buckets.Values); + bucket.Value.ShutDown(); + bucket.Value.Dispose(); } + + RouteToBucketId.Clear(); + Buckets.Clear(); + RateLimit.Shutdown(); + } + + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendList("Buckets", Buckets.Values); } -} +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Services/IpApi/IpApiService.cs b/Oxide.Ext.Discord/Services/IpApi/IpApiService.cs index 1dae507ee..4cb012d8d 100644 --- a/Oxide.Ext.Discord/Services/IpApi/IpApiService.cs +++ b/Oxide.Ext.Discord/Services/IpApi/IpApiService.cs @@ -10,123 +10,130 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Services.IpApi +namespace Oxide.Ext.Discord.Services.IpApi; + +internal sealed class IpApiService : Singleton { - internal sealed class IpApiService : Singleton - { - private readonly HttpClient _client; - private readonly ILogger _logger = DiscordExtension.GlobalLogger; - private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5, 5); + private readonly HttpClient _client; + private readonly ILogger _logger = DiscordExtension.GlobalLogger; + private readonly SemaphoreSlim _semaphore = new(5, 5); - private int _remainingRequests = 45; - private DateTimeOffset _limitReset = DateTimeOffset.MinValue; + private int _remainingRequests = 45; + private DateTimeOffset _limitReset = DateTimeOffset.MinValue; - private const string RemainingRequestsHeader = "X-Rl"; - private const string RemainingSecondsHeader = "X-Ttl"; + private const string RemainingRequestsHeader = "X-Rl"; + private const string RemainingSecondsHeader = "X-Ttl"; + private const int MaxRetries = 3; - private IpApiService() + private IpApiService() + { + HttpClientHandler handler = new() { - HttpClientHandler handler = new HttpClientHandler - { - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, - UseCookies = false - }; - _client = new HttpClient(handler) - { - Timeout = TimeSpan.FromSeconds(15), - BaseAddress = new Uri("http://ip-api.com/json/") - }; - _client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json")); - _client.DefaultRequestHeaders.AcceptEncoding.Add( StringWithQualityHeaderValue.Parse("gzip")); - _client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("deflate")); - } + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, + UseCookies = false + }; + _client = new HttpClient(handler) + { + Timeout = TimeSpan.FromSeconds(15), + BaseAddress = new Uri("http://ip-api.com/json/") + }; + _client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json")); + _client.DefaultRequestHeaders.AcceptEncoding.Add( StringWithQualityHeaderValue.Parse("gzip")); + _client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("deflate")); + } + + public ValueTask GetCountryCode(string ip) + { + _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCode)} Getting IP data for {{0}}", ip); + string url = $"{ip}?fields=49155"; + return GetCountryCodeInternal(url, 0); + } - public ValueTask GetCountryCode(string ip) + private async ValueTask GetCountryCodeInternal(string url, int retries) + { + if (retries++ >= MaxRetries) { - _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCode)} Getting IP data for {{0}}", ip); - string url = $"{ip}?fields=49155"; - return GetCountryCodeInternal(url, 0); + _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} Failed to get IP data after {{0}} retries", retries); + return null; } - - private async ValueTask GetCountryCodeInternal(string url, int retries) + + if (_remainingRequests <= 0 && _limitReset > DateTimeOffset.UtcNow) { - if (retries >= 3) - { - _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} Failed to get IP data after {{0}} retries", retries); - return null; - } + _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} Rate Limit reached. Waiting for {{0}}", DateTimeOffset.UtcNow - _limitReset); + await _limitReset.DelayUntil().ConfigureAwait(false); + } - if (_remainingRequests <= 0 && _limitReset > DateTimeOffset.UtcNow) + HttpResponseMessage result = null; + try + { + await _semaphore.WaitAsync().ConfigureAwait(false); + _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} Start Request {{0}}", url); + result = await _client.GetAsync(url).ConfigureAwait(false); + if (result.IsSuccessStatusCode) { - _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} Rate Limit reached. Waiting for {{0}}", DateTimeOffset.UtcNow - _limitReset); - await _limitReset.DelayUntil().ConfigureAwait(false); + string json = await result.Content.ReadAsStringAsync().ConfigureAwait(false); + IpResult ipResult = JsonConvert.DeserializeObject(json); + _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} Request Success for IP: {{0}}. IP Success: {{1}} Message: {{2}} Body:\n{{3}} ", url, ipResult?.IsSuccess ?? false, ipResult?.Message, json); + return ipResult?.IsSuccess ?? false ? ipResult : null; } - - HttpResponseMessage result = null; - try - { - await _semaphore.WaitAsync().ConfigureAwait(false); - _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} Start Request {{0}}", url); - result = await _client.GetAsync(url).ConfigureAwait(false); - if (result.IsSuccessStatusCode) - { - string json = await result.Content.ReadAsStringAsync().ConfigureAwait(false); - IpResult ipResult = JsonConvert.DeserializeObject(json); - _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} Request Success for IP: {{0}}. IP Success: {{1}} Message: {{2}} Body:\n{{3}} ", url, ipResult?.IsSuccess ?? false, ipResult?.Message, json); - return ipResult?.IsSuccess ?? false ? ipResult : null; - } + if (retries >= MaxRetries) + { _logger.Error($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} An error occured during request. Code: {{0}} Message: {{1}}", result.StatusCode, await result.Content.ReadAsStringAsync().ConfigureAwait(false)); - - switch (result.StatusCode) - { - case HttpStatusCode.ServiceUnavailable: - case HttpStatusCode.InternalServerError: - await (DateTimeOffset.UtcNow + TimeSpan.FromSeconds(1)).DelayUntil().ConfigureAwait(false); - return await GetCountryCodeInternal(url, retries + 1).ConfigureAwait(false); - } - - return null; } - catch (JsonSerializationException ex) - { - _logger.Exception($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} An error occured during JSON serialization.", ex); - return null; + + switch (result.StatusCode) + { + case HttpStatusCode.ServiceUnavailable: + case HttpStatusCode.InternalServerError: + await (DateTimeOffset.UtcNow + TimeSpan.FromSeconds(1)).DelayUntil().ConfigureAwait(false); + return await GetCountryCodeInternal(url, retries).ConfigureAwait(false); } - catch (Exception ex) + + return null; + } + catch (JsonSerializationException ex) + { + _logger.Exception($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} An error occured during JSON serialization.", ex); + return null; + } + catch (Exception ex) + { + if (retries >= MaxRetries) { _logger.Exception($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} An error occured during IP lookup.", ex); - await (DateTimeOffset.UtcNow + TimeSpan.FromSeconds(1)).DelayUntil().ConfigureAwait(false); - return await GetCountryCodeInternal(url, retries + 1).ConfigureAwait(false); } - finally + + await (DateTimeOffset.UtcNow + TimeSpan.FromSeconds(1)).DelayUntil().ConfigureAwait(false); + return await GetCountryCodeInternal(url, retries).ConfigureAwait(false); + } + finally + { + _semaphore.Release(); + if (result?.Headers != null) { - _semaphore.Release(); - if (result?.Headers != null) - { - ParseHeaders(result.Headers); - } + ParseHeaders(result.Headers); } } + } - private void ParseHeaders(HttpResponseHeaders headers) + private void ParseHeaders(HttpResponseHeaders headers) + { + if (headers.TryGetInt(RemainingRequestsHeader, out int remaining) && remaining < _remainingRequests) { - if (headers.TryGetInt(RemainingRequestsHeader, out int remaining) && remaining < _remainingRequests) - { - _remainingRequests = remaining; - } + _remainingRequests = remaining; + } - if (headers.TryGetInt(RemainingSecondsHeader, out int seconds)) + if (headers.TryGetInt(RemainingSecondsHeader, out int seconds)) + { + DateTimeOffset reset = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds) + TimeSpan.FromMilliseconds(25); + if (reset > _limitReset) { - DateTimeOffset reset = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds) + TimeSpan.FromMilliseconds(25); - if (reset > _limitReset) - { - _remainingRequests = remaining; - _limitReset = reset; - } + _remainingRequests = remaining; + _limitReset = reset; } - - _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} Parsed Headers. Remaining: {{0}} Limit Reset At: {{1}}", _remainingRequests, _limitReset); } + + _logger.Verbose($"{nameof(IpApiService)}.{nameof(GetCountryCodeInternal)} Parsed Headers. Remaining: {{0}} Limit Reset At: {{1}}", _remainingRequests, _limitReset); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Services/IpApi/IpResult.cs b/Oxide.Ext.Discord/Services/IpApi/IpResult.cs index 04448837d..22e318e41 100644 --- a/Oxide.Ext.Discord/Services/IpApi/IpResult.cs +++ b/Oxide.Ext.Discord/Services/IpApi/IpResult.cs @@ -1,21 +1,20 @@ using Newtonsoft.Json; -namespace Oxide.Ext.Discord.Services.IpApi +namespace Oxide.Ext.Discord.Services.IpApi; + +internal class IpResult { - internal class IpResult - { - [JsonProperty("status")] - public string Status { get; set; } + [JsonProperty("status")] + public string Status { get; set; } - [JsonProperty("message")] - public string Message { get; set; } + [JsonProperty("message")] + public string Message { get; set; } - [JsonProperty("country")] - public string Country { get; set; } + [JsonProperty("country")] + public string Country { get; set; } - [JsonProperty("countryCode")] - public string CountryCode { get; set; } + [JsonProperty("countryCode")] + public string CountryCode { get; set; } - public bool IsSuccess => Status == "success"; - } + public bool IsSuccess => Status == "success"; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Services/PlayerSearch/CovalenceSearchService.cs b/Oxide.Ext.Discord/Services/PlayerSearch/CovalenceSearchService.cs index b31dec529..6a63790db 100644 --- a/Oxide.Ext.Discord/Services/PlayerSearch/CovalenceSearchService.cs +++ b/Oxide.Ext.Discord/Services/PlayerSearch/CovalenceSearchService.cs @@ -3,38 +3,37 @@ using Oxide.Core.Libraries.Covalence; using Oxide.Ext.Discord.Cache; -namespace Oxide.Ext.Discord.Services +namespace Oxide.Ext.Discord.Services; + +internal class CovalenceSearchService : IPlayerSearchService { - internal class CovalenceSearchService : IPlayerSearchService + public IEnumerable GetOnlinePlayers(string name) { - public IEnumerable GetOnlinePlayers(string name) + foreach (IPlayer player in OxideLibrary.Instance.Covalence.Players.Connected) { - foreach (IPlayer player in OxideLibrary.Instance.Covalence.Players.Connected) + if (IsMatch(player, name)) { - if (IsMatch(player, name)) - { - yield return player; - } + yield return player; } } + } - public IEnumerable GetAllPlayers(string name) + public IEnumerable GetAllPlayers(string name) + { + foreach (IPlayer player in OxideLibrary.Instance.Covalence.Players.All) { - foreach (IPlayer player in OxideLibrary.Instance.Covalence.Players.All) + if (IsMatch(player, name)) { - if (IsMatch(player, name)) - { - yield return player; - } + yield return player; } } + } - private static bool IsMatch(IPlayer player, string name) => !string.IsNullOrWhiteSpace(name) && player.Name.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1; + private static bool IsMatch(IPlayer player, string name) => !string.IsNullOrWhiteSpace(name) && player.Name.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1; - public void OnUserConnected(IPlayer player) { } + public void OnUserConnected(IPlayer player) { } - public void OnUserDisconnected(IPlayer player) { } + public void OnUserDisconnected(IPlayer player) { } - public void OnUserNameUpdated(IPlayer player, string oldName, string newName) {} - } + public void OnUserNameUpdated(IPlayer player, string oldName, string newName) {} } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Services/PlayerSearch/IPlayerSearchService.cs b/Oxide.Ext.Discord/Services/PlayerSearch/IPlayerSearchService.cs index 30f402ad7..54047e46d 100644 --- a/Oxide.Ext.Discord/Services/PlayerSearch/IPlayerSearchService.cs +++ b/Oxide.Ext.Discord/Services/PlayerSearch/IPlayerSearchService.cs @@ -1,17 +1,16 @@ using System.Collections.Generic; using Oxide.Core.Libraries.Covalence; -namespace Oxide.Ext.Discord.Services +namespace Oxide.Ext.Discord.Services; + +internal interface IPlayerSearchService { - internal interface IPlayerSearchService - { - IEnumerable GetOnlinePlayers(string name); - IEnumerable GetAllPlayers(string name); + IEnumerable GetOnlinePlayers(string name); + IEnumerable GetAllPlayers(string name); - void OnUserConnected(IPlayer player); + void OnUserConnected(IPlayer player); - void OnUserDisconnected(IPlayer player); + void OnUserDisconnected(IPlayer player); - void OnUserNameUpdated(IPlayer player, string oldName, string newName); - } + void OnUserNameUpdated(IPlayer player, string oldName, string newName); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Services/PlayerSearch/UkkonenTrieService.cs b/Oxide.Ext.Discord/Services/PlayerSearch/UkkonenTrieService.cs index a1acf8608..41bd1bb51 100644 --- a/Oxide.Ext.Discord/Services/PlayerSearch/UkkonenTrieService.cs +++ b/Oxide.Ext.Discord/Services/PlayerSearch/UkkonenTrieService.cs @@ -3,46 +3,45 @@ using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.Services +namespace Oxide.Ext.Discord.Services; + +internal class UkkonenTrieService : IPlayerSearchService { - internal class UkkonenTrieService : IPlayerSearchService - { - private readonly UkkonenTrie _online = new UkkonenTrie(PlayerEquals); - private readonly UkkonenTrie _all = new UkkonenTrie(PlayerEquals); + private readonly UkkonenTrie _online = new(PlayerEquals); + private readonly UkkonenTrie _all = new(PlayerEquals); - internal UkkonenTrieService() + internal UkkonenTrieService() + { + foreach (IPlayer player in OxideLibrary.Instance.Covalence.Players.All) { - foreach (IPlayer player in OxideLibrary.Instance.Covalence.Players.All) - { - _all.Add(player.Name, player); - } + _all.Add(player.Name, player); + } - foreach (IPlayer player in OxideLibrary.Instance.Covalence.Players.Connected) - { - _all.Add(player.Name, player); - } + foreach (IPlayer player in OxideLibrary.Instance.Covalence.Players.Connected) + { + _all.Add(player.Name, player); } + } - public IEnumerable GetOnlinePlayers(string name) => _online.Search(name); + public IEnumerable GetOnlinePlayers(string name) => _online.Search(name); - public IEnumerable GetAllPlayers(string name) => _all.Search(name); + public IEnumerable GetAllPlayers(string name) => _all.Search(name); - public void OnUserConnected(IPlayer player) - { - _all.Remove(player.Name, player); - _online.Remove(player.Name, player); - _all.Add(player.Name, player); - _online.Add(player.Name, player); - } + public void OnUserConnected(IPlayer player) + { + _all.Remove(player.Name, player); + _online.Remove(player.Name, player); + _all.Add(player.Name, player); + _online.Add(player.Name, player); + } - public void OnUserDisconnected(IPlayer player) => _online.Remove(player.Name, player); + public void OnUserDisconnected(IPlayer player) => _online.Remove(player.Name, player); - public void OnUserNameUpdated(IPlayer player, string oldName, string newName) - { - _all.Remove(oldName, player); - _all.Add(newName, player); - } - - private static bool PlayerEquals(IPlayer left, IPlayer right) => left.Id == right.Id; + public void OnUserNameUpdated(IPlayer player, string oldName, string newName) + { + _all.Remove(oldName, player); + _all.Add(newName, player); } + + private static bool PlayerEquals(IPlayer left, IPlayer right) => left.Id == right.Id; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/BidirectionalDictionary.cs b/Oxide.Ext.Discord/Types/BidirectionalDictionary.cs index 082bea57c..cc1529fa5 100644 --- a/Oxide.Ext.Discord/Types/BidirectionalDictionary.cs +++ b/Oxide.Ext.Discord/Types/BidirectionalDictionary.cs @@ -2,125 +2,141 @@ using System.Collections.Generic; using System.Collections.ObjectModel; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// A Dictionary that stores the keys -> values and values -> keys +/// +/// Type of the key +/// Type of the value +internal class BidirectionalDictionary { + private readonly Dictionary _keyToValue = new(); + private readonly Dictionary _valueToKey = new(); + /// - /// A Dictionary that stores the keys -> values and values -> keys + /// Count of the /// - /// Type of the key - /// Type of the value - internal class BidirectionalDictionary - { - private readonly Dictionary _keyToValue = new Dictionary(); - private readonly Dictionary _valueToKey = new Dictionary(); - - /// - /// Count of the - /// - public int Count => Math.Min(_keyToValue.Count, _valueToKey.Count); - - /// - /// Returns true of the dictionary contains the given key - /// - /// Key to check for - /// - public bool ContainsKey(TKey key) => _keyToValue.ContainsKey(key); - - /// - /// Returns true of the dictionary contains the given key - /// - /// Key to check for - /// - public bool ContainsKey(TValue key) => _valueToKey.ContainsKey(key); - - public bool TryGetValue(TKey key, out TValue value) => _keyToValue.TryGetValue(key, out value); + public int Count => Math.Min(_keyToValue.Count, _valueToKey.Count); - public bool TryGetValue(TValue key, out TKey value) => _valueToKey.TryGetValue(key, out value); + /// + /// Returns true of the dictionary contains the given key + /// + /// Key to check for + /// + public bool ContainsKey(TKey key) => _keyToValue.ContainsKey(key); - public TValue this[TKey key] - { - get => _keyToValue[key]; - set - { - _keyToValue[key] = value; - _valueToKey[value] = key; - } - } + /// + /// Returns true of the dictionary contains the given key + /// + /// Key to check for + /// + public bool ContainsKey(TValue key) => _valueToKey.ContainsKey(key); - public TKey this[TValue key] - { - get => _valueToKey[key]; - set - { - _valueToKey[key] = value; - _keyToValue[value] = key; - } - } + public bool TryGetValue(TKey key, out TValue value) => _keyToValue.TryGetValue(key, out value); - public void Add(TKey key, TValue value) - { - _valueToKey.Add(value, key); - _keyToValue.Add(key, value); - } - - public void Add(TValue key, TKey value) - { - _keyToValue.Add(value, key); - _valueToKey.Add(key, value); - } + public bool TryGetValue(TValue key, out TKey value) => _valueToKey.TryGetValue(key, out value); - public void AddKey(TKey key, TValue value) + public TValue this[TKey key] + { + get => _keyToValue[key]; + set { _keyToValue[key] = value; + _valueToKey[value] = key; } + } - public void AddValue(TValue key, TKey value) + public TKey this[TValue key] + { + get => _valueToKey[key]; + set { _valueToKey[key] = value; + _keyToValue[value] = key; } + } - public bool Remove(TKey key) - { - if (!_keyToValue.TryGetValue(key, out TValue valueKey)) - { - return false; - } - - _keyToValue.Remove(key); - if (_valueToKey.TryGetValue(valueKey, out TKey _)) - { - _valueToKey.Remove(valueKey); - } - - return true; - } + public void Add(TKey key, TValue value) + { + _valueToKey.Add(value, key); + _keyToValue.Add(key, value); + } - public bool Remove(TValue key) + public void Add(TValue key, TKey value) + { + _keyToValue.Add(value, key); + _valueToKey.Add(key, value); + } + + public void AddKey(TKey key, TValue value) + { + _keyToValue[key] = value; + } + + public void AddValue(TValue key, TKey value) + { + _valueToKey[key] = value; + } + + public bool Remove(TKey key) + { + if (!_keyToValue.Remove(key, out TValue valueKey)) { - if (!_valueToKey.TryGetValue(key, out TKey valueKey)) - { - return false; - } - - _valueToKey.Remove(key); - if (_keyToValue.TryGetValue(valueKey, out TValue _)) - { - _keyToValue.Remove(valueKey); - } - - return true; + return false; } - public void Clear() + _valueToKey.Remove(valueKey, out TKey _); + + return true; + } + + public bool Remove(TValue key) + { + if (!_valueToKey.Remove(key, out TKey valueKey)) { - _keyToValue.Clear(); - _valueToKey.Clear(); + return false; } - public ReadOnlyDictionary AsReadOnlyKeyToValue() => new ReadOnlyDictionary(_keyToValue); - public ReadOnlyDictionary AsReadOnlyValueToKey() => new ReadOnlyDictionary(_valueToKey); + _keyToValue.Remove(valueKey, out TValue _); + + return true; + } + + public void Clear() + { + _keyToValue.Clear(); + _valueToKey.Clear(); + } - public ICollection AsKeyCollection() => _keyToValue.Keys; - public ICollection AsValueCollection() => _valueToKey.Keys; + public ReadOnlyDictionary AsReadOnlyKeyToValue() => new(_keyToValue); + public ReadOnlyDictionary AsReadOnlyValueToKey() => new(_valueToKey); + + public ICollection AsKeyCollection() => _keyToValue.Keys; + public ICollection AsValueCollection() => _valueToKey.Keys; + + public override string ToString() + { + ValueStringBuilder sb = new(); + + sb.AppendLine(nameof(BidirectionalDictionary)); + sb.AppendLine("{"); + sb.AppendLine("\tKeyToValue:"); + sb.AppendLine("\t{"); + foreach (TKey key in _keyToValue.Keys) + { + sb.AppendLine($"\t\t{key}: {_keyToValue[key]}"); + } + sb.AppendLine("\t}"); + sb.AppendLine("\valueToKey:"); + sb.AppendLine("\t{"); + foreach (TValue key in _valueToKey.Keys) + { + sb.AppendLine($"\t\t{key}: {_valueToKey[key]}"); + } + sb.AppendLine("\t}"); + sb.AppendLine("}"); + + return sb.ToString(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Hooks/DiscordHook.cs b/Oxide.Ext.Discord/Types/Hooks/DiscordHook.cs index 14f783207..68f83cba2 100644 --- a/Oxide.Ext.Discord/Types/Hooks/DiscordHook.cs +++ b/Oxide.Ext.Discord/Types/Hooks/DiscordHook.cs @@ -1,222 +1,216 @@ -using System; using System.Collections.Generic; +using Oxide.Core; using Oxide.Core.Plugins; using Oxide.Ext.Discord.Callbacks; using Oxide.Ext.Discord.Clients; using Oxide.Ext.Discord.Extensions; using Oxide.Ext.Discord.Interfaces; -using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Types -{ - internal class DiscordHook - { - private readonly DiscordHookCache _cache; - private readonly ILogger _logger; +namespace Oxide.Ext.Discord.Types; - private static readonly DiscordHookCache Global = new DiscordHookCache(DiscordExtension.GlobalLogger); +internal class DiscordHook +{ + private readonly DiscordHookCache _cache; + private readonly ILogger _logger; - internal DiscordHook(ILogger logger) - { - _logger = logger; - _cache = new DiscordHookCache(logger); - } + internal DiscordHook(ILogger logger) + { + _logger = logger; + _cache = new DiscordHookCache(logger); + } - #region Plugin Handling - internal void AddPlugin(DiscordClient client, PluginSetup setup) - { - _cache.AddPlugin(client, setup.PluginHooks); - Global.AddPlugin(client, setup.GlobalHooks); - } + #region Plugin Handling + internal void AddPlugin(DiscordClient client) + { + _cache.AddPlugin(client, client.PluginSetup.PluginHooks); + } - internal void RemovePlugin(Plugin plugin) + internal void RemovePlugin(Plugin plugin) + { + _cache.RemovePlugin(plugin); + } + #endregion + + #region Hooks + internal void CallHook(string hookName) => CallHookInternal(_cache, hookName); + internal void CallHook(string hookName, T0 arg0) => CallHookInternal(_cache, hookName, arg0); + internal void CallHook(string hookName, T0 arg0, T1 arg1) => CallHookInternal(_cache, hookName, arg0, arg1); + internal void CallHook(string hookName, T0 arg0, T1 arg1, T2 arg2) => CallHookInternal(_cache, hookName, arg0, arg1, arg2); + internal void CallHook(string hookName, T0 arg0, T1 arg1, T2 arg2, T3 arg3) => CallHookInternal(_cache, hookName, arg0, arg1, arg2, arg3); + internal void CallHook(string hookName, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) => CallHookInternal(_cache, hookName, arg0, arg1, arg2, arg3, arg4); + #endregion + + #region Global Hooks + internal static void CallGlobalHook(string hookName) => Interface.Oxide.CallHook(hookName); + internal static void CallGlobalHook(string hookName, T0 arg0) => Interface.Oxide.CallHook(hookName, arg0); + internal static void CallGlobalHook(string hookName, T0 arg0, T1 arg1) => Interface.Oxide.CallHook(hookName, arg0, arg1); + internal static void CallGlobalHook(string hookName, T0 arg0, T1 arg1, T2 arg2) => Interface.Oxide.CallHook(hookName, arg0, arg1, arg2); + internal static void CallGlobalHook(string hookName, T0 arg0, T1 arg1, T2 arg2, T3 arg3) => Interface.Oxide.CallHook(hookName, arg0, arg1, arg2, arg3); + #endregion + + #region Plugin Hooks + internal static void CallPluginHook(Plugin plugin, string name) => CallHookInternal(plugin, name); + internal static void CallPluginHook(Plugin plugin, string name, T0 arg0) => CallHookInternal(plugin, name, arg0); + internal static void CallPluginHook(Plugin plugin, string name, T0 arg0, T1 arg1) => CallHookInternal(plugin, name, arg0, arg1); + internal static void CallPluginHook(Plugin plugin, string name, T0 arg0, T1 arg1, T2 arg2) => CallHookInternal(plugin, name, arg0, arg1, arg2); + internal static void CallPluginHook(Plugin plugin, string name, T0 arg0, T1 arg1, T2 arg2, T3 arg3) => CallHookInternal(plugin, name, arg0, arg1, arg2, arg3); + #endregion + + #region Internal Handling + private static bool CanCallHook(DiscordHookCache cache, string hookName, out List plugins) => cache.TryGetHook(hookName, out plugins) && plugins.Count != 0; + private static void CallHookInternal(Plugin plugin, string hookName, object[] args) + { + if (ThreadEx.IsMain) { - _cache.RemovePlugin(plugin); - Global.RemovePlugin(plugin); + CallHook(plugin, hookName, args); + return; } - #endregion - - #region Hooks - internal void CallHook(string hookName) => CallHookInternal(_cache, hookName); - internal void CallHook(string hookName, T0 arg0) => CallHookInternal(_cache, hookName, arg0); - internal void CallHook(string hookName, T0 arg0, T1 arg1) => CallHookInternal(_cache, hookName, arg0, arg1); - internal void CallHook(string hookName, T0 arg0, T1 arg1, T2 arg2) => CallHookInternal(_cache, hookName, arg0, arg1, arg2); - internal void CallHook(string hookName, T0 arg0, T1 arg1, T2 arg2, T3 arg3) => CallHookInternal(_cache, hookName, arg0, arg1, arg2, arg3); - internal void CallHook(string hookName, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) => CallHookInternal(_cache, hookName, arg0, arg1, arg2, arg3, arg4); - #endregion - - #region Global Hooks - internal static void CallGlobalHook(string hookName) => CallHookInternal(Global, hookName); - internal static void CallGlobalHook(string hookName, T0 arg0) => CallHookInternal(Global, hookName, arg0); - internal static void CallGlobalHook(string hookName, T0 arg0, T1 arg1) => CallHookInternal(Global, hookName, arg0, arg1); - internal static void CallGlobalHook(string hookName, T0 arg0, T1 arg1, T2 arg2) => CallHookInternal(Global, hookName, arg0, arg1, arg2); - internal static void CallGlobalHook(string hookName, T0 arg0, T1 arg1, T2 arg2, T3 arg3) => CallHookInternal(Global, hookName, arg0, arg1, arg2, arg3); - #endregion - - #region Plugin Hooks - internal static void CallPluginHook(Plugin plugin, string name) => CallHookInternal(plugin, name); - internal static void CallPluginHook(Plugin plugin, string name, T0 arg0) => CallHookInternal(plugin, name, arg0); - internal static void CallPluginHook(Plugin plugin, string name, T0 arg0, T1 arg1) => CallHookInternal(plugin, name, arg0, arg1); - internal static void CallPluginHook(Plugin plugin, string name, T0 arg0, T1 arg1, T2 arg2) => CallHookInternal(plugin, name, arg0, arg1, arg2); - internal static void CallPluginHook(Plugin plugin, string name, T0 arg0, T1 arg1, T2 arg2, T3 arg3) => CallHookInternal(plugin, name, arg0, arg1, arg2, arg3); - #endregion - - #region Internal Handling - private static bool CanCallHook(DiscordHookCache cache, string hookName, out List plugins) => cache.TryGetHook(hookName, out plugins) && plugins.Count != 0; - private static void CallHookInternal(Plugin plugin, string hookName, object[] args) - { - if (ThreadEx.IsMain) - { - CallHook(plugin, hookName, args); - return; - } - PluginHookCallback.Start(plugin, hookName, args); - } + PluginHookCallback.Start(plugin, hookName, args); + } - private static void CallHookInternal(List plugins, string hookName, object[] args) + private static void CallHookInternal(List plugins, string hookName, object[] args) + { + if (ThreadEx.IsMain) { - if (ThreadEx.IsMain) - { - CallHook(plugins, hookName, args); - return; - } - - PluginHookCallback.Start(plugins, hookName, args); + CallHook(plugins, hookName, args); + return; } + + PluginHookCallback.Start(plugins, hookName, args); + } - private static void CallHookInternal(Plugin plugin, string name) => CallHookInternal(plugin, name, GetArgs()); - private static void CallHookInternal(Plugin plugin, string name, T0 arg0) => CallHookInternal(plugin, name, GetArgs(arg0)); - private static void CallHookInternal(Plugin plugin, string name, T0 arg0, T1 arg1) => CallHookInternal(plugin, name, GetArgs(arg0, arg1)); - private static void CallHookInternal(Plugin plugin, string name, T0 arg0, T1 arg1, T2 arg2) => CallHookInternal(plugin, name, GetArgs(arg0, arg1, arg2)); - private static void CallHookInternal(Plugin plugin, string name, T0 arg0, T1 arg1, T2 arg2, T3 arg3) => CallHookInternal(plugin, name, GetArgs(arg0, arg1, arg2, arg3)); + private static void CallHookInternal(Plugin plugin, string name) => CallHookInternal(plugin, name, GetArgs()); + private static void CallHookInternal(Plugin plugin, string name, T0 arg0) => CallHookInternal(plugin, name, GetArgs(arg0)); + private static void CallHookInternal(Plugin plugin, string name, T0 arg0, T1 arg1) => CallHookInternal(plugin, name, GetArgs(arg0, arg1)); + private static void CallHookInternal(Plugin plugin, string name, T0 arg0, T1 arg1, T2 arg2) => CallHookInternal(plugin, name, GetArgs(arg0, arg1, arg2)); + private static void CallHookInternal(Plugin plugin, string name, T0 arg0, T1 arg1, T2 arg2, T3 arg3) => CallHookInternal(plugin, name, GetArgs(arg0, arg1, arg2, arg3)); - private static void CallHookInternal(DiscordHookCache cache, string name) + private static void CallHookInternal(DiscordHookCache cache, string name) + { + if (CanCallHook(cache, name, out List plugins)) { - if (CanCallHook(cache, name, out List plugins)) - { - CallHookInternal(plugins, name, GetArgs()); - } + CallHookInternal(plugins, name, GetArgs()); } + } - private static void CallHookInternal(DiscordHookCache cache, string name, T0 arg0) + private static void CallHookInternal(DiscordHookCache cache, string name, T0 arg0) + { + if (CanCallHook(cache, name, out List plugins)) { - if (CanCallHook(cache, name, out List plugins)) - { - CallHookInternal(plugins, name, GetArgs(arg0)); - } + CallHookInternal(plugins, name, GetArgs(arg0)); } + } - private static void CallHookInternal(DiscordHookCache cache, string name, T0 arg0, T1 arg1) + private static void CallHookInternal(DiscordHookCache cache, string name, T0 arg0, T1 arg1) + { + if (CanCallHook(cache, name, out List plugins)) { - if (CanCallHook(cache, name, out List plugins)) - { - CallHookInternal(plugins, name, GetArgs(arg0, arg1)); - } + CallHookInternal(plugins, name, GetArgs(arg0, arg1)); } + } - private static void CallHookInternal(DiscordHookCache cache, string name, T0 arg0, T1 arg1, T2 arg2) + private static void CallHookInternal(DiscordHookCache cache, string name, T0 arg0, T1 arg1, T2 arg2) + { + if (CanCallHook(cache, name, out List plugins)) { - if (CanCallHook(cache, name, out List plugins)) - { - CallHookInternal(plugins, name, GetArgs(arg0, arg1, arg2)); - } + CallHookInternal(plugins, name, GetArgs(arg0, arg1, arg2)); } + } - private static void CallHookInternal(DiscordHookCache cache, string name, T0 arg0, T1 arg1, T2 arg2, T3 arg3) + private static void CallHookInternal(DiscordHookCache cache, string name, T0 arg0, T1 arg1, T2 arg2, T3 arg3) + { + if (CanCallHook(cache, name, out List plugins)) { - if (CanCallHook(cache, name, out List plugins)) - { - CallHookInternal(plugins, name, GetArgs(arg0, arg1, arg2, arg3)); - } + CallHookInternal(plugins, name, GetArgs(arg0, arg1, arg2, arg3)); } + } - private static void CallHookInternal(DiscordHookCache cache, string name, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + private static void CallHookInternal(DiscordHookCache cache, string name, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + if (CanCallHook(cache, name, out List plugins)) { - if (CanCallHook(cache, name, out List plugins)) - { - CallHookInternal(plugins, name, GetArgs(arg0, arg1, arg2, arg3, arg4)); - } + CallHookInternal(plugins, name, GetArgs(arg0, arg1, arg2, arg3, arg4)); } + } - private static object[] GetArgs() - { - return Array.Empty(); - } + private static object[] GetArgs() + { + return []; + } - private static object[] GetArgs( T0 arg0) - { - object[] args = ArrayPool.Instance.Get(1); - args[0] = arg0; - return args; - } + private static object[] GetArgs( T0 arg0) + { + object[] args = ArrayPool.Instance.Get(1); + args[0] = arg0; + return args; + } - private static object[] GetArgs(T0 arg0, T1 arg1) - { - object[] args = ArrayPool.Instance.Get(2); - args[0] = arg0; - args[1] = arg1; - return args; - } + private static object[] GetArgs(T0 arg0, T1 arg1) + { + object[] args = ArrayPool.Instance.Get(2); + args[0] = arg0; + args[1] = arg1; + return args; + } - private static object[] GetArgs(T0 arg0, T1 arg1, T2 arg2) - { - object[] args = ArrayPool.Instance.Get(3); - args[0] = arg0; - args[1] = arg1; - args[2] = arg2; - return args; - } + private static object[] GetArgs(T0 arg0, T1 arg1, T2 arg2) + { + object[] args = ArrayPool.Instance.Get(3); + args[0] = arg0; + args[1] = arg1; + args[2] = arg2; + return args; + } - private static object[] GetArgs( T0 arg0, T1 arg1, T2 arg2, T3 arg3) - { - object[] args = ArrayPool.Instance.Get(4); - args[0] = arg0; - args[1] = arg1; - args[2] = arg2; - args[3] = arg3; - return args; - } + private static object[] GetArgs( T0 arg0, T1 arg1, T2 arg2, T3 arg3) + { + object[] args = ArrayPool.Instance.Get(4); + args[0] = arg0; + args[1] = arg1; + args[2] = arg2; + args[3] = arg3; + return args; + } - private static object[] GetArgs( T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) - { - object[] args = ArrayPool.Instance.Get(5); - args[0] = arg0; - args[1] = arg1; - args[2] = arg2; - args[3] = arg3; - args[4] = arg4; - return args; - } - #endregion + private static object[] GetArgs( T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + object[] args = ArrayPool.Instance.Get(5); + args[0] = arg0; + args[1] = arg1; + args[2] = arg2; + args[3] = arg3; + args[4] = arg4; + return args; + } + #endregion - #region HandleCall - internal static void CallHook(Plugin plugin, string name, object[] args) - { - plugin?.CallHook(name, args); + #region HandleCall + internal static void CallHook(Plugin plugin, string name, object[] args) + { + plugin?.CallHook(name, args); - if (args.Length != 0) - { - ArrayPool.Instance.Free(ref args); - } + if (args.Length != 0) + { + ArrayPool.Instance.Free(ref args); } + } - internal static void CallHook(List plugins, string name, object[] args) + internal static void CallHook(List plugins, string name, object[] args) + { + for (int index = 0; index < plugins.Count; index++) { - for (int index = 0; index < plugins.Count; index++) + Plugin plugin = plugins[index]; + if (plugin.IsLoaded) { - Plugin plugin = plugins[index]; - if (plugin.IsLoaded) - { - plugin.CallHook(name, args); - } + plugin.CallHook(name, args); } + } - if (args.Length != 0) - { - ArrayPool.Instance.Free(ref args); - } + if (args.Length != 0) + { + ArrayPool.Instance.Free(ref args); } - #endregion } + #endregion } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Hooks/DiscordHookCache.cs b/Oxide.Ext.Discord/Types/Hooks/DiscordHookCache.cs index 9cfd57b64..781b023d6 100644 --- a/Oxide.Ext.Discord/Types/Hooks/DiscordHookCache.cs +++ b/Oxide.Ext.Discord/Types/Hooks/DiscordHookCache.cs @@ -10,73 +10,72 @@ using Oxide.Ext.Discord.Logging; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal class DiscordHookCache { - internal class DiscordHookCache + private readonly Hash> _hookCache = new(); + private readonly ILogger _logger; + + internal DiscordHookCache(ILogger logger) { - private readonly Hash> _hookCache = new Hash>(); - private readonly ILogger _logger; + _logger = logger; + } - internal DiscordHookCache(ILogger logger) + internal void AddPlugin(DiscordClient client, List hooks) + { + for (int index = 0; index < hooks.Count; index++) { - _logger = logger; + string hook = hooks[index]; + AddPluginHook(client, hook); } + } - internal void AddPlugin(DiscordClient client, List hooks) + private void AddPluginHook(DiscordClient client, string hook) + { + BotConnection connection = client.Connection; + GatewayIntents intent = DiscordExtHooks.HookGatewayIntent[hook]; + if (intent != GatewayIntents.None && !connection.HasAnyIntent(intent)) { - for (int index = 0; index < hooks.Count; index++) - { - string hook = hooks[index]; - AddPluginHook(client, hook); - } + _logger.Warning("{0} is trying to add hook {1} which requires one of the following GatewayIntents \"{2}\", but only specified \"{3}\" intents " + + "This hook will not work correctly until it is corrected. " + + "Please contact the plugin author {4} with this message.", client.PluginName, hook, EnumCache.Instance.ToString(intent), EnumCache.Instance.ToString(connection.Intents), client.Plugin?.Author); } - private void AddPluginHook(DiscordClient client, string hook) + List hooks = _hookCache[hook]; + if (hooks == null) { - BotConnection connection = client.Connection; - GatewayIntents intent = DiscordExtHooks.HookGatewayIntent[hook]; - if (intent != GatewayIntents.None && !connection.HasAnyIntent(intent)) - { - _logger.Warning("{0} is trying to add hook {1} which requires one of the following GatewayIntents \"{2}\", but only specified \"{3}\" intents " + - "This hook will not work correctly until it is corrected. " + - "Please contact the plugin author {4} with this message.", client.PluginName, hook, EnumCache.Instance.ToString(intent), EnumCache.Instance.ToString(connection.Intents), client.Plugin?.Author); - } - - List hooks = _hookCache[hook]; - if (hooks == null) - { - hooks = new List(); - _hookCache[hook] = hooks; - } - - if (!hooks.Contains(client.Plugin)) - { - hooks.Add(client.Plugin); - } + hooks = new List(); + _hookCache[hook] = hooks; } - internal void RemovePlugin(Plugin plugin) + if (!hooks.Contains(client.Plugin)) { - List hooksToRemove = DiscordPool.Internal.GetList(); - foreach (KeyValuePair> cache in _hookCache) - { - if (cache.Value.Remove(plugin) && cache.Value.Count == 0) - { - hooksToRemove.Add(cache.Key); - } - } + hooks.Add(client.Plugin); + } + } - for (int index = 0; index < hooksToRemove.Count; index++) + internal void RemovePlugin(Plugin plugin) + { + List hooksToRemove = DiscordPool.Internal.GetList(); + foreach (KeyValuePair> cache in _hookCache) + { + if (cache.Value.Remove(plugin) && cache.Value.Count == 0) { - _hookCache.Remove(hooksToRemove[index]); + hooksToRemove.Add(cache.Key); } - - DiscordPool.Internal.FreeList(hooksToRemove); } - internal bool TryGetHook(string hook, out List plugins) + for (int index = 0; index < hooksToRemove.Count; index++) { - return _hookCache.TryGetValue(hook, out plugins); + _hookCache.Remove(hooksToRemove[index]); } + + DiscordPool.Internal.FreeList(hooksToRemove); + } + + internal bool TryGetHook(string hook, out List plugins) + { + return _hookCache.TryGetValue(hook, out plugins); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Network/DiscordStreamContent.cs b/Oxide.Ext.Discord/Types/Network/DiscordStreamContent.cs index af0075787..7aedc74e9 100644 --- a/Oxide.Ext.Discord/Types/Network/DiscordStreamContent.cs +++ b/Oxide.Ext.Discord/Types/Network/DiscordStreamContent.cs @@ -5,41 +5,40 @@ using System.Threading.Tasks; using Oxide.Ext.Discord.Extensions; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Stream content that is sent over HTTP +/// This is used because disposes the underlying stream when disposed and we don't want that since we cache our stream +/// +public class DiscordStreamContent : HttpContent { + private readonly MemoryStream _content; + /// - /// Stream content that is sent over HTTP - /// This is used because disposes the underlying stream when disposed and we don't want that since we cache our stream + /// Constructor /// - public class DiscordStreamContent : HttpContent + /// Stream content to send over HTTP + /// Throws if content is null + public DiscordStreamContent(MemoryStream content) { - private readonly MemoryStream _content; - - /// - /// Constructor - /// - /// Stream content to send over HTTP - /// Throws if content is null - public DiscordStreamContent(MemoryStream content) - { - _content = content ?? throw new ArgumentNullException(nameof(content)); - } - - /// - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) - { - _content.CopyToPooled(stream); - return Task.CompletedTask; - } + _content = content ?? throw new ArgumentNullException(nameof(content)); + } - /// - protected override bool TryComputeLength(out long length) - { - length = _content.Length; - return true; - } + /// + protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) + { + _content.CopyToPooled(stream); + return Task.CompletedTask; + } - /// - protected override Task CreateContentReadStreamAsync() => Task.FromResult(_content); + /// + protected override bool TryComputeLength(out long length) + { + length = _content.Length; + return true; } + + /// + protected override Task CreateContentReadStreamAsync() => Task.FromResult(_content); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/BasePool.cs b/Oxide.Ext.Discord/Types/Pooling/BasePool.cs index 4939063b3..0dd1e311c 100644 --- a/Oxide.Ext.Discord/Types/Pooling/BasePool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/BasePool.cs @@ -5,223 +5,219 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a BasePool in Discord +/// +/// Type being pooled +/// Type of the pool +public abstract class BasePool : IPool + where TPooled : class + where TPool : BasePool, new() { /// - /// Represents a BasePool in Discord + /// Plugin Pool for this pool /// - /// Type being pooled - /// Type of the pool - public abstract class BasePool : IPool - where TPooled : class - where TPool : BasePool, new() - { - /// - /// Plugin Pool for this pool - /// - protected DiscordPluginPool PluginPool; + protected DiscordPluginPool PluginPool; - private TPooled[] _pool; - private int _index; - private readonly object _lock = new object(); - private PoolSize _size; - private bool _isFirstLeakError = true; - private DateTime _nextLeakError; - private bool _isInitialized; + private TPooled[] _pool; + private int _index; + private readonly object _lock = new(); + private PoolSize _size; + private bool _isFirstLeakError = true; + private DateTime _nextLeakError; + private bool _isInitialized; - private static readonly ConcurrentDictionary Pools = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary Pools = new(); - private void InitPool(DiscordPluginPool pluginPool) + private void InitPool(DiscordPluginPool pluginPool) + { + lock (_lock) { - lock (_lock) + if (_isInitialized) { - if (_isInitialized) - { - return; - } - _size = GetPoolSize(pluginPool.Settings); - InvalidPoolException.ThrowIfInvalidPoolSize(_size); - PluginPool = pluginPool; - pluginPool.AddPool(this); - _pool = new TPooled[_size.StartingSize]; - _isInitialized = true; - DiscordExtension.GlobalLogger.Debug("Creating Pool. Plugin ID: {0} Type: {1}", pluginPool.PluginName, typeof(TPool).GetRealTypeName()); + return; } + _size = GetPoolSize(pluginPool.Settings); + InvalidPoolException.ThrowIfInvalidPoolSize(_size); + PluginPool = pluginPool; + pluginPool.AddPool(this); + _pool = new TPooled[_size.StartingSize]; + _isInitialized = true; + DiscordExtension.GlobalLogger.Debug("Creating Pool. Plugin ID: {0} Type: {1}", pluginPool.PluginName, typeof(TPool).GetRealTypeName()); } + } - /// - /// Returns the pool size from the pool settings for the pool - /// - /// - /// - protected abstract PoolSize GetPoolSize(PoolSettings settings); - - /// - /// Returns a pool for the given plugin pool - /// - /// to get the pool from - /// - public static TPool ForPlugin(DiscordPluginPool pluginPool) + /// + /// Returns the pool size from the pool settings for the pool + /// + /// + /// + protected abstract PoolSize GetPoolSize(PoolSettings settings); + + /// + /// Returns a pool for the given plugin pool + /// + /// to get the pool from + /// + public static TPool ForPlugin(DiscordPluginPool pluginPool) + { + TPool pool = Pools.GetOrAdd(pluginPool.PluginId, CreatePool); + if (!pool._isInitialized) { - TPool pool = Pools.GetOrAdd(pluginPool.PluginId, CreatePool); - if (!pool._isInitialized) - { - pool.InitPool(pluginPool); - } - return pool; + pool.InitPool(pluginPool); } + return pool; + } - private static TPool CreatePool(PluginId id) => new TPool(); - /// - /// Returns an element from the pool if it exists else it creates a new one - /// - /// - public TPooled Get() + private static TPool CreatePool(PluginId id) => new(); + /// + /// Returns an element from the pool if it exists else it creates a new one + /// + /// + public TPooled Get() + { + TPooled item = null; + lock (_lock) { - TPooled item = null; - lock (_lock) + if (_index == _pool.Length && _size.CanResize(_pool.Length)) { - if (_index == _pool.Length && _size.CanResize(_pool.Length)) - { - int nextSize = _size.GetNextSize(_pool.Length); - DiscordExtension.GlobalLogger.Debug("{0} Resizing Pool {1} Current Size: {2} Next Size: {3}", PluginPool.PluginName, GetType(), _pool.Length, nextSize); - Array.Resize(ref _pool, nextSize); - } - - if (_index < _pool.Length) - { - item = _pool[_index]; - _pool[_index] = null; - _index++; - } - else if(ShouldLogLeak()) - { - DiscordExtension.GlobalLogger.Warning("{0} Pool {1} is leaking entities!!! {2}/{3}", PluginPool.PluginName, GetType(), _index, _pool.Length); - } + int nextSize = _size.GetNextSize(_pool.Length); + DiscordExtension.GlobalLogger.Debug("{0} Resizing Pool {1} Current Size: {2} Next Size: {3}", PluginPool.PluginName, GetType(), _pool.Length, nextSize); + Array.Resize(ref _pool, nextSize); } - if (item == null) + if (_index < _pool.Length) { - item = CreateNew(); + item = _pool[_index]; + _pool[_index] = null; + _index++; + } + else if(ShouldLogLeak()) + { + DiscordExtension.GlobalLogger.Warning("{0} Pool {1} is leaking entities!!! {2}/{3}", PluginPool.PluginName, GetType(), _index, _pool.Length); } - - OnGetItem(item); - return item; } + + item ??= CreateNew(); + + OnGetItem(item); + return item; + } - private bool ShouldLogLeak() + private bool ShouldLogLeak() + { + if (!PluginPool.PluginId.IsExtensionPlugin) { - if (!PluginPool.PluginId.IsExtensionPlugin) - { - return true; - } + return true; + } - if (_isFirstLeakError) - { - _isFirstLeakError = false; - return false; - } + if (_isFirstLeakError) + { + _isFirstLeakError = false; + return false; + } - if (_nextLeakError < DateTime.UtcNow) - { - return false; - } - - _nextLeakError = DateTime.UtcNow + TimeSpan.FromSeconds(30); - return true; + if (_nextLeakError < DateTime.UtcNow) + { + return false; } + + _nextLeakError = DateTime.UtcNow + TimeSpan.FromSeconds(30); + return true; + } - /// - /// Creates new type of T - /// - /// Newly created type of T - protected abstract TPooled CreateNew(); + /// + /// Creates a new type of T + /// + /// Newly created type of T + protected abstract TPooled CreateNew(); - /// - /// Frees an item back to the pool - /// - /// Item being freed - public void Free(TPooled item) => Free(ref item); + /// + /// Frees an item back to the pool + /// + /// Item being freed + public void Free(TPooled item) => Free(ref item); - private void Free(ref TPooled item) + private void Free(ref TPooled item) + { + if (item == null) { - if (item == null) - { - return; - } + return; + } - if (!OnFreeItem(ref item)) - { - //DiscordExtension.GlobalLogger.Debug("Skip Free Item: {0}", typeof(T).Name); - return; - } + if (!OnFreeItem(ref item)) + { + //DiscordExtension.GlobalLogger.Debug("Skip Free Item: {0}", typeof(T).Name); + return; + } - lock (_lock) + lock (_lock) + { + if (_index != 0) { - if (_index != 0) - { - _index--; - _pool[_index] = item; - } + _index--; + _pool[_index] = item; } - - item = null; } + + item = null; + } - /// - public void OnPluginUnloaded(DiscordPluginPool pluginPool) - { - Pools.TryRemove(pluginPool.PluginId, out TPool _); - } + /// + public void OnPluginUnloaded(DiscordPluginPool pluginPool) + { + Pools.TryRemove(pluginPool.PluginId, out TPool _); + } - /// - /// Clears the pool of all pooled objects and resets state to when the pool was first created - /// - public void ClearPoolEntities() + /// + /// Clears the pool of all pooled objects and resets state to when the pool was first created + /// + public void ClearPoolEntities() + { + lock (_lock) { - lock (_lock) + for (int i = _pool.Length - 1; i >= 0; i--) { - for (int i = _pool.Length - 1; i >= 0; i--) - { - _pool[i] = null; - } - _index = 0; + _pool[i] = null; } + _index = 0; } + } - /// - /// Wipes all the pools for this type - /// - public void RemoveAllPools() - { - Pools.Clear(); - } + /// + /// Wipes all the pools for this type + /// + public void RemoveAllPools() + { + Pools.Clear(); + } - /// - /// Called when an item is retrieved from the pool - /// - /// Item being retrieved - protected virtual void OnGetItem(TPooled item) - { + /// + /// Called when an item is retrieved from the pool + /// + /// Item being retrieved + protected virtual void OnGetItem(TPooled item) + { - } + } - /// - /// Returns if an item can be freed to the pool - /// - /// Item to be freed - /// True if can be freed; false otherwise - protected virtual bool OnFreeItem(ref TPooled item) - { - return true; - } + /// + /// Returns if an item can be freed to the pool + /// + /// Item to be freed + /// True if the item can be freed; false otherwise + protected virtual bool OnFreeItem(ref TPooled item) + { + return true; + } - /// - public void LogDebug(DebugLogger logger) - { - logger.StartObject($"{GetType().GetRealTypeName()}"); - logger.AppendFieldOutOf("Pool", _pool.Length - _index, _pool.Length); - logger.EndObject(); - } + /// + public void LogDebug(DebugLogger logger) + { + logger.StartObject($"{GetType().GetRealTypeName()}"); + logger.AppendFieldOutOf("Pool", _pool.Length - _index, _pool.Length); + logger.EndObject(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/BasePoolable.cs b/Oxide.Ext.Discord/Types/Pooling/BasePoolable.cs index 65df659f1..93a49a8df 100644 --- a/Oxide.Ext.Discord/Types/Pooling/BasePoolable.cs +++ b/Oxide.Ext.Discord/Types/Pooling/BasePoolable.cs @@ -1,79 +1,78 @@ using System; using Oxide.Ext.Discord.Extensions; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a poolable object +/// +public abstract class BasePoolable : IDisposable { + internal DiscordPluginPool PluginPool { get; private set; } + /// - /// Represents a poolable object + /// Returns if the object should be pooled. + /// This field is set to true when leaving the pool. + /// If the object instantiated using new() outside the pool it will be false /// - public abstract class BasePoolable : IDisposable - { - internal DiscordPluginPool PluginPool { get; private set; } - - /// - /// Returns if the object should be pooled. - /// This field is set to true when leaving the pool. - /// If the object instantiated using new() outside the pool it will be false - /// - private bool _shouldPool; - internal bool Disposed; + private bool _shouldPool; + internal bool Disposed; - private IPool _pool; + private IPool _pool; - internal void OnInit(DiscordPluginPool pluginPool, IPool pool) - { - PluginPool = pluginPool; - _pool = pool; - } + internal void OnInit(DiscordPluginPool pluginPool, IPool pool) + { + PluginPool = pluginPool; + _pool = pool; + } - internal void EnterPoolInternal() - { - EnterPool(); - _shouldPool = false; - Disposed = true; - } + internal void EnterPoolInternal() + { + EnterPool(); + _shouldPool = false; + Disposed = true; + } - internal void LeavePoolInternal() - { - _shouldPool = true; - Disposed = false; - LeavePool(); - } + internal void LeavePoolInternal() + { + _shouldPool = true; + Disposed = false; + LeavePool(); + } - /// - /// Called when the object is returned to the pool. - /// Can be overriden in child classes to cleanup used data - /// - protected virtual void EnterPool() - { + /// + /// Called when the object is returned to the pool. + /// Can be overriden in child classes to cleanup used data + /// + protected virtual void EnterPool() + { - } + } - /// - /// Called when the object leaves the pool. - /// Can be overriden in child classes to set the initial object state - /// - protected virtual void LeavePool() - { + /// + /// Called when the object leaves the pool. + /// Can be overriden in child classes to set the initial object state + /// + protected virtual void LeavePool() + { - } + } - /// - /// Disposes the object when used in a using statement - /// - public void Dispose() + /// + /// Disposes the object when used in a using statement + /// + public void Dispose() + { + if (!_shouldPool) { - if (!_shouldPool) - { - return; - } + return; + } - if (Disposed) - { - throw new ObjectDisposedException(GetType().GetRealTypeName()); - } - - _pool.Free(this); + if (Disposed) + { + throw new ObjectDisposedException(GetType().GetRealTypeName()); } + + _pool.Free(this); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/DiscordPluginPool.cs b/Oxide.Ext.Discord/Types/Pooling/DiscordPluginPool.cs index f39d43493..f6eb4443a 100644 --- a/Oxide.Ext.Discord/Types/Pooling/DiscordPluginPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/DiscordPluginPool.cs @@ -9,261 +9,260 @@ using Oxide.Ext.Discord.Plugins; using Oxide.Plugins; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Built in pooling for discord entities +/// +public class DiscordPluginPool : IDebugLoggable { - /// - /// Built in pooling for discord entities - /// - public class DiscordPluginPool : IDebugLoggable - { - private readonly List _pools = new List(); - private PoolSettings _settings; + private readonly List _pools = []; + private PoolSettings _settings; - internal PoolSettings Settings => _settings ?? DefaultSettings; - internal readonly PluginId PluginId; - internal readonly string PluginName; + internal PoolSettings Settings => _settings ?? DefaultSettings; + internal readonly PluginId PluginId; + internal readonly string PluginName; - private static readonly PoolSettings DefaultSettings = new PoolSettings(); + private static readonly PoolSettings DefaultSettings = new(); - /// - /// Constructor - /// - /// Plugin the pool is for - public DiscordPluginPool(Plugin plugin) - { - PluginId = plugin.Id(); - PluginName = plugin.FullName(); - } + /// + /// Constructor + /// + /// Plugin the pool is for + public DiscordPluginPool(Plugin plugin) + { + PluginId = plugin.Id(); + PluginName = plugin.FullName(); + } - /// - /// Sets the settings for the pools - /// - /// - public void SetSettings(PoolSettings settings) - { - _settings = settings; - } + /// + /// Sets the settings for the pools + /// + /// + public void SetSettings(PoolSettings settings) + { + _settings = settings; + } - internal void AddPool(IPool pool) => _pools.Add(pool); + internal void AddPool(IPool pool) => _pools.Add(pool); - /// - /// Returns a pooled object of {T} type - /// Must inherit from and have an empty default constructor - /// - /// Type to be returned - /// Pooled object of type T - public T Get() where T : BasePoolable, new() - { - return (T)ObjectPool.ForPlugin(this).Get(); - } + /// + /// Returns a pooled object of {T} type + /// Must inherit from and have an empty default constructor + /// + /// Type to be returned + /// Pooled object of type T + public T Get() where T : BasePoolable, new() + { + return (T)ObjectPool.ForPlugin(this).Get(); + } - /// - /// Returns a back into the pool - /// - /// Object to free - /// Type of object being freed - internal void Free(T value) where T : BasePoolable, new() - { - ObjectPool.ForPlugin(this).Free(value); - } + /// + /// Returns a back into the pool + /// + /// Object to free + /// Type of object being freed + internal void Free(T value) where T : BasePoolable, new() + { + ObjectPool.ForPlugin(this).Free(value); + } - /// - /// Returns a pooled - /// - /// Type for the list - /// Pooled List - public List GetList() - { - return ListPool.ForPlugin(this).Get(); - } + /// + /// Returns a pooled + /// + /// Type for the list + /// Pooled List + public List GetList() + { + return ListPool.ForPlugin(this).Get(); + } - /// - /// Free's a pooled - /// - /// List to be freed - /// Type of the list - public void FreeList(List list) - { - ListPool.ForPlugin(this).Free(list); - } + /// + /// Free's a pooled + /// + /// List to be freed + /// Type of the list + public void FreeList(List list) + { + ListPool.ForPlugin(this).Free(list); + } - /// - /// Returns a pooled - /// - /// Type for the key - /// Type for the value - /// Pooled Hash - public Hash GetHash() - { - return HashPool.ForPlugin(this).Get(); - } + /// + /// Returns a pooled + /// + /// Type for the key + /// Type for the value + /// Pooled Hash + public Hash GetHash() + { + return HashPool.ForPlugin(this).Get(); + } - /// - /// Frees a pooled - /// - /// Hash to be freed - /// Type for key - /// Type for value - public void FreeHash(Hash hash) - { - HashPool.ForPlugin(this).Free(hash); - } + /// + /// Frees a pooled + /// + /// Hash to be freed + /// Type for key + /// Type for value + public void FreeHash(Hash hash) + { + HashPool.ForPlugin(this).Free(hash); + } - /// - /// Returns a pooled - /// - /// Type for the HashSet - /// Pooled List - public HashSet GetHashSet() - { - return HashSetPool.ForPlugin(this).Get(); - } + /// + /// Returns a pooled + /// + /// Type for the HashSet + /// Pooled List + public HashSet GetHashSet() + { + return HashSetPool.ForPlugin(this).Get(); + } - /// - /// Free's a pooled - /// - /// HashSet to be freed - /// Type of the HashSet - public void FreeHashSet(HashSet list) - { - HashSetPool.ForPlugin(this).Free(list); - } + /// + /// Free's a pooled + /// + /// HashSet to be freed + /// Type of the HashSet + public void FreeHashSet(HashSet list) + { + HashSetPool.ForPlugin(this).Free(list); + } - /// - /// Returns a pooled - /// - /// Pooled - public StringBuilder GetStringBuilder() - { - return StringBuilderPool.ForPlugin(this).Get(); - } + /// + /// Returns a pooled + /// + /// Pooled + public StringBuilder GetStringBuilder() + { + return StringBuilderPool.ForPlugin(this).Get(); + } - /// - /// Returns a pooled - /// - /// Initial text for the builder - /// Pooled - public StringBuilder GetStringBuilder(string initial) - { - StringBuilder builder = StringBuilderPool.ForPlugin(this).Get(); - builder.Append(initial); - return builder; - } + /// + /// Returns a pooled + /// + /// Initial text for the builder + /// Pooled + public StringBuilder GetStringBuilder(string initial) + { + StringBuilder builder = StringBuilderPool.ForPlugin(this).Get(); + builder.Append(initial); + return builder; + } - /// - /// Frees a back to the pool - /// - /// StringBuilder being freed - public void FreeStringBuilder(StringBuilder sb) - { - StringBuilderPool.ForPlugin(this).Free(sb); - } + /// + /// Frees a back to the pool + /// + /// StringBuilder being freed + public void FreeStringBuilder(StringBuilder sb) + { + StringBuilderPool.ForPlugin(this).Free(sb); + } - /// - /// Frees a back to the pool returning the built - /// - /// being freed - public string ToStringAndFree(StringBuilder sb) - { - string result = sb?.ToString(); - FreeStringBuilder(sb); - return result; - } + /// + /// Frees a back to the pool returning the built + /// + /// being freed + public string ToStringAndFree(StringBuilder sb) + { + string result = sb?.ToString(); + FreeStringBuilder(sb); + return result; + } - /// - /// Returns a pooled - /// - /// Pooled - public MemoryStream GetMemoryStream() - { - return MemoryStreamPool.ForPlugin(this).Get(); - } + /// + /// Returns a pooled + /// + /// Pooled + public MemoryStream GetMemoryStream() + { + return MemoryStreamPool.ForPlugin(this).Get(); + } - /// - /// Frees a back to the pool - /// - /// being freed - public void FreeMemoryStream(MemoryStream stream) - { - MemoryStreamPool.ForPlugin(this).Free(stream); - } + /// + /// Frees a back to the pool + /// + /// being freed + public void FreeMemoryStream(MemoryStream stream) + { + MemoryStreamPool.ForPlugin(this).Free(stream); + } - /// - /// Returns a pooled - /// - /// Pooled - internal PlaceholderData GetPlaceholderData() - { - return (PlaceholderData)PlaceholderDataPool.ForPlugin(this).Get(); - } + /// + /// Returns a pooled + /// + /// Pooled + internal PlaceholderData GetPlaceholderData() + { + return (PlaceholderData)PlaceholderDataPool.ForPlugin(this).Get(); + } - /// - /// Frees a back to the pool - /// - /// being freed - internal void FreePlaceholderData(PlaceholderData data) - { - PlaceholderDataPool.ForPlugin(this).Free(data); - } + /// + /// Frees a back to the pool + /// + /// being freed + internal void FreePlaceholderData(PlaceholderData data) + { + PlaceholderDataPool.ForPlugin(this).Free(data); + } - /// - /// Returns a pooled - /// - /// Type for the Boxed - /// Pooled Boxed - internal Boxed GetBoxed(T value) - { - Boxed boxed = BoxedPool.ForPlugin(this).Get(); - boxed.Value = value; - return boxed; - } + /// + /// Returns a pooled + /// + /// Type for the Boxed + /// Pooled Boxed + internal Boxed GetBoxed(T value) + { + Boxed boxed = BoxedPool.ForPlugin(this).Get(); + boxed.Value = value; + return boxed; + } - /// - /// Free's a pooled - /// - /// Boxed to be freed - /// Type of the Boxed - internal void FreeBoxed(Boxed boxed) - { - BoxedPool.ForPlugin(this).Free(boxed); - } + /// + /// Free's a pooled + /// + /// Boxed to be freed + /// Type of the Boxed + internal void FreeBoxed(Boxed boxed) + { + BoxedPool.ForPlugin(this).Free(boxed); + } - internal void OnPluginUnloaded() + internal void OnPluginUnloaded() + { + for (int index = 0; index < _pools.Count; index++) { - for (int index = 0; index < _pools.Count; index++) - { - IPool pool = _pools[index]; - pool.OnPluginUnloaded(this); - } + IPool pool = _pools[index]; + pool.OnPluginUnloaded(this); } + } - internal void Clear() + internal void Clear() + { + for (int index = 0; index < _pools.Count; index++) { - for (int index = 0; index < _pools.Count; index++) - { - IPool pool = _pools[index]; - pool.ClearPoolEntities(); - } + IPool pool = _pools[index]; + pool.ClearPoolEntities(); } + } - internal void Wipe() + internal void Wipe() + { + for (int index = 0; index < _pools.Count; index++) { - for (int index = 0; index < _pools.Count; index++) - { - IPool pool = _pools[index]; - pool.RemoveAllPools(); - } + IPool pool = _pools[index]; + pool.RemoveAllPools(); } + } - /// - public void LogDebug(DebugLogger logger) + /// + public void LogDebug(DebugLogger logger) + { + logger.StartArray(PluginId.PluginName()); + foreach (IPool pool in _pools) { - logger.StartArray(PluginId.PluginName()); - foreach (IPool pool in _pools) - { - pool.LogDebug(logger); - } - logger.EndArray(); + pool.LogDebug(logger); } + logger.EndArray(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/Entities/Boxed.cs b/Oxide.Ext.Discord/Types/Pooling/Entities/Boxed.cs index 9d9e47574..48ffbfb72 100644 --- a/Oxide.Ext.Discord/Types/Pooling/Entities/Boxed.cs +++ b/Oxide.Ext.Discord/Types/Pooling/Entities/Boxed.cs @@ -2,40 +2,39 @@ using Oxide.Ext.Discord.Cache; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal class Boxed : IBoxed { - internal class Boxed : IBoxed - { - public T Value; - private bool _disposed; - internal DiscordPluginPool Pool; + public T Value; + private bool _disposed; + internal DiscordPluginPool Pool; - public override string ToString() => StringCache.Instance.ToString(Value); + public override string ToString() => StringCache.Instance.ToString(Value); - internal void LeavePool() - { - _disposed = false; - } + internal void LeavePool() + { + _disposed = false; + } - public IBoxed Copy() - { - return Pool.GetBoxed(Value); - } + public IBoxed Copy() + { + return Pool.GetBoxed(Value); + } - public void Dispose() + public void Dispose() + { + if (_disposed) { - if (_disposed) - { - throw new ObjectDisposedException($"{nameof(Boxed)}<{typeof(T).Name}>"); - } - - _disposed = true; - DiscordPool.Internal.FreeBoxed(this); + throw new ObjectDisposedException($"{nameof(Boxed)}<{typeof(T).Name}>"); } + + _disposed = true; + DiscordPool.Internal.FreeBoxed(this); } +} - internal interface IBoxed : IDisposable - { - IBoxed Copy(); - } +internal interface IBoxed : IDisposable +{ + IBoxed Copy(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/IPool.cs b/Oxide.Ext.Discord/Types/Pooling/IPool.cs index 2faecdc07..78b9fcbd4 100644 --- a/Oxide.Ext.Discord/Types/Pooling/IPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/IPool.cs @@ -1,26 +1,25 @@ using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a pool +/// +public interface IPool : IDebugLoggable { /// - /// Represents a pool + /// Called on a pool when a plugin is unloaded /// - public interface IPool : IDebugLoggable - { - /// - /// Called on a pool when a plugin is unloaded - /// - /// - void OnPluginUnloaded(DiscordPluginPool pluginPool); + /// + void OnPluginUnloaded(DiscordPluginPool pluginPool); - /// - /// Clears the pool of all items - /// - void ClearPoolEntities(); + /// + /// Clears the pool of all items + /// + void ClearPoolEntities(); - /// - /// Wipes all pools of the given type - /// - void RemoveAllPools(); - } + /// + /// Wipes all pools of the given type + /// + void RemoveAllPools(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/IPool{T}.cs b/Oxide.Ext.Discord/Types/Pooling/IPool{T}.cs index cab2937f4..4c8fe81ad 100644 --- a/Oxide.Ext.Discord/Types/Pooling/IPool{T}.cs +++ b/Oxide.Ext.Discord/Types/Pooling/IPool{T}.cs @@ -1,21 +1,20 @@ -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a pool of type T +/// +/// Type to be pooled +public interface IPool : IPool { /// - /// Represents a pool of type T + /// Returns the Pooled type or a new instance if pool is empty. /// - /// Type to be pooled - public interface IPool : IPool - { - /// - /// Returns the Pooled type or a new instance if pool is empty. - /// - /// - T Get(); + /// + T Get(); - /// - /// Returns the pooled type back to the pool - /// - /// - void Free(T poolable); - } + /// + /// Returns the pooled type to the pool + /// + /// + void Free(T poolable); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/PoolSettings.cs b/Oxide.Ext.Discord/Types/Pooling/PoolSettings.cs index 7c04f7278..91856736b 100644 --- a/Oxide.Ext.Discord/Types/Pooling/PoolSettings.cs +++ b/Oxide.Ext.Discord/Types/Pooling/PoolSettings.cs @@ -1,54 +1,53 @@ -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Settings for the pools +/// +public class PoolSettings { /// - /// Settings for the pools + /// Size of the /// - public class PoolSettings - { - /// - /// Size of the - /// - public PoolSize HashPoolSize = new PoolSize(32, 256); + public PoolSize HashPoolSize = new(32, 256); - /// - /// Size of the - /// - public PoolSize HashSetPoolSize { get; set; } = new PoolSize(32, 256); + /// + /// Size of the + /// + public PoolSize HashSetPoolSize { get; set; } = new(32, 256); - /// - /// Size of the - /// - public PoolSize ListPoolSize { get; set; } = new PoolSize(32, 256); + /// + /// Size of the + /// + public PoolSize ListPoolSize { get; set; } = new(32, 256); - /// - /// Size of the - /// - public PoolSize MemoryStreamPoolSize { get; set; } = new PoolSize(32, 256); + /// + /// Size of the + /// + public PoolSize MemoryStreamPoolSize { get; set; } = new(32, 256); - /// - /// Size of the - /// - public PoolSize ObjectPoolSize { get; set; } = new PoolSize(32, 256); + /// + /// Size of the + /// + public PoolSize ObjectPoolSize { get; set; } = new(32, 256); - /// - /// Size of the - /// - public PoolSize PlaceholderDataPoolSize { get; set; } = new PoolSize(32, 512); + /// + /// Size of the + /// + public PoolSize PlaceholderDataPoolSize { get; set; } = new(32, 512); - /// - /// Size of the - /// - public PoolSize StringBuilderPoolSize { get; set; } = new PoolSize(32, 256); + /// + /// Size of the + /// + public PoolSize StringBuilderPoolSize { get; set; } = new(32, 256); - internal static PoolSettings CreateInternal() => new PoolSettings - { - HashPoolSize = new PoolSize(128, 1024), - HashSetPoolSize = new PoolSize(128, 1024), - ListPoolSize = new PoolSize(128, 1024), - MemoryStreamPoolSize = new PoolSize(128, 1024), - ObjectPoolSize = new PoolSize(128, 1024), - PlaceholderDataPoolSize = new PoolSize(128, 1024), - StringBuilderPoolSize = new PoolSize(128, 1024), - }; - } + internal static PoolSettings CreateInternal() => new() + { + HashPoolSize = new PoolSize(128, 1024), + HashSetPoolSize = new PoolSize(128, 1024), + ListPoolSize = new PoolSize(128, 1024), + MemoryStreamPoolSize = new PoolSize(128, 1024), + ObjectPoolSize = new PoolSize(128, 1024), + PlaceholderDataPoolSize = new PoolSize(128, 1024), + StringBuilderPoolSize = new PoolSize(128, 1024), + }; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/PoolSize.cs b/Oxide.Ext.Discord/Types/Pooling/PoolSize.cs index 9b24367e7..5e955ce65 100644 --- a/Oxide.Ext.Discord/Types/Pooling/PoolSize.cs +++ b/Oxide.Ext.Discord/Types/Pooling/PoolSize.cs @@ -1,52 +1,51 @@ using Oxide.Ext.Discord.Exceptions; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents size constraints for a pool +/// +public readonly struct PoolSize { /// - /// Represents size constraints for a pool + /// Starting size of the pool /// - public struct PoolSize - { - /// - /// Starting size of the pool - /// - public readonly int StartingSize; + public readonly int StartingSize; - /// - /// Max size of the pool - /// - public readonly int MaxSize; + /// + /// Max size of the pool + /// + public readonly int MaxSize; - /// - /// If the pool size is valid - /// - public bool IsValid => StartingSize > 0 && MaxSize >= StartingSize; + /// + /// If the pool size is valid + /// + public bool IsValid => StartingSize > 0 && MaxSize >= StartingSize; - /// - /// Constructor settings the startingSize and maxSize - /// - /// Starting size of the pool - /// Max size of the pool - public PoolSize(int startingSize, int maxSize) - { - InvalidPoolException.ThrowIfNotPowerOf2(startingSize, nameof(startingSize)); - InvalidPoolException.ThrowIfNotPowerOf2(maxSize, nameof(maxSize)); - StartingSize = startingSize; - MaxSize = maxSize; - } + /// + /// Constructor settings the startingSize and maxSize + /// + /// Starting size of the pool + /// Max size of the pool + public PoolSize(int startingSize, int maxSize) + { + InvalidPoolException.ThrowIfNotPowerOf2(startingSize, nameof(startingSize)); + InvalidPoolException.ThrowIfNotPowerOf2(maxSize, nameof(maxSize)); + StartingSize = startingSize; + MaxSize = maxSize; + } - /// - /// Returns true of the current size can be resized - /// - /// - /// - public bool CanResize(int currentSize) => GetNextSize(currentSize) <= MaxSize; + /// + /// Returns true of the current size can be resized + /// + /// + /// + public bool CanResize(int currentSize) => GetNextSize(currentSize) <= MaxSize; - /// - /// Returns the next size for the current size - /// - /// - /// - public int GetNextSize(int currentSize) => currentSize << 1; - } + /// + /// Returns the next size for the current size + /// + /// + /// + public int GetNextSize(int currentSize) => currentSize << 1; } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/Pools/ArrayPool.cs b/Oxide.Ext.Discord/Types/Pooling/Pools/ArrayPool.cs index 6f1a84722..2310e6892 100644 --- a/Oxide.Ext.Discord/Types/Pooling/Pools/ArrayPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/Pools/ArrayPool.cs @@ -1,109 +1,108 @@ using System; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal sealed class ArrayPool : Singleton> { - internal sealed class ArrayPool : Singleton> - { - private const int MaxArraySize = 64; - private readonly ArrayPoolInternal[] _pool = new ArrayPoolInternal[MaxArraySize + 1]; + private const int MaxArraySize = 64; + private readonly ArrayPoolInternal[] _pool = new ArrayPoolInternal[MaxArraySize + 1]; - private ArrayPool() { } + private ArrayPool() { } - public TPooled[] Get(int size) + public TPooled[] Get(int size) + { + if (size < 0) throw new ArgumentOutOfRangeException(nameof(size), "Cannot be less than 0"); + if (size == 0) { - if (size < 0) throw new ArgumentOutOfRangeException(nameof(size), "Cannot be less than 0"); - if (size == 0) - { - return Array.Empty(); - } + return []; + } - if (size > MaxArraySize) - { - throw new ArgumentOutOfRangeException(nameof(size), $"Cannot be greater than {MaxArraySize}"); - } + if (size > MaxArraySize) + { + throw new ArgumentOutOfRangeException(nameof(size), $"Cannot be greater than {MaxArraySize}"); + } - ArrayPoolInternal pool = _pool[size]; - if (pool == null) - { - pool = new ArrayPoolInternal(size); - _pool[size] = pool; - } - - return pool.Get(); + ArrayPoolInternal pool = _pool[size]; + if (pool == null) + { + pool = new ArrayPoolInternal(size); + _pool[size] = pool; } - public void Free(ref TPooled[] array) + return pool.Get(); + } + + public void Free(ref TPooled[] array) + { + int size = array.Length; + if (size == 0) { - int size = array.Length; - if (size == 0) - { - return; - } - - if (size > MaxArraySize) - { - throw new ArgumentOutOfRangeException(nameof(array), $"Array length cannot be greater than {MaxArraySize}"); - } + return; + } - _pool[size]?.Free(ref array); + if (size > MaxArraySize) + { + throw new ArgumentOutOfRangeException(nameof(array), $"Array length cannot be greater than {MaxArraySize}"); } + + _pool[size]?.Free(ref array); + } - private class ArrayPoolInternal - { - private const int MaxArrays = 64; - private ushort _index; - private readonly TPooled[][] _pool = new TPooled[MaxArrays][]; - private readonly object _lock = new object(); - private readonly int _arraySize; + private class ArrayPoolInternal + { + private const int MaxArrays = 64; + private ushort _index; + private readonly TPooled[][] _pool = new TPooled[MaxArrays][]; + private readonly object _lock = new(); + private readonly int _arraySize; - public ArrayPoolInternal(int arraySize) - { - _arraySize = arraySize; - } + public ArrayPoolInternal(int arraySize) + { + _arraySize = arraySize; + } - public TPooled[] Get() + public TPooled[] Get() + { + TPooled[] array = null; + lock (_lock) { - TPooled[] array = null; - lock (_lock) + if (_index < _pool.Length) { - if (_index < _pool.Length) - { - array = _pool[_index]; - _pool[_index] = null; - _index++; - } - else - { - DiscordExtension.GlobalLogger.Warning("Pool {0} is leaking entities!!! {1}/{2}", GetType(), _index, _pool.Length); - } + array = _pool[_index]; + _pool[_index] = null; + _index++; + } + else + { + DiscordExtension.GlobalLogger.Warning("Pool {0} is leaking entities!!! {1}/{2}", GetType(), _index, _pool.Length); } - - return array ?? new TPooled[_arraySize]; } + + return array ?? new TPooled[_arraySize]; + } - public void Free(ref TPooled[] item) + public void Free(ref TPooled[] item) + { + if (item == null) { - if (item == null) - { - return; - } + return; + } - for (int index = 0; index < item.Length; ++index) - { - item[index] = default(TPooled); - } + for (int index = 0; index < item.Length; ++index) + { + item[index] = default; + } - lock (_lock) + lock (_lock) + { + if (_index != 0) { - if (_index != 0) - { - _pool[--_index] = item; - } + _pool[--_index] = item; } - - item = null; } + + item = null; } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/Pools/BoxedPool.cs b/Oxide.Ext.Discord/Types/Pooling/Pools/BoxedPool.cs index 963f95720..cb41baf65 100644 --- a/Oxide.Ext.Discord/Types/Pooling/Pools/BoxedPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/Pools/BoxedPool.cs @@ -1,25 +1,24 @@ -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a pool for ; +/// +/// Type that will be in the boxed object +internal class BoxedPool : BasePool, BoxedPool> { - /// - /// Represents a pool for ; - /// - /// Type that will be in the boxed object - internal class BoxedPool : BasePool, BoxedPool> - { - protected override PoolSize GetPoolSize(PoolSettings settings) => new PoolSize(32, 512); + protected override PoolSize GetPoolSize(PoolSettings settings) => new(32, 512); - protected override void OnGetItem(Boxed item) - { - item.LeavePool(); - item.Pool = PluginPool; - } - - protected override bool OnFreeItem(ref Boxed item) - { - item.Pool = null; - return base.OnFreeItem(ref item); - } + protected override void OnGetItem(Boxed item) + { + item.LeavePool(); + item.Pool = PluginPool; + } - protected override Boxed CreateNew() => new Boxed(); + protected override bool OnFreeItem(ref Boxed item) + { + item.Pool = null; + return base.OnFreeItem(ref item); } + + protected override Boxed CreateNew() => new(); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/Pools/HashPool.cs b/Oxide.Ext.Discord/Types/Pooling/Pools/HashPool.cs index f41e47e33..733095c83 100644 --- a/Oxide.Ext.Discord/Types/Pooling/Pools/HashPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/Pools/HashPool.cs @@ -1,23 +1,22 @@ using Oxide.Plugins; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a pool for Hash<TKey, TValue> +/// +/// +/// +internal class HashPool : BasePool, HashPool> { - /// - /// Represents a pool for Hash<TKey, TValue> - /// - /// - /// - internal class HashPool : BasePool, HashPool> - { - protected override PoolSize GetPoolSize(PoolSettings settings) => settings.HashPoolSize; + protected override PoolSize GetPoolSize(PoolSettings settings) => settings.HashPoolSize; - protected override Hash CreateNew() => new Hash(); + protected override Hash CreateNew() => new(); - /// - protected override bool OnFreeItem(ref Hash item) - { - item.Clear(); - return true; - } + /// + protected override bool OnFreeItem(ref Hash item) + { + item.Clear(); + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/Pools/HashSetPool.cs b/Oxide.Ext.Discord/Types/Pooling/Pools/HashSetPool.cs index 8f8ca2233..eae25359b 100644 --- a/Oxide.Ext.Discord/Types/Pooling/Pools/HashSetPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/Pools/HashSetPool.cs @@ -1,22 +1,21 @@ using System.Collections.Generic; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a pool for Hash<TKey, TValue> +/// +/// +internal class HashSetPool : BasePool, HashSetPool> { - /// - /// Represents a pool for Hash<TKey, TValue> - /// - /// - internal class HashSetPool : BasePool, HashSetPool> - { - protected override PoolSize GetPoolSize(PoolSettings settings) => settings.HashSetPoolSize; + protected override PoolSize GetPoolSize(PoolSettings settings) => settings.HashSetPoolSize; - protected override HashSet CreateNew() => new HashSet(); + protected override HashSet CreateNew() => new(); - /// - protected override bool OnFreeItem(ref HashSet item) - { - item.Clear(); - return true; - } + /// + protected override bool OnFreeItem(ref HashSet item) + { + item.Clear(); + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/Pools/ListPool.cs b/Oxide.Ext.Discord/Types/Pooling/Pools/ListPool.cs index 6dd029b6c..6fa89334d 100644 --- a/Oxide.Ext.Discord/Types/Pooling/Pools/ListPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/Pools/ListPool.cs @@ -1,22 +1,21 @@ using System.Collections.Generic; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a pool for list<T> +/// +/// Type that will be in the list +internal class ListPool : BasePool, ListPool> { - /// - /// Represents a pool for list<T> - /// - /// Type that will be in the list - internal class ListPool : BasePool, ListPool> - { - protected override PoolSize GetPoolSize(PoolSettings settings) => settings.ListPoolSize; + protected override PoolSize GetPoolSize(PoolSettings settings) => settings.ListPoolSize; - protected override List CreateNew() => new List(); + protected override List CreateNew() => new(); - /// - protected override bool OnFreeItem(ref List item) - { - item.Clear(); - return true; - } + /// + protected override bool OnFreeItem(ref List item) + { + item.Clear(); + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/Pools/MemoryStreamPool.cs b/Oxide.Ext.Discord/Types/Pooling/Pools/MemoryStreamPool.cs index 4277718b1..cbd4c89d4 100644 --- a/Oxide.Ext.Discord/Types/Pooling/Pools/MemoryStreamPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/Pools/MemoryStreamPool.cs @@ -1,21 +1,20 @@ using System.IO; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a pool for MemoryStream +/// +internal class MemoryStreamPool : BasePool { - /// - /// Represents a pool for MemoryStream - /// - internal class MemoryStreamPool : BasePool - { - protected override PoolSize GetPoolSize(PoolSettings settings) => settings.MemoryStreamPoolSize; + protected override PoolSize GetPoolSize(PoolSettings settings) => settings.MemoryStreamPoolSize; - protected override MemoryStream CreateNew() => new MemoryStream(); + protected override MemoryStream CreateNew() => new(); - /// - protected override bool OnFreeItem(ref MemoryStream item) - { - item.SetLength(0); - return true; - } + /// + protected override bool OnFreeItem(ref MemoryStream item) + { + item.SetLength(0); + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/Pools/ObjectPool.cs b/Oxide.Ext.Discord/Types/Pooling/Pools/ObjectPool.cs index a16a75985..868740caa 100644 --- a/Oxide.Ext.Discord/Types/Pooling/Pools/ObjectPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/Pools/ObjectPool.cs @@ -1,31 +1,30 @@ -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal class ObjectPool : BasePool> where T : BasePoolable, new() { - internal class ObjectPool : BasePool> where T : BasePoolable, new() - { - protected override PoolSize GetPoolSize(PoolSettings settings) => settings.ObjectPoolSize; + protected override PoolSize GetPoolSize(PoolSettings settings) => settings.ObjectPoolSize; - protected override BasePoolable CreateNew() - { - T obj = new T(); - obj.OnInit(PluginPool, this); - return obj; - } + protected override BasePoolable CreateNew() + { + T obj = new(); + obj.OnInit(PluginPool, this); + return obj; + } - protected override void OnGetItem(BasePoolable item) - { - item.LeavePoolInternal(); - } + protected override void OnGetItem(BasePoolable item) + { + item.LeavePoolInternal(); + } - protected override bool OnFreeItem(ref BasePoolable item) + protected override bool OnFreeItem(ref BasePoolable item) + { + if (item.Disposed) { - if (item.Disposed) - { - return false; - } - - item.EnterPoolInternal(); - return true; + return false; } + + item.EnterPoolInternal(); + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/Pools/PlaceholderDataPool.cs b/Oxide.Ext.Discord/Types/Pooling/Pools/PlaceholderDataPool.cs index aa9e69a8f..7edf99b2a 100644 --- a/Oxide.Ext.Discord/Types/Pooling/Pools/PlaceholderDataPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/Pools/PlaceholderDataPool.cs @@ -1,32 +1,31 @@ using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal class PlaceholderDataPool : BasePool { - internal class PlaceholderDataPool : BasePool + protected override PoolSize GetPoolSize(PoolSettings settings) => settings.PlaceholderDataPoolSize; + + protected override BasePoolable CreateNew() { - protected override PoolSize GetPoolSize(PoolSettings settings) => settings.PlaceholderDataPoolSize; + PlaceholderData data = new(); + data.OnInit(PluginPool, this); + return data; + } - protected override BasePoolable CreateNew() - { - PlaceholderData data = new PlaceholderData(); - data.OnInit(PluginPool, this); - return data; - } + protected override void OnGetItem(BasePoolable item) + { + item.LeavePoolInternal(); + } - protected override void OnGetItem(BasePoolable item) + protected override bool OnFreeItem(ref BasePoolable item) + { + if (item.Disposed) { - item.LeavePoolInternal(); + return false; } - - protected override bool OnFreeItem(ref BasePoolable item) - { - if (item.Disposed) - { - return false; - } - item.EnterPoolInternal(); - return true; - } + item.EnterPoolInternal(); + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Pooling/Pools/StringBuilderPool.cs b/Oxide.Ext.Discord/Types/Pooling/Pools/StringBuilderPool.cs index bff21d587..dba90f23d 100644 --- a/Oxide.Ext.Discord/Types/Pooling/Pools/StringBuilderPool.cs +++ b/Oxide.Ext.Discord/Types/Pooling/Pools/StringBuilderPool.cs @@ -1,21 +1,20 @@ using System.Text; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Pool for StringBuilders +/// +internal class StringBuilderPool : BasePool { - /// - /// Pool for StringBuilders - /// - internal class StringBuilderPool : BasePool - { - protected override PoolSize GetPoolSize(PoolSettings settings) => settings.StringBuilderPoolSize; + protected override PoolSize GetPoolSize(PoolSettings settings) => settings.StringBuilderPoolSize; - protected override StringBuilder CreateNew() => new StringBuilder(); + protected override StringBuilder CreateNew() => new(); - /// - protected override bool OnFreeItem(ref StringBuilder item) - { - item.Clear(); - return true; - } + /// + protected override bool OnFreeItem(ref StringBuilder item) + { + item.Clear(); + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/BasePromise.cs b/Oxide.Ext.Discord/Types/Promises/BasePromise.cs index a568b3f2e..0e171f913 100644 --- a/Oxide.Ext.Discord/Types/Promises/BasePromise.cs +++ b/Oxide.Ext.Discord/Types/Promises/BasePromise.cs @@ -13,121 +13,121 @@ using Oxide.Ext.Discord.Logging; #endif -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents the base class for all promises +/// +public class BasePromise : BasePoolable, IRejectable { /// - /// Represents the base class for all promises + /// ID of the promise /// - public class BasePromise : BasePoolable, IRejectable - { - /// - /// ID of the promise - /// - public Snowflake Id { get; private set; } + public Snowflake Id { get; private set; } - /// - /// Tracks the current state of the promise. - /// - public PromiseState State { get; protected set; } = PromiseState.Pending; + /// + /// Tracks the current state of the promise. + /// + public PromiseState State { get; protected set; } = PromiseState.Pending; - /// - /// The exception when the promise is rejected. - /// - protected Exception Exception; + /// + /// The exception when the promise is rejected. + /// + protected Exception Exception; - private bool _isDisposing; + private bool _isDisposing; - /// - /// Collection of handlers for rejected promises - /// - protected readonly List Rejects = new List(); + /// + /// Collection of handlers for rejected promises + /// + protected readonly List Rejects = new(); - internal readonly Action OnReject; - private readonly Action _onRejectInternal; - private readonly Action _dispose; + internal readonly Action OnReject; + private readonly Action _onRejectInternal; + private readonly Action _dispose; #if PROMISE_DEBUG private System.Timers.Timer _timer; #endif - /// - /// Constructor - /// - protected BasePromise() - { - OnReject = Reject; - _onRejectInternal = InvokeRejectHandlersInternal; - _dispose = Dispose; - } + /// + /// Constructor + /// + protected BasePromise() + { + OnReject = Reject; + _onRejectInternal = InvokeRejectHandlersInternal; + _dispose = Dispose; + } - /// - public void Reject(Exception ex) - { - PromiseException.ThrowIfDisposed(this); - PromiseException.ThrowIfNotPending(State); + /// + public virtual void Reject(Exception ex) + { + PromiseException.ThrowIfDisposed(this); + PromiseException.ThrowIfNotPending(State); - Exception = ex; - State = PromiseState.Rejected; + Exception = ex; + State = PromiseState.Rejected; - InvokeRejectHandlers(ex); - } + InvokeRejectHandlers(ex); + } - /// - /// Invoke all resolve handlers. - /// - private void InvokeRejectHandlers(Exception ex) + /// + /// Invoke all resolve handlers. + /// + private void InvokeRejectHandlers(Exception ex) + { + Exception = ex; + if (ThreadEx.IsMain) { - Exception = ex; - if (ThreadEx.IsMain) - { - InvokeRejectHandlersInternal(); - return; - } - - Interface.Oxide.NextTick(_onRejectInternal); + InvokeRejectHandlersInternal(); + return; } + + Interface.Oxide.NextTick(_onRejectInternal); + } - private void InvokeRejectHandlersInternal() + private void InvokeRejectHandlersInternal() + { + for (int i = 0; i < Rejects.Count; ++i) { - for (int i = 0; i < Rejects.Count; ++i) - { - RejectHandler reject = Rejects[i]; + RejectHandler reject = Rejects[i]; #if PROMISE_DEBUG DiscordExtension.GlobalLogger.Info($"Invoking Reject ID: {Id}"); #endif - reject.Reject(Exception); - } - - ClearHandlers(); - DelayedDispose(); + reject.Reject(Exception); } + + ClearHandlers(); + DelayedDispose(); + } - /// - /// Clears all the handlers for the promises - /// Called after completion - /// - protected virtual void ClearHandlers() - { - Rejects.Clear(); - } + /// + /// Clears all the handlers for the promises + /// Called after completion + /// + protected virtual void ClearHandlers() + { + Rejects.Clear(); + } - /// - /// Delays disposing the promise till NextTick - /// - protected void DelayedDispose() + /// + /// Delays disposing the promise till NextTick + /// + protected void DelayedDispose() + { + if (!_isDisposing) { - if (!_isDisposing) - { - _isDisposing = true; - Interface.Oxide.NextTick(_dispose); - } + _isDisposing = true; + Interface.Oxide.NextTick(_dispose); } + } - /// - protected override void LeavePool() - { - Id = SnowflakeIdFactory.Instance.Generate(); - base.LeavePool(); + /// + protected override void LeavePool() + { + Id = SnowflakeIdFactory.Instance.Generate(); + base.LeavePool(); #if PROMISE_DEBUG Snowflake id = Id; DiscordExtension.GlobalLogger.Error($"Creating Promise. ID: {Id}"); @@ -140,23 +140,22 @@ protected override void LeavePool() } }; #endif - } + } - /// - protected override void EnterPool() - { + /// + protected override void EnterPool() + { #if PROMISE_DEBUG DiscordExtension.GlobalLogger.Info($"Disposed Promise: {Id}"); _timer?.Stop(); _timer?.Dispose(); _timer = null; #endif - Id = default(Snowflake); - State = PromiseState.Pending; - Exception = null; - Rejects.Clear(); - _isDisposing = false; - base.EnterPool(); - } + Id = default; + State = PromiseState.Pending; + Exception = null; + Rejects.Clear(); + _isDisposing = false; + base.EnterPool(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/Promise.cs b/Oxide.Ext.Discord/Types/Promises/Promise.cs index c3b4249a2..af94ef4af 100644 --- a/Oxide.Ext.Discord/Types/Promises/Promise.cs +++ b/Oxide.Ext.Discord/Types/Promises/Promise.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; using Oxide.Core; using Oxide.Ext.Discord.Callbacks; using Oxide.Ext.Discord.Exceptions; @@ -15,458 +17,480 @@ using Oxide.Ext.Discord.Logging; #endif -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Implements a non-generic C# promise; this is a promise that simply resolves without delivering a value. +/// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise +/// +public sealed class Promise : BasePromise, IPendingPromise { /// - /// Implements a non-generic C# promise, this is a promise that simply resolves without delivering a value. - /// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise + /// Completed handlers that accept no value. /// - public sealed class Promise : BasePromise, IPendingPromise + private readonly List _resolves = new(1); + + private readonly Action _onResolve; + private readonly Action _onResolveInternal; + + private readonly ManualResetValueTaskSource _taskSource = new(); + + /// + /// Constructor for the promise + /// + public Promise() { - /// - /// Completed handlers that accept no value. - /// - private readonly List _resolves = new List(1); - - private readonly Action _onResolve; - private readonly Action _onResolveInternal; - - /// - /// Constructor for the promise - /// - public Promise() - { - _onResolve = Resolve; - _onResolveInternal = InvokeResolveHandlersInternal; - } + _onResolve = Resolve; + _onResolveInternal = InvokeResolveHandlersInternal; + } - /// - /// Creates a Promise - /// - /// - public static Promise Create() => DiscordPool.Internal.Get(); - - /// - /// Returns a promise that has been resolved - /// - /// - public static IPromise Resolved() - { - Promise promise = Create(); - promise.State = PromiseState.Resolved; - promise.DelayedDispose(); - return promise; - } + /// + /// Creates a Promise + /// + /// + public static Promise Create() => DiscordPool.Internal.Get(); - /// - /// Convert an exception directly into a rejected promise. - /// - public static IPromise Rejected(Exception ex) - { - Promise promise = Create(); - promise.State = PromiseState.Rejected; - promise.Exception = ex; - promise.DelayedDispose(); - return promise; - } + /// + /// Returns a promise that has been resolved + /// + /// + public static IPromise Resolved() + { + Promise promise = Create(); + promise.State = PromiseState.Resolved; + promise.DelayedDispose(); + return promise; + } - /// - /// Helper function clear out all handlers after resolution or rejection. - /// - protected override void ClearHandlers() - { - _resolves.Clear(); - base.ClearHandlers(); - } + /// + /// Convert an exception directly into a rejected promise. + /// + public static IPromise Rejected(Exception ex) + { + Promise promise = Create(); + promise.State = PromiseState.Rejected; + promise.Exception = ex; + promise.DelayedDispose(); + return promise; + } - /// - /// Invoke all resolve handlers. - /// - private void InvokeResolveHandlers() + /// + /// Helper function to clear out all handlers after resolution or rejection. + /// + protected override void ClearHandlers() + { + _resolves.Clear(); + base.ClearHandlers(); + } + + /// + /// Invoke all resolve handlers. + /// + private void InvokeResolveHandlers() + { + if (ThreadEx.IsMain) { - if (ThreadEx.IsMain) - { - InvokeResolveHandlersInternal(); - return; - } - - Interface.Oxide.NextTick(_onResolveInternal); + InvokeResolveHandlersInternal(); + return; } + + Interface.Oxide.NextTick(_onResolveInternal); + } - private void InvokeResolveHandlersInternal() + private void InvokeResolveHandlersInternal() + { + if (_resolves != null) { - if (_resolves != null) + for (int i = 0; i < _resolves.Count; i++) { - for (int i = 0; i < _resolves.Count; i++) - { - ResolveHandler resolve = _resolves[i]; + ResolveHandler resolve = _resolves[i]; #if PROMISE_DEBUG DiscordExtension.GlobalLogger.Info($"Invoking Resolve ID: {Id}"); #endif - resolve.Resolve(); - } + resolve.Resolve(); } - - ClearHandlers(); - DelayedDispose(); } + + ClearHandlers(); + DelayedDispose(); + } - /// - public void Resolve() + /// + public void Resolve() + { + PromiseException.ThrowIfDisposed(this); + PromiseException.ThrowIfNotPending(State); + State = PromiseState.Resolved; + _taskSource.SetResult(); + InvokeResolveHandlers(); + } + + /// + public override void Reject(Exception ex) + { + base.Reject(ex); + _taskSource.SetException(ex); + } + + /// + public IPromise Catch(Action onRejected) + { + PromiseException.ThrowIfDisposed(this); + if (State == PromiseState.Resolved) { - PromiseException.ThrowIfDisposed(this); - PromiseException.ThrowIfNotPending(State); - State = PromiseState.Resolved; - InvokeResolveHandlers(); + return this; } - /// - public IPromise Catch(Action onRejected) + Promise resultPromise = Create(); + + void RejectHandler(Exception exception) { - PromiseException.ThrowIfDisposed(this); - if (State == PromiseState.Resolved) + try { - return this; + onRejected(exception); + resultPromise.Resolve(); } - - Promise resultPromise = Create(); - - void RejectHandler(Exception exception) + catch (Exception ex) { - try - { - onRejected(exception); - resultPromise.Resolve(); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An error occured during then catch reject of Promise", ex); - resultPromise.Reject(ex); - } + DiscordExtension.GlobalLogger.Exception("An error occured during then catch reject of Promise", ex); + resultPromise.Reject(ex); } + } - AddHandlers(new ResolveHandler(resultPromise._onResolve, resultPromise), new RejectHandler(RejectHandler, resultPromise)); + AddHandlers(new ResolveHandler(resultPromise._onResolve, resultPromise), new RejectHandler(RejectHandler, resultPromise)); - return resultPromise; - } + return resultPromise; + } - /// - public IPromise Catch(Action onRejected) where TException : Exception + /// + public IPromise Catch(Action onRejected) where TException : Exception + { + return Catch(ex => { - return Catch(ex => + if (ex is TException exception) { - if (ex is TException exception) - { - onRejected.Invoke(exception); - } - }); - } + onRejected.Invoke(exception); + } + }); + } - /// - public IPromise Then(Func> onResolved) => Then(onResolved, null); + /// + public IPromise Then(Func> onResolved) => Then(onResolved, null); - /// - public IPromise Then(Func onResolved) => Then(onResolved, null); + /// + public IPromise Then(Func onResolved) => Then(onResolved, null); - /// - public IPromise Then(Action onResolved) => Then(onResolved, null); + /// + public IPromise Then(Action onResolved) => Then(onResolved, null); - /// - public IPromise Then(Func> onResolved, Func> onRejected) + /// + public IPromise Then(Func> onResolved, Func> onRejected) + { + PromiseException.ThrowIfDisposed(this); + if (State == PromiseState.Resolved) { - PromiseException.ThrowIfDisposed(this); - if (State == PromiseState.Resolved) - { - try - { - return onResolved(); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An error occured during then then resolved of Promise", ex); - return Promise.Rejected(ex); - } - } - - // This version of the function must supply an onResolved. - // Otherwise there is now way to get the converted value to pass to the resulting promise. - Promise resultPromise = Promise.Create(); - - void ResolveHandler() + try { - onResolved().Then(resultPromise); - } - - void RejectHandler(Exception exception) + return onResolved(); + } + catch (Exception ex) { - if (onRejected == null) - { - resultPromise.Reject(exception); - return; - } - - try - { - onRejected(exception).Then(resultPromise); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during then convert Promise to Promise<{typeof(TConvert).Name}>", ex); - resultPromise.Reject(ex); - } + DiscordExtension.GlobalLogger.Exception("An error occured during then then resolved of Promise", ex); + return Promise.Rejected(ex); } + } - AddHandlers(new ResolveHandler(ResolveHandler, resultPromise), new RejectHandler(RejectHandler, resultPromise)); + // This version of the function must supply an onResolved. + // Otherwise, there is no way to get the converted value to pass to the resulting promise. + Promise resultPromise = Promise.Create(); - return resultPromise; + void ResolveHandler() + { + onResolved().Then(resultPromise); } - /// - public IPromise Then(Func onResolved, Action onRejected) + void RejectHandler(Exception exception) { - PromiseException.ThrowIfDisposed(this); - if (State == PromiseState.Resolved) + if (onRejected == null) { - try - { - return onResolved(); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An error occured during then then resolved of Promise", ex); - return Rejected(ex); - } + resultPromise.Reject(exception); + return; } - Promise resultPromise = Create(); - - Action resolveHandler; - if (onResolved != null) + try { - void ResolveHandler() - { - onResolved().Then(resultPromise); - } - - resolveHandler = ResolveHandler; + onRejected(exception).Then(resultPromise); } - else + catch (Exception ex) { - resolveHandler = resultPromise._onResolve; + DiscordExtension.GlobalLogger.Exception($"An error occured during then convert Promise to Promise<{typeof(TConvert).Name}>", ex); + resultPromise.Reject(ex); } + } + + AddHandlers(new ResolveHandler(ResolveHandler, resultPromise), new RejectHandler(RejectHandler, resultPromise)); - Action rejectHandler; - if (onRejected != null) + return resultPromise; + } + + /// + public IPromise Then(Func onResolved, Action onRejected) + { + PromiseException.ThrowIfDisposed(this); + if (State == PromiseState.Resolved) + { + try { - rejectHandler = ex => - { - onRejected(ex); - resultPromise.Reject(ex); - }; + return onResolved(); } - else + catch (Exception ex) { - rejectHandler = resultPromise.OnReject; + DiscordExtension.GlobalLogger.Exception("An error occured during then then resolved of Promise", ex); + return Rejected(ex); } - - AddHandlers(new ResolveHandler(resolveHandler, resultPromise), new RejectHandler(rejectHandler, resultPromise)); - - return resultPromise; } - /// - public IPromise Then(IPromise promise) - { - Promise prom = (Promise)promise; - return Then(prom._onResolve, prom.OnReject); - } - - /// - public IPromise Then(Action onResolved, Action onRejected) + Promise resultPromise = Create(); + + Action resolveHandler; + if (onResolved != null) { - PromiseException.ThrowIfDisposed(this); - if (State == PromiseState.Resolved) + void ResolveHandler() { - try - { - onResolved(); - return this; - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An error occured during then then resolved of Promise", ex); - return Rejected(ex); - } + onResolved().Then(resultPromise); } - Promise resultPromise = Create(); - - PromiseCallback callback = PromiseCallback.Create(resultPromise, onResolved, onRejected); - - AddHandlers(new ResolveHandler(callback.RunResolve, resultPromise), new RejectHandler(callback.RunRejected, resultPromise)); - - return resultPromise; + resolveHandler = ResolveHandler; + } + else + { + resolveHandler = resultPromise._onResolve; } - /// - /// Helper function to invoke or register resolve/reject handlers. - /// - private void AddHandlers(ResolveHandler resolve, RejectHandler reject) + Action rejectHandler; + if (onRejected != null) { - if (State == PromiseState.Resolved) + rejectHandler = ex => { - resolve.Resolve(); - } - else if (State == PromiseState.Rejected) + onRejected(ex); + resultPromise.Reject(ex); + }; + } + else + { + rejectHandler = resultPromise.OnReject; + } + + AddHandlers(new ResolveHandler(resolveHandler, resultPromise), new RejectHandler(rejectHandler, resultPromise)); + + return resultPromise; + } + + /// + public IPromise Then(IPromise promise) + { + Promise prom = (Promise)promise; + return Then(prom._onResolve, prom.OnReject); + } + + /// + public IPromise Then(Action onResolved, Action onRejected) + { + PromiseException.ThrowIfDisposed(this); + if (State == PromiseState.Resolved) + { + try { - reject.Reject(Exception); + onResolved(); + return this; } - else + catch (Exception ex) { - _resolves.Add(resolve); - Rejects.Add(reject); + DiscordExtension.GlobalLogger.Exception("An error occured during then then resolved of Promise", ex); + return Rejected(ex); } } - /// - public IPromise ThenAll(Func> chain) => Then( All(chain())); + Promise resultPromise = Create(); + + PromiseCallback callback = PromiseCallback.Create(resultPromise, onResolved, onRejected); - /// - public IPromise> ThenAll(Func>> chain) => Then(() => Promise.All(chain())); + AddHandlers(new ResolveHandler(callback.RunResolve, resultPromise), new RejectHandler(callback.RunRejected, resultPromise)); - /// - /// Returns a promise that resolves when all of the promises in the enumerable argument have resolved. - /// Returns a promise of a collection of the resolved results. - /// - public static IPromise All(params IPromise[] promises) => All((IEnumerable)promises); // Cast is required to force use of the other All function. + return resultPromise; + } - /// - /// Returns a promise that resolves when all of the promises in the enumerable argument have resolved. - /// Returns a promise of a collection of the resolved results. - /// - public static IPromise All(IEnumerable promisesEnumerable) + /// + /// Helper function to invoke or register resolve/reject handlers. + /// + private void AddHandlers(ResolveHandler resolve, RejectHandler reject) + { + if (State == PromiseState.Resolved) { - List promises = DiscordPool.Internal.GetList(); - promises.AddRange(promisesEnumerable); - if (promises.Count == 0) - { - return Resolved(); - } + resolve.Resolve(); + } + else if (State == PromiseState.Rejected) + { + reject.Reject(Exception); + } + else + { + _resolves.Add(resolve); + Rejects.Add(reject); + } + } - int remainingCount = promises.Count; - Promise resultPromise = Create(); + /// + public IPromise ThenAll(Func> chain) => Then( All(chain())); - for (int index = 0; index < promises.Count; index++) - { - IPromise promise = promises[index]; - promise.Then(() => - { - --remainingCount; - if (remainingCount <= 0 && resultPromise.State == PromiseState.Pending) - { - // This will never happen if any of the promises errored. - resultPromise.Resolve(); - } - }) - .Catch(ex => - { - if (resultPromise.State == PromiseState.Pending) - { - // If a promise errored and the result promise is still pending, reject it. - resultPromise.Reject(ex); - } - }); - } - - DiscordPool.Internal.FreeList(promises); + /// + public IPromise> ThenAll(Func>> chain) => Then(() => Promise.All(chain())); - return resultPromise; - } + /// + /// Returns a promise that resolves when all of the promises in the enumerable argument have resolved. + /// Returns a promise of a collection of the resolved results. + /// + public static IPromise All(params IPromise[] promises) => All((IEnumerable)promises); // Cast is required to force use of the other All function. - /// - public IPromise ThenSequence(Func>> chain) => Then( Sequence(chain())); + /// + /// Returns a promise that resolves when all of the promises in the enumerable argument have resolved. + /// Returns a promise of a collection of the resolved results. + /// + public static IPromise All(IEnumerable promisesEnumerable) + { + List promises = DiscordPool.Internal.GetList(); + promises.AddRange(promisesEnumerable); + if (promises.Count == 0) + { + return Resolved(); + } - /// - /// Chain a number of operations using promises. - /// Takes a number of functions each of which starts an async operation and yields a promise. - /// - public static IPromise Sequence(params Func[] fns) => Sequence((IEnumerable>)fns); + int remainingCount = promises.Count; + Promise resultPromise = Create(); - /// - /// Chain a sequence of operations using promises. - /// Takes a collection of functions each of which starts an async operation and yields a promise. - /// - public static IPromise Sequence(IEnumerable> fns) + for (int index = 0; index < promises.Count; index++) { - Promise promise = Create(); - fns.Aggregate(Resolved(), (prevPromise, fn) => prevPromise.Then(fn)).Then(promise._onResolve).Catch(promise.OnReject); - return promise; + IPromise promise = promises[index]; + promise.Then(() => + { + --remainingCount; + if (remainingCount <= 0 && resultPromise.State == PromiseState.Pending) + { + // This will never happen if any of the promises errored. + resultPromise.Resolve(); + } + }) + .Catch(ex => + { + if (resultPromise.State == PromiseState.Pending) + { + // If a promise errored and the result promise is still pending, reject it. + resultPromise.Reject(ex); + } + }); } + + DiscordPool.Internal.FreeList(promises); + + return resultPromise; + } + + /// + public IPromise ThenSequence(Func>> chain) => Then( Sequence(chain())); + + /// + /// Chain a number of operations using promises. + /// Takes a number of functions each of which starts an async operation and yields a promise. + /// + public static IPromise Sequence(params Func[] fns) => Sequence((IEnumerable>)fns); + + /// + /// Chain a sequence of operations using promises. + /// Takes a collection of functions each of which starts an async operation and yields a promise. + /// + public static IPromise Sequence(IEnumerable> fns) + { + Promise promise = Create(); + fns.Aggregate(Resolved(), (prevPromise, fn) => prevPromise.Then(fn)).Then(promise._onResolve).Catch(promise.OnReject); + return promise; + } - /// - public IPromise Finally(Action onComplete) + /// + public IPromise Finally(Action onComplete) + { + if (State == PromiseState.Resolved) { - if (State == PromiseState.Resolved) + try { - try - { - onComplete(); - return this; - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An error occured during then complete finally of Promise", ex); - return Rejected(ex); - } + onComplete(); + return this; + } + catch (Exception ex) + { + DiscordExtension.GlobalLogger.Exception("An error occured during then complete finally of Promise", ex); + return Rejected(ex); } + } - Promise promise = Create(); + Promise promise = Create(); - Then(promise._onResolve); - Catch(exception => + Then(promise._onResolve); + Catch(exception => + { + try { - try - { - onComplete(); - promise.Reject(exception); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An error occured during then catch finally of Promise", ex); - promise.Reject(ex); - } - }); + onComplete(); + promise.Reject(exception); + } + catch (Exception ex) + { + DiscordExtension.GlobalLogger.Exception("An error occured during then catch finally of Promise", ex); + promise.Reject(ex); + } + }); - return promise.Then(onComplete); - } + return promise.Then(onComplete); + } - /// - public IPromise ContinueWith(Func onComplete) - { - Promise promise = Create(); + /// + public IPromise ContinueWith(Func onComplete) + { + Promise promise = Create(); - Then(promise._onResolve); - Catch(e => promise.Resolve()); + Then(promise._onResolve); + Catch(_ => promise.Resolve()); - return promise.Then(onComplete); - } + return promise.Then(onComplete); + } - /// - public IPromise ContinueWith(Func> onComplete) - { - Promise promise = Create(); + /// + public IPromise ContinueWith(Func> onComplete) + { + Promise promise = Create(); - Then(promise._onResolve); - Catch(e => promise.Resolve()); + Then(promise._onResolve); + Catch(_ => promise.Resolve()); - return promise.Then(onComplete); - } + return promise.Then(onComplete); + } - /// - protected override void EnterPool() - { - base.EnterPool(); - _resolves.Clear(); - } + /// + public ValueTask AsTask() + { + return _taskSource.GetTask(); + } + + /// + public ValueTaskAwaiter GetAwaiter() + { + return _taskSource.GetTask().GetAwaiter(); + } + + /// + protected override void EnterPool() + { + base.EnterPool(); + _resolves.Clear(); + _taskSource.Reset(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/PromiseState.cs b/Oxide.Ext.Discord/Types/Promises/PromiseState.cs index b3b659d8e..e18c07059 100644 --- a/Oxide.Ext.Discord/Types/Promises/PromiseState.cs +++ b/Oxide.Ext.Discord/Types/Promises/PromiseState.cs @@ -1,20 +1,19 @@ // Originally from: https://github.com/Real-Serious-Games/C-Sharp-Promise // Modified by: MJSU -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Specifies the state of a promise. +/// +public enum PromiseState : byte { - /// - /// Specifies the state of a promise. - /// - public enum PromiseState : byte - { - /// The promise is in-flight. - Pending, + /// The promise is in-flight. + Pending, - /// The promise has been rejected. - Rejected, + /// The promise has been rejected. + Rejected, - /// The promise has been resolved. - Resolved - }; + /// The promise has been resolved. + Resolved } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/Promise{T}.cs b/Oxide.Ext.Discord/Types/Promises/Promise{T}.cs index 215514a8c..47c70d658 100644 --- a/Oxide.Ext.Discord/Types/Promises/Promise{T}.cs +++ b/Oxide.Ext.Discord/Types/Promises/Promise{T}.cs @@ -3,7 +3,8 @@ using System; using System.Collections.Generic; -using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; using Oxide.Core; using Oxide.Ext.Discord.Callbacks; using Oxide.Ext.Discord.Exceptions; @@ -16,515 +17,536 @@ #endif -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Implements a C# promise. +/// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise +/// +public sealed class Promise : BasePromise, IPendingPromise { /// - /// Implements a C# promise. - /// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise + /// The value when the promises is resolved. + /// + private TPromised _resolveValue; + + /// + /// Completed handlers that accept a value. /// - public sealed class Promise : BasePromise, IPendingPromise + private readonly List> _resolves = new(1); + + private readonly Action _onResolve; + private readonly Action _onResolveInternal; + + private readonly ManualResetValueTaskSource _taskSource = new(); + + /// + /// Constructor + /// + public Promise() { - /// - /// The value when the promises is resolved. - /// - private TPromised _resolveValue; - - /// - /// Completed handlers that accept a value. - /// - private readonly List> _resolves = new List>(1); - - private readonly Action _onResolve; - private readonly Action _onResolveInternal; - - /// - /// Constructor - /// - public Promise() - { - _onResolve = Resolve; - _onResolveInternal = InvokeResolveHandlersInternal; - } + _onResolve = Resolve; + _onResolveInternal = InvokeResolveHandlersInternal; + } - /// - /// Returns a promise that is currently pending - /// - /// - public static Promise Create() - { - Promise promise = DiscordPool.Internal.Get>(); - return promise; - } + /// + /// Returns a promise that is currently pending + /// + /// + public static Promise Create() + { + Promise promise = DiscordPool.Internal.Get>(); + return promise; + } - /// - /// Returns a promise that is currently pending - /// - /// - public static Promise Create() - { - Promise promise = DiscordPool.Internal.Get>(); - return promise; - } + /// + /// Returns a promise that is currently pending + /// + /// + public static Promise Create() + { + Promise promise = DiscordPool.Internal.Get>(); + return promise; + } - /// - /// - /// - /// - /// - public static IPromise Create(Action, Action> resolver) + /// + /// + /// + /// + /// + public static IPromise Create(Action, Action> resolver) + { + Promise promise = Create(); + try { - Promise promise = Create(); - try - { - resolver(promise._onResolve, promise.OnReject); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during create of Promise<{typeof(TPromised).Name}>", ex); - promise.Reject(ex); - } - - return promise; + resolver(promise._onResolve, promise.OnReject); } - - /// - /// Convert a simple value directly into a resolved promise. - /// - public static IPromise Resolved(TPromised promisedValue) + catch (Exception ex) { - Promise promise = Create(); - promise.State = PromiseState.Resolved; - promise._resolveValue = promisedValue; - promise.DelayedDispose(); - return promise; + DiscordExtension.GlobalLogger.Exception($"An error occured during create of Promise<{typeof(TPromised).Name}>", ex); + promise.Reject(ex); } - /// - /// Convert an exception directly into a rejected promise. - /// - public static IPromise Rejected(Exception ex) - { - Promise promise = Create(); - promise.State = PromiseState.Rejected; - promise.Exception = ex; - promise.DelayedDispose(); - return promise; - } + return promise; + } - /// - public void Resolve(TPromised value) - { - PromiseException.ThrowIfDisposed(this); - PromiseException.ThrowIfNotPending(State); + /// + /// Convert a simple value directly into a resolved promise. + /// + public static IPromise Resolved(TPromised promisedValue) + { + Promise promise = Create(); + promise.State = PromiseState.Resolved; + promise._resolveValue = promisedValue; + promise.DelayedDispose(); + return promise; + } + + /// + /// Convert an exception directly into a rejected promise. + /// + public static IPromise Rejected(Exception ex) + { + Promise promise = Create(); + promise.State = PromiseState.Rejected; + promise.Exception = ex; + promise.DelayedDispose(); + return promise; + } - _resolveValue = value; - State = PromiseState.Resolved; + /// + public void Resolve(TPromised value) + { + PromiseException.ThrowIfDisposed(this); + PromiseException.ThrowIfNotPending(State); - InvokeResolveHandlers(value); - } + _resolveValue = value; + State = PromiseState.Resolved; + _taskSource.SetResult(value); + InvokeResolveHandlers(value); + } + + /// + public override void Reject(Exception ex) + { + base.Reject(ex); + _taskSource.SetException(ex); + } - /// - /// Invoke all resolve handlers. - /// - private void InvokeResolveHandlers(TPromised value) + /// + /// Invoke all resolve handlers. + /// + private void InvokeResolveHandlers(TPromised value) + { + _resolveValue = value; + if (ThreadEx.IsMain) { - _resolveValue = value; - if (ThreadEx.IsMain) - { - InvokeResolveHandlersInternal(); - return; - } - - Interface.Oxide.NextTick(_onResolveInternal); + InvokeResolveHandlersInternal(); + return; } + + Interface.Oxide.NextTick(_onResolveInternal); + } - private void InvokeResolveHandlersInternal() + private void InvokeResolveHandlersInternal() + { + for (int i = 0; i < _resolves.Count; i++) { - for (int i = 0; i < _resolves.Count; i++) - { - ResolveHandler resolve = _resolves[i]; + ResolveHandler resolve = _resolves[i]; #if PROMISE_DEBUG DiscordExtension.GlobalLogger.Info($"Invoking Resolve ID: {Id}"); #endif - resolve.Resolve(_resolveValue); - } + resolve.Resolve(_resolveValue); + } - ClearHandlers(); - DelayedDispose(); + ClearHandlers(); + DelayedDispose(); + } + + /// + public IPromise Catch(Action onRejected) + { + if (State == PromiseState.Resolved) + { + return Promise.Resolved(); } - /// - public IPromise Catch(Action onRejected) + Promise resultPromise = Promise.Create(); + + void ResolveHandler(TPromised _) => resultPromise.Resolve(); + void RejectHandler(Exception ex) { - if (State == PromiseState.Resolved) + try { - return Promise.Resolved(); + onRejected(ex); + resultPromise.Resolve(); } - - Promise resultPromise = Promise.Create(); - - void ResolveHandler(TPromised _) => resultPromise.Resolve(); - void RejectHandler(Exception ex) + catch (Exception cbEx) { - try - { - onRejected(ex); - resultPromise.Resolve(); - } - catch (Exception cbEx) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during catch reject of Promise<{typeof(TPromised).Name}>", ex); - resultPromise.Reject(cbEx); - } + DiscordExtension.GlobalLogger.Exception($"An error occured during catch reject of Promise<{typeof(TPromised).Name}>", ex); + resultPromise.Reject(cbEx); } + } - AddHandlers(new ResolveHandler(ResolveHandler, resultPromise), new RejectHandler(RejectHandler, resultPromise)); + AddHandlers(new ResolveHandler(ResolveHandler, resultPromise), new RejectHandler(RejectHandler, resultPromise)); - return resultPromise; - } + return resultPromise; + } - /// - public IPromise Catch(Action onRejected) where TException : Exception + /// + public IPromise Catch(Action onRejected) where TException : Exception + { + return Catch(ex => { - return Catch(ex => + if (ex is TException exception) { - if (ex is TException exception) - { - onRejected.Invoke(exception); - } - }); + onRejected.Invoke(exception); + } + }); + } + + /// + public IPromise Catch(Func onRejected) + { + if (State == PromiseState.Resolved) + { + return this; } - /// - public IPromise Catch(Func onRejected) + Promise resultPromise = Create(); + + void RejectHandler(Exception ex) { - if (State == PromiseState.Resolved) + try { - return this; + resultPromise.Resolve(onRejected(ex)); } - - Promise resultPromise = Create(); - - void RejectHandler(Exception ex) + catch (Exception cbEx) { - try - { - resultPromise.Resolve(onRejected(ex)); - } - catch (Exception cbEx) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during catch reject of Promise<{typeof(TPromised).Name}>", ex); - resultPromise.Reject(cbEx); - } + DiscordExtension.GlobalLogger.Exception($"An error occured during catch reject of Promise<{typeof(TPromised).Name}>", ex); + resultPromise.Reject(cbEx); } + } - AddHandlers(new ResolveHandler(resultPromise._onResolve, resultPromise), new RejectHandler(RejectHandler, resultPromise)); + AddHandlers(new ResolveHandler(resultPromise._onResolve, resultPromise), new RejectHandler(RejectHandler, resultPromise)); - return resultPromise; - } + return resultPromise; + } - /// - public IPromise Then(Func> onResolved) => Then(onResolved, null); + /// + public IPromise Then(Func> onResolved) => Then(onResolved, null); - /// - public IPromise Then(Action onResolved) => Then(onResolved, null); + /// + public IPromise Then(Action onResolved) => Then(onResolved, null); - /// - public IPromise Then(Func> onResolved, Func> onRejected) + /// + public IPromise Then(Func> onResolved, Func> onRejected) + { + if (State == PromiseState.Resolved) { - if (State == PromiseState.Resolved) + try { - try - { - return onResolved(_resolveValue); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during then resolved of Promise<{typeof(TPromised).Name}>", ex); - return Promise.Rejected(ex); - } + return onResolved(_resolveValue); } + catch (Exception ex) + { + DiscordExtension.GlobalLogger.Exception($"An error occured during then resolved of Promise<{typeof(TPromised).Name}>", ex); + return Promise.Rejected(ex); + } + } - // This version of the function must supply an onResolved. - // Otherwise there is no way to get the converted value to pass to the resulting promise. - Promise resultPromise = Create(); + // This version of the function must supply an onResolved. + // Otherwise there is no way to get the converted value to pass to the resulting promise. + Promise resultPromise = Create(); - void ResolveHandler(TPromised promised) + void ResolveHandler(TPromised promised) + { + onResolved(promised).Then(resultPromise); + } + + void RejectHandler(Exception ex) + { + if (onRejected == null) { - onResolved(promised).Then(resultPromise); + resultPromise.Reject(ex); + return; } - void RejectHandler(Exception ex) + try { - if (onRejected == null) - { - resultPromise.Reject(ex); - return; - } - - try - { - onRejected(ex).Then(resultPromise); - } - catch (Exception callbackEx) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during convert of Promise<{typeof(TPromised).Name}> to Promise<{typeof(TConvert).Name}>", ex); - resultPromise.Reject(callbackEx); - } + onRejected(ex).Then(resultPromise); + } + catch (Exception callbackEx) + { + DiscordExtension.GlobalLogger.Exception($"An error occured during convert of Promise<{typeof(TPromised).Name}> to Promise<{typeof(TConvert).Name}>", ex); + resultPromise.Reject(callbackEx); } + } - AddHandlers(new ResolveHandler(ResolveHandler, resultPromise), new RejectHandler(RejectHandler, resultPromise)); + AddHandlers(new ResolveHandler(ResolveHandler, resultPromise), new RejectHandler(RejectHandler, resultPromise)); - return resultPromise; - } + return resultPromise; + } - /// - public IPromise Then(Func onResolved, Action onRejected) + /// + public IPromise Then(Func onResolved, Action onRejected) + { + if (State == PromiseState.Resolved) { - if (State == PromiseState.Resolved) + try { - try - { - return onResolved(_resolveValue); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during then reject of Promise<{typeof(TPromised).Name}>", ex); - return Promise.Rejected(ex); - } + return onResolved(_resolveValue); } - - Promise resultPromise = Promise.Create(); - - void ResolveHandler(TPromised promised) + catch (Exception ex) { - if (onResolved != null) - { - onResolved(promised).Then(resultPromise); - } - else - { - resultPromise.Resolve(); - } + DiscordExtension.GlobalLogger.Exception($"An error occured during then reject of Promise<{typeof(TPromised).Name}>", ex); + return Promise.Rejected(ex); } + } - Action rejectHandler; - if (onRejected != null) + Promise resultPromise = Promise.Create(); + + void ResolveHandler(TPromised promised) + { + if (onResolved != null) { - void RejectHandler(Exception ex) - { - onRejected(ex); - resultPromise.Reject(ex); - } - - rejectHandler = RejectHandler; + onResolved(promised).Then(resultPromise); } else { - rejectHandler = resultPromise.OnReject; + resultPromise.Resolve(); } + } - AddHandlers(new ResolveHandler(ResolveHandler, resultPromise), new RejectHandler(rejectHandler, resultPromise)); + Action rejectHandler; + if (onRejected != null) + { + void RejectHandler(Exception ex) + { + onRejected(ex); + resultPromise.Reject(ex); + } - return resultPromise; + rejectHandler = RejectHandler; } - - /// - public IPromise Then(IPromise promise) + else { - Promise prom = (Promise)promise; - return Then(prom._onResolve, prom.OnReject); + rejectHandler = resultPromise.OnReject; } - /// - public IPromise Then(Action onResolved, Action onRejected) + AddHandlers(new ResolveHandler(ResolveHandler, resultPromise), new RejectHandler(rejectHandler, resultPromise)); + + return resultPromise; + } + + /// + public IPromise Then(IPromise promise) + { + Promise prom = (Promise)promise; + return Then(prom._onResolve, prom.OnReject); + } + + /// + public IPromise Then(Action onResolved, Action onRejected) + { + if (State == PromiseState.Resolved) { - if (State == PromiseState.Resolved) + try { - try - { - onResolved(_resolveValue); - return Resolved(_resolveValue); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during resolve of Promise<{typeof(TPromised).Name}>", ex); - return Rejected(ex); - } + onResolved(_resolveValue); + return Resolved(_resolveValue); } + catch (Exception ex) + { + DiscordExtension.GlobalLogger.Exception($"An error occured during resolve of Promise<{typeof(TPromised).Name}>", ex); + return Rejected(ex); + } + } - Promise resultPromise = Create(); + Promise resultPromise = Create(); - PromiseCallback callback = PromiseCallback.Create(resultPromise, onResolved, onRejected); + PromiseCallback callback = PromiseCallback.Create(resultPromise, onResolved, onRejected); - AddHandlers(new ResolveHandler(callback.RunResolve, resultPromise), new RejectHandler(callback.RunRejected, resultPromise)); + AddHandlers(new ResolveHandler(callback.RunResolve, resultPromise), new RejectHandler(callback.RunRejected, resultPromise)); - return resultPromise; - } + return resultPromise; + } - /// - public IPromise Then(Func transform) => Then(value => Promise.Resolved(transform(value))); + /// + public IPromise Then(Func transform) => Then(value => Promise.Resolved(transform(value))); - /// - /// Helper function to invoke or register resolve/reject handlers. - /// - private void AddHandlers(ResolveHandler resolve, RejectHandler reject) + /// + /// Helper function to invoke or register resolve/reject handlers. + /// + private void AddHandlers(ResolveHandler resolve, RejectHandler reject) + { + if (State == PromiseState.Resolved) + { + resolve.Resolve(_resolveValue); + } + else if (State == PromiseState.Rejected) + { + reject.Reject(Exception); + } + else { - if (State == PromiseState.Resolved) - { - resolve.Resolve(_resolveValue); - } - else if (State == PromiseState.Rejected) - { - reject.Reject(Exception); - } - else - { #if PROMISE_DEBUG Interface.Oxide.LogInfo($"{Id} Adding Handlers."); #endif - _resolves.Add(resolve); - Rejects.Add(reject); - } + _resolves.Add(resolve); + Rejects.Add(reject); } + } - /// - public IPromise> ThenAll(Func>> chain) => Then(value => Promise.All(chain(value))); + /// + public IPromise> ThenAll(Func>> chain) => Then(value => Promise.All(chain(value))); - /// - public IPromise ThenAll(Func> chain) => Then(value => Promise.All(chain(value)), null); + /// + public IPromise ThenAll(Func> chain) => Then(value => Promise.All(chain(value)), null); - /// - /// Returns a promise that resolves when all of the promises in the enumerable argument have resolved. - /// Returns a promise of a collection of the resolved results. - /// - public static IPromise> All(params IPromise[] promises) => All((IEnumerable>)promises); // Cast is required to force use of the other All function. + /// + /// Returns a promise that resolves when all the promises in the enumerable argument have resolved. + /// Returns a promise of a collection of the resolved results. + /// + public static IPromise> All(params IPromise[] promises) => All((IEnumerable>)promises); // Cast is required to force use of the other All function. - /// - /// Returns a promise that resolves when all of the promises in the enumerable argument have resolved. - /// Returns a promise of a collection of the resolved results. - /// - public static IPromise> All(IEnumerable> promisesEnumerable) - { - List> promises = DiscordPool.Internal.GetList>(); - promises.AddRange(promisesEnumerable); + /// + /// Returns a promise that resolves when all of the promises in the enumerable argument have resolved. + /// Returns a promise of a collection of the resolved results. + /// + public static IPromise> All(IEnumerable> promisesEnumerable) + { + List> promises = DiscordPool.Internal.GetList>(); + promises.AddRange(promisesEnumerable); - if (promises.Count == 0) - { - return Promise>.Resolved(Enumerable.Empty()); - } + if (promises.Count == 0) + { + return Promise>.Resolved([]); + } - int remainingCount = promises.Count; - TPromised[] results = new TPromised[remainingCount]; - Promise> resultPromise = Create>(); + int remainingCount = promises.Count; + TPromised[] results = new TPromised[remainingCount]; + Promise> resultPromise = Create>(); - for (int index = 0; index < promises.Count; index++) - { - int resultIndex = index; - IPromise promise = promises[index]; - promise - .Then(result => + for (int index = 0; index < promises.Count; index++) + { + int resultIndex = index; + IPromise promise = promises[index]; + promise + .Then(result => + { + results[resultIndex] = result; + + --remainingCount; + if (remainingCount <= 0 && resultPromise.State == PromiseState.Pending) { - results[resultIndex] = result; - - --remainingCount; - if (remainingCount <= 0 && resultPromise.State == PromiseState.Pending) - { - // This will never happen if any of the promises errored. - resultPromise.Resolve(results); - } - }) - .Catch(ex => + // This will never happen if any of the promises errored. + resultPromise.Resolve(results); + } + }) + .Catch(ex => + { + if (resultPromise.State == PromiseState.Pending) { - if (resultPromise.State == PromiseState.Pending) - { - // If a promise errored and the result promise is still pending, reject it. - resultPromise.Reject(ex); - } - }); - } + // If a promise errored and the result promise is still pending, reject it. + resultPromise.Reject(ex); + } + }); + } - DiscordPool.Internal.FreeList(promises); + DiscordPool.Internal.FreeList(promises); - return resultPromise; - } + return resultPromise; + } - /// - public IPromise Finally(Action onComplete) + /// + public IPromise Finally(Action onComplete) + { + if (State == PromiseState.Resolved) { - if (State == PromiseState.Resolved) + try { - try - { - onComplete(); - return this; - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during resolved finally of Promise<{typeof(TPromised).Name}>", ex); - return Rejected(ex); - } + onComplete(); + return this; } - - Promise promise = Create(); - - Then(promise._onResolve); - Catch(e => + catch (Exception ex) { - try - { - onComplete(); - promise.Reject(e); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during catch finally of Promise<{typeof(TPromised).Name}>", ex); - promise.Reject(ex); - } - }); + DiscordExtension.GlobalLogger.Exception($"An error occured during resolved finally of Promise<{typeof(TPromised).Name}>", ex); + return Rejected(ex); + } + } - return promise.Then(promised => + Promise promise = Create(); + + Then(promise._onResolve); + Catch(e => + { + try { onComplete(); - return promised; - }); - } + promise.Reject(e); + } + catch (Exception ex) + { + DiscordExtension.GlobalLogger.Exception($"An error occured during catch finally of Promise<{typeof(TPromised).Name}>", ex); + promise.Reject(ex); + } + }); - /// - public IPromise ContinueWith(Func onComplete) + return promise.Then(promised => { - Promise promise = Promise.Create(); + onComplete(); + return promised; + }); + } - Then(x => promise.Resolve()); - Catch(e => promise.Resolve()); + /// + public IPromise ContinueWith(Func onComplete) + { + Promise promise = Promise.Create(); - return promise.Then(onComplete); - } + Then(_ => promise.Resolve()); + Catch(_ => promise.Resolve()); - /// - public IPromise ContinueWith(Func> onComplete) - { - Promise promise = Promise.Create(); + return promise.Then(onComplete); + } - Then(x => promise.Resolve()); - Catch(e => promise.Resolve()); + /// + public IPromise ContinueWith(Func> onComplete) + { + Promise promise = Promise.Create(); - return promise.Then(onComplete); - } - - /// - protected override void ClearHandlers() - { - _resolves.Clear(); - base.ClearHandlers(); - } + Then(_ => promise.Resolve()); + Catch(_ => promise.Resolve()); + + return promise.Then(onComplete); + } + + /// + public ValueTask AsTask() + { + return _taskSource.GetTask(); + } + + /// + public ValueTaskAwaiter GetAwaiter() + { + return _taskSource.GetTask().GetAwaiter(); + } + + /// + protected override void ClearHandlers() + { + _resolves.Clear(); + base.ClearHandlers(); + } - /// - protected override void EnterPool() - { - base.EnterPool(); - _resolveValue = default(TPromised); - _resolves.Clear(); - } + /// + protected override void EnterPool() + { + base.EnterPool(); + _resolveValue = default; + _resolves.Clear(); + _taskSource.Reset(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/RejectHandler.cs b/Oxide.Ext.Discord/Types/Promises/RejectHandler.cs index e27a2e630..1e903de37 100644 --- a/Oxide.Ext.Discord/Types/Promises/RejectHandler.cs +++ b/Oxide.Ext.Discord/Types/Promises/RejectHandler.cs @@ -5,40 +5,39 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a handler invoked when the promise is rejected. +/// +public readonly struct RejectHandler { /// - /// Represents a handler invoked when the promise is rejected. + /// Callback fn. /// - public struct RejectHandler - { - /// - /// Callback fn. - /// - private readonly Action _callback; + private readonly Action _callback; - /// - /// The promise that is rejected when there is an error while invoking the handler. - /// - private readonly IRejectable _rejectable; + /// + /// The promise that is rejected when there is an error while invoking the handler. + /// + private readonly IRejectable _rejectable; - internal RejectHandler(Action callback, IRejectable rejectable) + internal RejectHandler(Action callback, IRejectable rejectable) + { + _callback = callback; + _rejectable = rejectable; + } + + internal void Reject(Exception exception) + { + try { - _callback = callback; - _rejectable = rejectable; + _callback(exception); } - - internal void Reject(Exception exception) + catch (Exception ex) { - try - { - _callback(exception); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception("An error occured during reject of Promise", ex); - _rejectable.Reject(ex); - } + DiscordExtension.GlobalLogger.Exception("An error occured during reject of Promise", ex); + _rejectable.Reject(ex); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/ResolveHandler.cs b/Oxide.Ext.Discord/Types/Promises/ResolveHandler.cs index e4f0a606a..ed85ed7fa 100644 --- a/Oxide.Ext.Discord/Types/Promises/ResolveHandler.cs +++ b/Oxide.Ext.Discord/Types/Promises/ResolveHandler.cs @@ -5,40 +5,39 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a handler invoked when the promise is resolved. +/// +internal readonly struct ResolveHandler { /// - /// Represents a handler invoked when the promise is resolved. + /// Callback fn. /// - internal struct ResolveHandler - { - /// - /// Callback fn. - /// - private readonly Action _resolve; + private readonly Action _resolve; - /// - /// The promise that is rejected when there is an error while invoking the handler. - /// - private readonly IRejectable _rejectable; + /// + /// The promise that is rejected when there is an error while invoking the handler. + /// + private readonly IRejectable _rejectable; - public ResolveHandler(Action resolve, IRejectable rejectable) + public ResolveHandler(Action resolve, IRejectable rejectable) + { + _resolve = resolve; + _rejectable = rejectable; + } + + public void Resolve() + { + try { - _resolve = resolve; - _rejectable = rejectable; + _resolve(); } - - public void Resolve() + catch (Exception ex) { - try - { - _resolve(); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during resolve of Promise", ex); - _rejectable.Reject(ex); - } + DiscordExtension.GlobalLogger.Exception($"An error occured during resolve of Promise", ex); + _rejectable.Reject(ex); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/ResolveHandler{T}.cs b/Oxide.Ext.Discord/Types/Promises/ResolveHandler{T}.cs index b7289c5d1..90bbb2731 100644 --- a/Oxide.Ext.Discord/Types/Promises/ResolveHandler{T}.cs +++ b/Oxide.Ext.Discord/Types/Promises/ResolveHandler{T}.cs @@ -5,40 +5,39 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a handler invoked when the promise is resolved. +/// +internal readonly struct ResolveHandler { /// - /// Represents a handler invoked when the promise is resolved. + /// Callback fn. /// - internal struct ResolveHandler - { - /// - /// Callback fn. - /// - private readonly Action _resolve; + private readonly Action _resolve; - /// - /// The promise that is rejected when there is an error while invoking the handler. - /// - private readonly IRejectable _rejectable; + /// + /// The promise that is rejected when there is an error while invoking the handler. + /// + private readonly IRejectable _rejectable; - public ResolveHandler(Action resolve, IRejectable rejectable) + public ResolveHandler(Action resolve, IRejectable rejectable) + { + _resolve = resolve; + _rejectable = rejectable; + } + + public void Resolve(TPromised value) + { + try { - _resolve = resolve; - _rejectable = rejectable; + _resolve(value); } - - public void Resolve(TPromised value) + catch (Exception ex) { - try - { - _resolve(value); - } - catch (Exception ex) - { - DiscordExtension.GlobalLogger.Exception($"An error occured during resolve of Promise<{typeof(TPromised).Name}>", ex); - _rejectable.Reject(ex); - } + DiscordExtension.GlobalLogger.Exception($"An error occured during resolve of Promise<{typeof(TPromised).Name}>", ex); + _rejectable.Reject(ex); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/Timer/BaseTimerInstance.cs b/Oxide.Ext.Discord/Types/Promises/Timer/BaseTimerInstance.cs index 5393d488e..144879e5f 100644 --- a/Oxide.Ext.Discord/Types/Promises/Timer/BaseTimerInstance.cs +++ b/Oxide.Ext.Discord/Types/Promises/Timer/BaseTimerInstance.cs @@ -5,40 +5,39 @@ using Oxide.Ext.Discord.Entities; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal abstract class BaseTimerInstance : BasePoolable { - internal abstract class BaseTimerInstance : BasePoolable - { - public Snowflake Id => PendingPromise.Id; + public Snowflake Id => PendingPromise.Id; - /// - /// The pending promise which is an interface for a promise that can be rejected or resolved. - /// - internal IPendingPromise PendingPromise; - public bool IsCompleted { get; private set; } + /// + /// The pending promise which is an interface for a promise that can be rejected or resolved. + /// + internal IPendingPromise PendingPromise; + public bool IsCompleted { get; private set; } - public abstract void Update(float currentTime); + public abstract void Update(float currentTime); - protected void Init() - { - PendingPromise = Promise.Create(); - } + protected void Init() + { + PendingPromise = Promise.Create(); + } - internal void Resolve() - { - PendingPromise.Resolve(); - IsCompleted = true; - } + internal void Resolve() + { + PendingPromise.Resolve(); + IsCompleted = true; + } - public void Reject(Exception ex) - { - PendingPromise.Reject(ex); - IsCompleted = true; - } + public void Reject(Exception ex) + { + PendingPromise.Reject(ex); + IsCompleted = true; + } - protected override void EnterPool() - { - PendingPromise = null; - } + protected override void EnterPool() + { + PendingPromise = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/Timer/DelayTimerInstance.cs b/Oxide.Ext.Discord/Types/Promises/Timer/DelayTimerInstance.cs index a9ea015cf..14cabc037 100644 --- a/Oxide.Ext.Discord/Types/Promises/Timer/DelayTimerInstance.cs +++ b/Oxide.Ext.Discord/Types/Promises/Timer/DelayTimerInstance.cs @@ -3,31 +3,30 @@ using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal sealed class DelayTimerInstance : BaseTimerInstance { - internal sealed class DelayTimerInstance : BaseTimerInstance - { - private float _endTime; + private float _endTime; - public static DelayTimerInstance Create(float endTime) - { - DelayTimerInstance timer = DiscordPool.Internal.Get(); - timer.Init(endTime); - return timer; - } + public static DelayTimerInstance Create(float endTime) + { + DelayTimerInstance timer = DiscordPool.Internal.Get(); + timer.Init(endTime); + return timer; + } - private void Init(float endTime) - { - base.Init(); - _endTime = endTime; - } + private void Init(float endTime) + { + base.Init(); + _endTime = endTime; + } - public override void Update(float currentTime) + public override void Update(float currentTime) + { + if (_endTime <= currentTime) { - if (_endTime <= currentTime) - { - Resolve(); - } + Resolve(); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/Timer/EventTimerInstance.cs b/Oxide.Ext.Discord/Types/Promises/Timer/EventTimerInstance.cs index dd68a60df..1a06137e0 100644 --- a/Oxide.Ext.Discord/Types/Promises/Timer/EventTimerInstance.cs +++ b/Oxide.Ext.Discord/Types/Promises/Timer/EventTimerInstance.cs @@ -4,51 +4,50 @@ using System; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal sealed class EventTimerInstance : BaseTimerInstance { - internal sealed class EventTimerInstance : BaseTimerInstance - { - /// - /// Predicate for resolving the promise - /// - private Func _predicate; + /// + /// Predicate for resolving the promise + /// + private Func _predicate; - /// - /// The time the promise was started - /// - private float _timeStarted; + /// + /// The time the promise was started + /// + private float _timeStarted; - private bool _state; + private bool _state; - public static EventTimerInstance Create(Func predicate, float timeStarted, bool state) - { - EventTimerInstance timer = DiscordPool.Internal.Get(); - timer.Init(predicate, timeStarted, state); - return timer; - } + public static EventTimerInstance Create(Func predicate, float timeStarted, bool state) + { + EventTimerInstance timer = DiscordPool.Internal.Get(); + timer.Init(predicate, timeStarted, state); + return timer; + } - private void Init(Func predicate, float timeStarted, bool state) - { - base.Init(); - _predicate = predicate; - _timeStarted = timeStarted; - _state = state; - } + private void Init(Func predicate, float timeStarted, bool state) + { + base.Init(); + _predicate = predicate; + _timeStarted = timeStarted; + _state = state; + } - public override void Update(float currentTime) + public override void Update(float currentTime) + { + float elapsedTime = currentTime - _timeStarted; + try { - float elapsedTime = currentTime - _timeStarted; - try + if (_predicate(elapsedTime) == _state) { - if (_predicate(elapsedTime) == _state) - { - Resolve(); - } - } - catch (Exception ex) - { - Reject(ex); + Resolve(); } } + catch (Exception ex) + { + Reject(ex); + } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Promises/Timer/PromiseTimer.cs b/Oxide.Ext.Discord/Types/Promises/Timer/PromiseTimer.cs index 050d7d817..22ca07f62 100644 --- a/Oxide.Ext.Discord/Types/Promises/Timer/PromiseTimer.cs +++ b/Oxide.Ext.Discord/Types/Promises/Timer/PromiseTimer.cs @@ -6,97 +6,96 @@ using Oxide.Ext.Discord.Exceptions; using Oxide.Ext.Discord.Interfaces; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Timer Implementation using promises +/// +internal sealed class PromiseTimer : Singleton { /// - /// Timer Implementation using promises + /// The current running total for time that this PromiseTimer has run for /// - internal sealed class PromiseTimer : Singleton - { - /// - /// The current running total for time that this PromiseTimer has run for - /// - private float _currentTime; + private float _currentTime; - /// - /// Currently pending promises - /// - private readonly List _waiting = new List(); + /// + /// Currently pending promises + /// + private readonly List _waiting = new(); - private PromiseTimer() { } + private PromiseTimer() { } - /// - /// Resolve the returned promise once the time has elapsed - /// - public IPromise WaitFor(float seconds) => SetupTimer(DelayTimerInstance.Create(_currentTime + seconds)); + /// + /// Resolve the returned promise once the time has elapsed + /// + public IPromise WaitFor(float seconds) => SetupTimer(DelayTimerInstance.Create(_currentTime + seconds)); - /// - /// Resolve the returned promise once the predicate evaluates to false - /// - public IPromise WaitWhile(Func predicate) => SetupTimer(EventTimerInstance.Create(predicate, _currentTime, false)); + /// + /// Resolve the returned promise once the predicate evaluates to false + /// + public IPromise WaitWhile(Func predicate) => SetupTimer(EventTimerInstance.Create(predicate, _currentTime, false)); - /// - /// Resolve the returned promise once the predicate evaluates to true - /// - public IPromise WaitUntil(Func predicate) => SetupTimer(EventTimerInstance.Create(predicate, _currentTime, true)); + /// + /// Resolve the returned promise once the predicate evaluates to true + /// + public IPromise WaitUntil(Func predicate) => SetupTimer(EventTimerInstance.Create(predicate, _currentTime, true)); - private IPromise SetupTimer(BaseTimerInstance timer) - { - _waiting.Add(timer); - return timer.PendingPromise; - } + private IPromise SetupTimer(BaseTimerInstance timer) + { + _waiting.Add(timer); + return timer.PendingPromise; + } - /// - /// Cancel a waiting promise and reject it immediately. - /// - public bool Cancel(IPromise promise) + /// + /// Cancel a waiting promise and reject it immediately. + /// + public bool Cancel(IPromise promise) + { + BaseTimerInstance timer = FindInWaiting(promise); + if (timer == null) { - BaseTimerInstance timer = FindInWaiting(promise); - if (timer == null) - { - return false; - } + return false; + } - timer.Reject(new PromiseCancelledException("Promise was cancelled by user.")); - _waiting.Remove(timer); + timer.Reject(new PromiseCancelledException("Promise was cancelled by user.")); + _waiting.Remove(timer); - return true; - } + return true; + } - /// - /// Update all pending promises. Must be called for the promises to progress and resolve at all. - /// - internal void Update(float deltaTime) + /// + /// Update all pending promises. Must be called for the promises to progress and resolve at all. + /// + internal void Update(float deltaTime) + { + _currentTime += deltaTime; + if (_waiting.Count == 0) { - _currentTime += deltaTime; - if (_waiting.Count == 0) - { - return; - } + return; + } - for (int index = 0; index < _waiting.Count;) + for (int index = 0; index < _waiting.Count;) + { + BaseTimerInstance timer = _waiting[index]; + timer.Update(_currentTime); + if (timer.IsCompleted) { - BaseTimerInstance timer = _waiting[index]; - timer.Update(_currentTime); - if (timer.IsCompleted) - { - _waiting.Remove(timer); - } + _waiting.Remove(timer); } } + } - private BaseTimerInstance FindInWaiting(IPromise promise) + private BaseTimerInstance FindInWaiting(IPromise promise) + { + for (int index = 0; index < _waiting.Count; index++) { - for (int index = 0; index < _waiting.Count; index++) + BaseTimerInstance instance = _waiting[index]; + if (instance.Id == promise.Id) { - BaseTimerInstance instance = _waiting[index]; - if (instance.Id == promise.Id) - { - return instance; - } + return instance; } - - return null; } + + return null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/RateLimits/BaseRateLimit.cs b/Oxide.Ext.Discord/Types/RateLimits/BaseRateLimit.cs index 470466c01..ac5b3f798 100644 --- a/Oxide.Ext.Discord/Types/RateLimits/BaseRateLimit.cs +++ b/Oxide.Ext.Discord/Types/RateLimits/BaseRateLimit.cs @@ -4,102 +4,101 @@ using Oxide.Ext.Discord.Interfaces; using Timer = System.Timers.Timer; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a base rate limit for websocket and rest api requests +/// +public abstract class BaseRateLimit { /// - /// Represents a base rate limit for websocket and rest api requests + /// The number of requests that have executed since the last reset /// - public abstract class BaseRateLimit - { - /// - /// The number of requests that have executed since the last reset - /// - protected int NumRequests; + protected int NumRequests; - /// - /// Returns when the last reset occured - /// - protected DateTimeOffset LastReset; + /// + /// Returns when the last reset occured + /// + protected DateTimeOffset LastReset; - /// - /// The max number of requests this rate limit can handle per interval - /// - protected readonly int MaxRequests; + /// + /// The max number of requests this rate limit can handle per interval + /// + protected readonly int MaxRequests; - /// - /// The interval in which this resets at - /// - protected readonly long ResetInterval; + /// + /// The interval in which this resets at + /// + protected readonly long ResetInterval; - /// - /// Logger for the rate limit - /// - protected readonly ILogger Logger; + /// + /// Logger for the rate limit + /// + protected readonly ILogger Logger; - private Timer _timer; + private Timer _timer; - /// - /// Base Rate Limit Constructor - /// - /// Max requests per interval - /// Reset Interval in milliseconds - /// Logger - protected BaseRateLimit(int maxRequests, long interval, ILogger logger) - { - MaxRequests = maxRequests; - ResetInterval = interval; - Logger = logger; + /// + /// Base Rate Limit Constructor + /// + /// Max requests per interval + /// Reset Interval in milliseconds + /// Logger + protected BaseRateLimit(int maxRequests, long interval, ILogger logger) + { + MaxRequests = maxRequests; + ResetInterval = interval; + Logger = logger; - _timer = new Timer(interval); - _timer.Elapsed += ResetRateLimit; - _timer.Start(); - LastReset = DateTimeOffset.UtcNow; - } + _timer = new Timer(interval); + _timer.Elapsed += ResetRateLimit; + _timer.Start(); + LastReset = DateTimeOffset.UtcNow; + } - private void ResetRateLimit(object sender, ElapsedEventArgs e) - { - OnRateLimitReset(); - LastReset = DateTimeOffset.UtcNow; - Interlocked.Exchange(ref NumRequests, 0); - } + private void ResetRateLimit(object sender, ElapsedEventArgs e) + { + OnRateLimitReset(); + LastReset = DateTimeOffset.UtcNow; + Interlocked.Exchange(ref NumRequests, 0); + } - /// - /// Returns the next reset for the rate limit - /// - /// - public virtual DateTimeOffset NextReset() => LastReset + TimeSpan.FromMilliseconds(ResetInterval); + /// + /// Returns the next reset for the rate limit + /// + /// + public virtual DateTimeOffset NextReset() => LastReset + TimeSpan.FromMilliseconds(ResetInterval); - /// - /// Called when an API request is fired - /// - protected void FiredRequestInternal() - { - Interlocked.Add(ref NumRequests, 1); - } + /// + /// Called when an API request is fired + /// + protected void FiredRequestInternal() + { + Interlocked.Add(ref NumRequests, 1); + } - /// - /// Called when the rate limit is reset - /// - protected abstract void OnRateLimitReset(); + /// + /// Called when the rate limit is reset + /// + protected abstract void OnRateLimitReset(); - /// - /// Returns true if we have reached the global rate limit - /// - public bool HasReachedRateLimit => NumRequests >= MaxRequests; + /// + /// Returns true if we have reached the global rate limit + /// + public bool HasReachedRateLimit => NumRequests >= MaxRequests; - /// - /// Called when a bot is shutting down - /// - public void Shutdown() + /// + /// Called when a bot is shutting down + /// + public void Shutdown() + { + if (_timer == null) { - if (_timer == null) - { - return; - } - - _timer.Stop(); - _timer.Dispose(); - _timer = null; + return; } + + _timer.Stop(); + _timer.Dispose(); + _timer = null; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/RateLimits/RestRateLimit.cs b/Oxide.Ext.Discord/Types/RateLimits/RestRateLimit.cs index fce6f1610..096c9eaa0 100644 --- a/Oxide.Ext.Discord/Types/RateLimits/RestRateLimit.cs +++ b/Oxide.Ext.Discord/Types/RateLimits/RestRateLimit.cs @@ -2,54 +2,53 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a rate limit for rest requests +/// +public class RestRateLimit : BaseRateLimit { + private DateTimeOffset _retryAfter; + /// - /// Represents a rate limit for rest requests + /// Constructor for RestRateLimit /// - public class RestRateLimit : BaseRateLimit - { - private DateTimeOffset _retryAfter; - - /// - /// Constructor for RestRateLimit - /// - public RestRateLimit(ILogger logger) : base(50, 1 * 1000L, logger) { } + public RestRateLimit(ILogger logger) : base(50, 1 * 1000L, logger) { } - /// - /// Called if we receive a header notifying us of hitting the rate limit - /// - /// How long until we should retry API request again - public void ReachedRateLimit(DateTimeOffset retryAfter) - { - NumRequests = MaxRequests; - _retryAfter = retryAfter; - } + /// + /// Called if we receive a header notifying us of hitting the rate limit + /// + /// How long until we should retry API request again + public void ReachedRateLimit(DateTimeOffset retryAfter) + { + NumRequests = MaxRequests; + _retryAfter = retryAfter; + } - /// - protected override void OnRateLimitReset() + /// + protected override void OnRateLimitReset() + { + if (NumRequests > 0) { - if (NumRequests > 0) - { - Logger.Debug($"{nameof(RestRateLimit)}.{nameof(OnRateLimitReset)} Num Requests: {{0}} Reached Rate Limit: {{1}}", NumRequests, HasReachedRateLimit); - } + Logger.Debug($"{nameof(RestRateLimit)}.{nameof(OnRateLimitReset)} Num Requests: {{0}} Reached Rate Limit: {{1}}", NumRequests, HasReachedRateLimit); } + } - /// - /// Returns how long until the current rate limit period will expire - /// - public override DateTimeOffset NextReset() - { - DateTimeOffset nextReset = base.NextReset(); - return nextReset > _retryAfter ? nextReset : _retryAfter; - } + /// + /// Returns how long until the current rate limit period will expire + /// + public override DateTimeOffset NextReset() + { + DateTimeOffset nextReset = base.NextReset(); + return nextReset > _retryAfter ? nextReset : _retryAfter; + } - /// - /// Called when an API request is fired - /// - public void FiredRequest() - { - FiredRequestInternal(); - } + /// + /// Called when an API request is fired + /// + public void FiredRequest() + { + FiredRequestInternal(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/RateLimits/WebsocketRateLimit.cs b/Oxide.Ext.Discord/Types/RateLimits/WebsocketRateLimit.cs index f2a6b2122..fc4157c68 100644 --- a/Oxide.Ext.Discord/Types/RateLimits/WebsocketRateLimit.cs +++ b/Oxide.Ext.Discord/Types/RateLimits/WebsocketRateLimit.cs @@ -4,49 +4,48 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Plugins; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a WebSocket Rate Limit +/// +public class WebsocketRateLimit : BaseRateLimit { + private readonly ConcurrentDictionary _pluginRequests = new(); + internal const int MaxRequestPerPlugin = 60; + internal const long RateLimitInterval = 60 * 1000L; + /// - /// Represents a WebSocket Rate Limit + /// Constructor for WebsocketRateLimit /// - public class WebsocketRateLimit : BaseRateLimit - { - private readonly ConcurrentDictionary _pluginRequests = new ConcurrentDictionary(); - internal const int MaxRequestPerPlugin = 60; - internal const long RateLimitInterval = 60 * 1000L; - - /// - /// Constructor for WebsocketRateLimit - /// - public WebsocketRateLimit(ILogger logger) : base(110, RateLimitInterval, logger) { } + public WebsocketRateLimit(ILogger logger) : base(110, RateLimitInterval, logger) { } - /// - /// Called when an API request is fired - /// - public void FiredRequest(WebSocketCommand command) - { - _pluginRequests.TryGetValue(command.Client.PluginId, out int numRequest); - _pluginRequests[command.Client.PluginId] = numRequest + 1; - Logger.Debug($"{nameof(WebsocketRateLimit)}.{nameof(FiredRequest)} For {{0}} Num Requests {{1}}", command.Client.PluginId, numRequest + 1); - FiredRequestInternal(); - } + /// + /// Called when an API request is fired + /// + public void FiredRequest(WebSocketCommand command) + { + _pluginRequests.TryGetValue(command.Client.PluginId, out int numRequest); + _pluginRequests[command.Client.PluginId] = numRequest + 1; + Logger.Debug($"{nameof(WebsocketRateLimit)}.{nameof(FiredRequest)} For {{0}} Num Requests {{1}}", command.Client.PluginId, numRequest + 1); + FiredRequestInternal(); + } - /// - /// Returns if the client can return the given command. - /// This is used to limit plugins to a certain number of websocket commands per rate limit tick - /// - /// Command that is to be ran - /// True if the command can run; False otherwise - public bool CanFireRequest(WebSocketCommand command) => !_pluginRequests.TryGetValue(command.Client.PluginId, out int numRequest) || numRequest < MaxRequestPerPlugin; + /// + /// Returns if the client can return the given command. + /// This is used to limit plugins to a certain number of websocket commands per rate limit tick + /// + /// Command that is to be ran + /// True if the command can run; False otherwise + public bool CanFireRequest(WebSocketCommand command) => !_pluginRequests.TryGetValue(command.Client.PluginId, out int numRequest) || numRequest < MaxRequestPerPlugin; - /// - protected override void OnRateLimitReset() + /// + protected override void OnRateLimitReset() + { + _pluginRequests.Clear(); + if (NumRequests > 0) { - _pluginRequests.Clear(); - if (NumRequests > 0) - { - Logger.Debug($"{nameof(RestRateLimit)}.{nameof(OnRateLimitReset)} Num Requests: {{0}} Reached Rate Limit: {{1}}", NumRequests, HasReachedRateLimit); - } + Logger.Debug($"{nameof(RestRateLimit)}.{nameof(OnRateLimitReset)} Num Requests: {{0}} Reached Rate Limit: {{1}}", NumRequests, HasReachedRateLimit); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/ReverseStringTokenizer.cs b/Oxide.Ext.Discord/Types/ReverseStringTokenizer.cs new file mode 100644 index 000000000..170129ba3 --- /dev/null +++ b/Oxide.Ext.Discord/Types/ReverseStringTokenizer.cs @@ -0,0 +1,44 @@ +using System; + +namespace Oxide.Ext.Discord.Types; + +internal ref struct ReverseStringTokenizer +{ + private ReadOnlySpan _remaining; + private readonly ReadOnlySpan _token; + + public ReadOnlySpan Current { get; private set; } + + public ReverseStringTokenizer(string str, string token) + { + _remaining = str; + _token = token; + } + + public bool MoveNext() + { + if (_remaining.Length == 0) + { + return false; + } + + int index = _remaining.LastIndexOf(_token); + if (index < 0) + { + Current = _remaining; + _remaining = default; + return true; + } + + int length = _remaining.Length - index; + if (length <= 1) + { + _remaining = _remaining.Slice(0, index); + return MoveNext(); + } + + Current = _remaining.Slice(index + 1, length - 1); + _remaining = _remaining.Slice(0, Math.Min(index, _remaining.Length)); + return true; + } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Singleton.cs b/Oxide.Ext.Discord/Types/Singleton.cs index 4b29b39c0..5b4d6624a 100644 --- a/Oxide.Ext.Discord/Types/Singleton.cs +++ b/Oxide.Ext.Discord/Types/Singleton.cs @@ -1,43 +1,42 @@ using System; using System.Reflection; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// Represents a singleton of type {T} +/// +/// Type of the singleton +public abstract class Singleton where T : Singleton { /// - /// Represents a singleton of type {T} + /// Retrieves the instance of the singleton /// - /// Type of the singleton - public abstract class Singleton where T : Singleton - { - /// - /// Retrieves the instance of the singleton - /// - public static readonly T Instance; + public static readonly T Instance; - private const string ErrorMessage = "must have only one constructor that is parameterless and private."; + private const string ErrorMessage = "must have only one constructor that is parameterless and private."; - static Singleton() + static Singleton() + { + ConstructorInfo[] constructors = typeof(T).GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (constructors.Length != 1) { - ConstructorInfo[] constructors = typeof(T).GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - if (constructors.Length != 1) - { - throw new Exception($"{typeof(T)} {ErrorMessage}"); - } + throw new Exception($"{typeof(T)} {ErrorMessage}"); + } - ConstructorInfo constructor = constructors[0]; - if (constructor.IsPublic) - { - throw new Exception($"{typeof(T)} {ErrorMessage}"); - } + ConstructorInfo constructor = constructors[0]; + if (constructor.IsPublic) + { + throw new Exception($"{typeof(T)} {ErrorMessage}"); + } - try - { - Instance = (T)constructor.Invoke(null); - } - catch - { - throw new Exception($"{typeof(T)} {ErrorMessage}"); - } + try + { + Instance = (T)constructor.Invoke(null); + } + catch + { + throw new Exception($"{typeof(T)} {ErrorMessage}"); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/StringTokenizer.cs b/Oxide.Ext.Discord/Types/StringTokenizer.cs index d83d0395c..23b0d7d98 100644 --- a/Oxide.Ext.Discord/Types/StringTokenizer.cs +++ b/Oxide.Ext.Discord/Types/StringTokenizer.cs @@ -1,79 +1,47 @@ using System; -using System.Collections; -using System.Collections.Generic; -using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal ref struct StringTokenizer { - internal class StringTokenizer : BasePoolable, IEnumerator> - { - private string _string; - private char _token; - private int _maxLength; - private int _stringIndex; - public int Index { get; private set; } = -1; + private ReadOnlySpan _remaining; + private readonly ReadOnlySpan _token; + private readonly int _maxLength; + public int Index { get; private set; } = -1; - public ReadOnlyMemory Current { get; private set; } + public ReadOnlySpan Current { get; private set; } - object IEnumerator.Current => Current; + public StringTokenizer(string str, string token) : this(str, token, str.Length) { } - public static StringTokenizer Create(string str, char token) => Create(str, token, str.Length); + public StringTokenizer(string str, string token, int maxLength) + { + _remaining = str; + _token = token; + _maxLength = maxLength; + } - public static StringTokenizer Create(string str, char token, int maxLength) + public bool MoveNext() + { + if (_remaining.Length == 0) { - StringTokenizer tokenizer = DiscordPool.Internal.Get(); - tokenizer.Init(str, token, maxLength); - return tokenizer; + return false; } - - private void Init(string str, char token, int maxLength) + + int index = _remaining.IndexOf(_token); + if (index == -1 || index > _maxLength) { - _string = str; - _token = token; - _maxLength = maxLength; + index = _remaining.Length; } - - public bool MoveNext() - { - if (_stringIndex >= _maxLength) - { - return false; - } - - int index = _string.IndexOf(_token, _stringIndex); - if (index == -1 || index >= _maxLength) - { - index = _maxLength; - } - int length = index - _stringIndex; - if (length == 0) - { - _stringIndex = index + 1; - return MoveNext(); - } - - Current = _string.AsMemory().Slice(_stringIndex, length); - _stringIndex = index + 1; - Index++; - return true; - } - - public void Reset() + if (index == 0) { - _stringIndex = 0; - Current = null; - Index = -1; + _remaining = _remaining.Slice(1); + return MoveNext(); } - protected override void EnterPool() - { - _stringIndex = 0; - Current = null; - _token = default(char); - _maxLength = 0; - _stringIndex = 0; - Index = -1; - } + Current = _remaining.Slice(0, index); + _remaining = _remaining.Slice(Math.Min(_remaining.Length, index + 1)); + Index++; + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Threading/AdjustableSemephore.cs b/Oxide.Ext.Discord/Types/Threading/AdjustableSemephore.cs index 384c470ad..2ffc54fcf 100644 --- a/Oxide.Ext.Discord/Types/Threading/AdjustableSemephore.cs +++ b/Oxide.Ext.Discord/Types/Threading/AdjustableSemephore.cs @@ -2,87 +2,86 @@ using System.Threading; using System.Threading.Tasks; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal class AdjustableSemaphore { - internal class AdjustableSemaphore - { - private readonly object _syncRoot = new object(); - private int _maximum; - public int Available { get; private set; } + private readonly object _syncRoot = new(); + private int _maximum; + public int Available { get; private set; } - public AdjustableSemaphore(int maximumCount) - { - MaximumCount = maximumCount; - } + public AdjustableSemaphore(int maximumCount) + { + MaximumCount = maximumCount; + } - public int MaximumCount + public int MaximumCount + { + get { - get - { - lock (_syncRoot) - { - return _maximum; - } - } - set + lock (_syncRoot) { - lock (_syncRoot) - { - if (value < 0) - { - throw new ArgumentException("Must be greater than or equal to 0.", nameof(MaximumCount)); - } - - Available += value - _maximum; - _maximum = value; - Monitor.PulseAll(_syncRoot); - } + return _maximum; } } - - public ValueTask WaitOneAsync() + set { lock (_syncRoot) { - while (Available <= 0) + if (value < 0) { - Monitor.Wait(_syncRoot); + throw new ArgumentException("Must be greater than or equal to 0.", nameof(MaximumCount)); } - Available--; + + Available += value - _maximum; + _maximum = value; + Monitor.PulseAll(_syncRoot); } - - return new ValueTask(); } + } - public void Release() + public ValueTask WaitOneAsync() + { + lock (_syncRoot) { - lock (_syncRoot) + while (Available <= 0) { - if (Available + 1 <= _maximum) - { - Available += 1; - Monitor.Pulse(_syncRoot); - } - else - { - throw new Exception($"Adding 1 the given count to the semaphore would cause it to exceed its maximum count of {_maximum}."); - } + Monitor.Wait(_syncRoot); } + Available--; } - public void AllowAllThrough() + return new ValueTask(); + } + + public void Release() + { + lock (_syncRoot) { - MaximumCount = int.MaxValue; - //Needs to be in a lock or an exception is thrown - lock (_syncRoot) + if (Available + 1 <= _maximum) { - Monitor.PulseAll(_syncRoot); + Available += 1; + Monitor.Pulse(_syncRoot); + } + else + { + throw new Exception($"Adding 1 the given count to the semaphore would cause it to exceed its maximum count of {_maximum}."); } } + } - public void Reset() + public void AllowAllThrough() + { + MaximumCount = int.MaxValue; + //Needs to be in a lock or an exception is thrown + lock (_syncRoot) { - MaximumCount = 1; + Monitor.PulseAll(_syncRoot); } } + + public void Reset() + { + MaximumCount = 1; + } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Threading/DiscordConcurrentQueue.cs b/Oxide.Ext.Discord/Types/Threading/DiscordConcurrentQueue.cs index 0ce28e75d..f118c397d 100644 --- a/Oxide.Ext.Discord/Types/Threading/DiscordConcurrentQueue.cs +++ b/Oxide.Ext.Discord/Types/Threading/DiscordConcurrentQueue.cs @@ -4,185 +4,184 @@ using System.Collections.Generic; using System.Threading; -namespace Oxide.Ext.Discord.Types -{ - internal class DiscordConcurrentQueue : ICollection, IProducerConsumerCollection, IDisposable - { - private readonly List _list = new List(); - private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - - public int Count - { - get - { - _lock.EnterReadLock(); - try - { - return _list.Count; - } - finally - { - if (_lock.IsReadLockHeld) _lock.ExitReadLock(); - } - } - } - - public object SyncRoot => throw new NotSupportedException("The SyncRoot property may not be used for the synchronization of concurrent collections."); - public bool IsSynchronized => false; +namespace Oxide.Ext.Discord.Types; - public bool IsReadOnly => ((ICollection)_list).IsReadOnly; - - ~DiscordConcurrentQueue() - { - _lock?.Dispose(); - } - - public void Dispose() - { - GC.SuppressFinalize(this); - _lock?.Dispose(); - } +internal class DiscordConcurrentQueue : ICollection, IProducerConsumerCollection, IDisposable +{ + private readonly List _list = []; + private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.SupportsRecursion); - public IEnumerator GetEnumerator() + public int Count + { + get { _lock.EnterReadLock(); try { - int count = Count; - for (int i = 0; i < count; i++) - { - yield return _list[i]; - } + return _list.Count; } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } + } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public object SyncRoot => throw new NotSupportedException("The SyncRoot property may not be used for the synchronization of concurrent collections."); + public bool IsSynchronized => false; - public void Add(T item) + public bool IsReadOnly => ((ICollection)_list).IsReadOnly; + + ~DiscordConcurrentQueue() + { + _lock?.Dispose(); + } + + public void Dispose() + { + GC.SuppressFinalize(this); + _lock?.Dispose(); + } + + public IEnumerator GetEnumerator() + { + _lock.EnterReadLock(); + try { - _lock.EnterWriteLock(); - try + int count = Count; + for (int i = 0; i < count; i++) { - _list.Add(item); - } - finally - { - if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); + yield return _list[i]; } } + finally + { + if (_lock.IsReadLockHeld) _lock.ExitReadLock(); + } + } - public void Clear() + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public void Add(T item) + { + _lock.EnterWriteLock(); + try { - _lock.EnterWriteLock(); - try - { - _list.Clear(); - } - finally - { - if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); - } + _list.Add(item); + } + finally + { + if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } + } - public bool Contains(T item) + public void Clear() + { + _lock.EnterWriteLock(); + try { - _lock.EnterReadLock(); - try - { - return _list.Contains(item); - } - finally - { - if (_lock.IsReadLockHeld) _lock.ExitReadLock(); - } + _list.Clear(); } + finally + { + if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); + } + } - public void CopyTo(T[] array, int arrayIndex) + public bool Contains(T item) + { + _lock.EnterReadLock(); + try { - _lock.EnterReadLock(); - try - { - _list.CopyTo(array, arrayIndex); - } - finally - { - if (_lock.IsReadLockHeld) _lock.ExitReadLock(); - } + return _list.Contains(item); + } + finally + { + if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } + } - public bool TryAdd(T item) + public void CopyTo(T[] array, int arrayIndex) + { + _lock.EnterReadLock(); + try { - Add(item); - return true; + _list.CopyTo(array, arrayIndex); + } + finally + { + if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } + } + + public bool TryAdd(T item) + { + Add(item); + return true; + } - public bool TryTake(out T item) + public bool TryTake(out T item) + { + _lock.EnterWriteLock(); + try { - _lock.EnterWriteLock(); - try - { - if (Count == 0) - { - item = default(T); - return false; - } - - item = _list[0]; - _list.RemoveAt(0); - return true; - } - finally + if (Count == 0) { - if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); + item = default; + return false; } + + item = _list[0]; + _list.RemoveAt(0); + return true; } + finally + { + if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); + } + } - public T[] ToArray() + public T[] ToArray() + { + _lock.EnterReadLock(); + try { - _lock.EnterReadLock(); - try - { - return _list.ToArray(); - } - finally - { - if (_lock.IsReadLockHeld) _lock.ExitReadLock(); - } + return _list.ToArray(); + } + finally + { + if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } + } - public bool Remove(T item) + public bool Remove(T item) + { + _lock.EnterWriteLock(); + try { - _lock.EnterWriteLock(); - try - { - return _list.Remove(item); - } - finally - { - if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); - } + return _list.Remove(item); } + finally + { + if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); + } + } - public void RemoveAll(Predicate predicate) + public void RemoveAll(Predicate predicate) + { + _lock.EnterWriteLock(); + try { - _lock.EnterWriteLock(); - try - { - _list.RemoveAll(predicate); - } - finally - { - if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); - } + _list.RemoveAll(predicate); } - - public void CopyTo(Array array, int index) + finally { - throw new NotSupportedException(); + if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } + + public void CopyTo(Array array, int index) + { + throw new NotSupportedException(); + } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Threading/DiscordConcurrentSet.cs b/Oxide.Ext.Discord/Types/Threading/DiscordConcurrentSet.cs index 4963da232..9478d99f1 100644 --- a/Oxide.Ext.Discord/Types/Threading/DiscordConcurrentSet.cs +++ b/Oxide.Ext.Discord/Types/Threading/DiscordConcurrentSet.cs @@ -2,97 +2,96 @@ using System.Collections.Generic; using System.Threading; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal class DiscordConcurrentSet : IDisposable { - internal class DiscordConcurrentSet : IDisposable - { - private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - private readonly HashSet _hashSet = new HashSet(); + private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.SupportsRecursion); + private readonly HashSet _hashSet = []; - public bool Add(T item) + public bool Add(T item) + { + _lock.EnterWriteLock(); + try { - _lock.EnterWriteLock(); - try - { - return _hashSet.Add(item); - } - finally - { - if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); - } + return _hashSet.Add(item); + } + finally + { + if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } + } - public void Clear() + public void Clear() + { + _lock.EnterWriteLock(); + try { - _lock.EnterWriteLock(); - try - { - _hashSet.Clear(); - } - finally - { - if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); - } + _hashSet.Clear(); + } + finally + { + if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } + } - public bool Contains(T item) + public bool Contains(T item) + { + _lock.EnterReadLock(); + try { - _lock.EnterReadLock(); - try - { - return _hashSet.Contains(item); - } - finally - { - if (_lock.IsReadLockHeld) _lock.ExitReadLock(); - } + return _hashSet.Contains(item); } + finally + { + if (_lock.IsReadLockHeld) _lock.ExitReadLock(); + } + } - public bool Remove(T item) + public bool Remove(T item) + { + _lock.EnterWriteLock(); + try { - _lock.EnterWriteLock(); - try - { - return _hashSet.Remove(item); - } - finally - { - if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); - } + return _hashSet.Remove(item); + } + finally + { + if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } + } - public int RemoveWhere(Predicate match) + public int RemoveWhere(Predicate match) + { + _lock.EnterWriteLock(); + try + { + return _hashSet.RemoveWhere(match); + } + finally + { + if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); + } + } + + public int Count + { + get { - _lock.EnterWriteLock(); try { - return _hashSet.RemoveWhere(match); + _lock.EnterReadLock(); + return _hashSet.Count; } finally { - if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); - } - } - - public int Count - { - get - { - try - { - _lock.EnterReadLock(); - return _hashSet.Count; - } - finally - { - if (_lock.IsReadLockHeld) _lock.ExitReadLock(); - } + if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } + } - public void Dispose() - { - _lock?.Dispose(); - } + public void Dispose() + { + _lock?.Dispose(); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Threading/ManualResetValueTaskSource.cs b/Oxide.Ext.Discord/Types/Threading/ManualResetValueTaskSource.cs new file mode 100644 index 000000000..b193079d3 --- /dev/null +++ b/Oxide.Ext.Discord/Types/Threading/ManualResetValueTaskSource.cs @@ -0,0 +1,34 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using System.Threading.Tasks.Sources; + +namespace Oxide.Ext.Discord.Types; + +internal class ManualResetValueTaskSource : IValueTaskSource +{ + private ManualResetValueTaskSourceCore _taskSource; + + public short Version => _taskSource.Version; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueTask GetTask() => new(this, _taskSource.Version); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SetResult() => _taskSource.SetResult(null); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SetException(Exception ex) => _taskSource.SetException(ex); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Reset() => _taskSource.Reset(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GetResult(short token) => _taskSource.GetResult(token); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ValueTaskSourceStatus GetStatus(short token) => _taskSource.GetStatus(token); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _taskSource.OnCompleted(continuation, state, token, flags); +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Threading/ManualResetValueTaskSource{T}.cs b/Oxide.Ext.Discord/Types/Threading/ManualResetValueTaskSource{T}.cs new file mode 100644 index 000000000..4d8edcbe6 --- /dev/null +++ b/Oxide.Ext.Discord/Types/Threading/ManualResetValueTaskSource{T}.cs @@ -0,0 +1,34 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using System.Threading.Tasks.Sources; + +namespace Oxide.Ext.Discord.Types; + +internal class ManualResetValueTaskSource : IValueTaskSource +{ + private ManualResetValueTaskSourceCore _taskSource; + + public short Version => _taskSource.Version; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueTask GetTask() => new(this, _taskSource.Version); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SetResult(T result) => _taskSource.SetResult(result); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SetException(Exception ex) => _taskSource.SetException(ex); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Reset() => _taskSource.Reset(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T GetResult(short token) => _taskSource.GetResult(token); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ValueTaskSourceStatus GetStatus(short token) => _taskSource.GetStatus(token); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _taskSource.OnCompleted(continuation, state, token, flags); +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Trie/AddState.cs b/Oxide.Ext.Discord/Types/Trie/AddState.cs index b43765fbf..4d3faeda2 100644 --- a/Oxide.Ext.Discord/Types/Trie/AddState.cs +++ b/Oxide.Ext.Discord/Types/Trie/AddState.cs @@ -1,25 +1,24 @@ // Originally from: https://github.com/gmamaladze/trienet // Modified by: MJSU -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal struct AddState { - internal struct AddState - { - public Node Leaf; - public Node Node; - public StringSlice Text; - public int Offset; + public Node Leaf; + public Node Node; + public StringSlice Text; + public int Offset; - public AddState(Node leaf, Node node, StringSlice text, int offset) - { - Leaf = leaf; - Node = node; - Text = text; - Offset = offset; - } + public AddState(Node leaf, Node node, StringSlice text, int offset) + { + Leaf = leaf; + Node = node; + Text = text; + Offset = offset; + } - public AddState SliceLastChar() => new AddState(Leaf, Node, Text.SliceLastChar(), Offset); + public AddState SliceLastChar() => new(Leaf, Node, Text.SliceLastChar(), Offset); - public AddState TraverseNodeLevel() => new AddState(Leaf, Node.Suffix, Text, Offset - 1); - } + public AddState TraverseNodeLevel() => new(Leaf, Node.Suffix, Text, Offset - 1); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Trie/Edge.cs b/Oxide.Ext.Discord/Types/Trie/Edge.cs index a9ca51207..7ed638131 100644 --- a/Oxide.Ext.Discord/Types/Trie/Edge.cs +++ b/Oxide.Ext.Discord/Types/Trie/Edge.cs @@ -1,17 +1,16 @@ // Originally from: https://github.com/gmamaladze/trienet // Modified by: MJSU -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal class Edge { - internal class Edge - { - public StringSlice Label; - public readonly Node Node; + public StringSlice Label; + public readonly Node Node; - public Edge(StringSlice label, Node node) - { - Label = label; - Node = node; - } + public Edge(StringSlice label, Node node) + { + Label = label; + Node = node; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Trie/EdgeKey.cs b/Oxide.Ext.Discord/Types/Trie/EdgeKey.cs index d26eb5c74..02f78999a 100644 --- a/Oxide.Ext.Discord/Types/Trie/EdgeKey.cs +++ b/Oxide.Ext.Discord/Types/Trie/EdgeKey.cs @@ -3,34 +3,33 @@ using System; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal readonly struct EdgeKey : IEquatable> { - internal struct EdgeKey : IEquatable> - { - public readonly char Key; - public readonly Edge Value; + public readonly char Key; + public readonly Edge Value; - public EdgeKey(char key, Edge value) - { - Key = key; - Value = value; - } - public bool Equals(EdgeKey other) - { - return Key == other.Key && Equals(Value, other.Value); - } + public EdgeKey(char key, Edge value) + { + Key = key; + Value = value; + } + public bool Equals(EdgeKey other) + { + return Key == other.Key && Equals(Value, other.Value); + } - public override bool Equals(object obj) - { - return obj is EdgeKey other && Equals(other); - } + public override bool Equals(object obj) + { + return obj is EdgeKey other && Equals(other); + } - public override int GetHashCode() + public override int GetHashCode() + { + unchecked { - unchecked - { - return (Key.GetHashCode() * 397) ^ (Value != null ? Value.GetHashCode() : 0); - } + return (Key.GetHashCode() * 397) ^ (Value != null ? Value.GetHashCode() : 0); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Trie/Node.cs b/Oxide.Ext.Discord/Types/Trie/Node.cs index 3fe55f852..c54597f4a 100644 --- a/Oxide.Ext.Discord/Types/Trie/Node.cs +++ b/Oxide.Ext.Discord/Types/Trie/Node.cs @@ -4,125 +4,124 @@ using System; using System.Collections.Generic; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal class Node { - internal class Node - { - public Node Suffix; + public Node Suffix; - public IReadOnlyList> Edges => _edges; + public IReadOnlyList> Edges => _edges; - private readonly List> _edges = new List>(0); - private readonly List> _data = new List>(0); - private readonly Func _equalsFunc; + private readonly List> _edges = new(0); + private readonly List> _data = new(0); + private readonly Func _equalsFunc; - public Node(Func equalsFunc) - { - _equalsFunc = equalsFunc; - } + public Node(Func equalsFunc) + { + _equalsFunc = equalsFunc; + } - public long Size() + public long Size() + { + long sum = 1; + for (int index = 0; index < _edges.Count; index++) { - long sum = 1; - for (int index = 0; index < _edges.Count; index++) - { - EdgeKey key = _edges[index]; - sum += key.Value.Node.Size(); - } - - return sum; + EdgeKey key = _edges[index]; + sum += key.Value.Node.Size(); } - /// - /// Gets the data of the whole sub-tree rooted on this node. - /// - /// - public IEnumerable> GetData() - { - for (int index = 0; index < _data.Count; index++) - { - WordKey key = _data[index]; - yield return key; - } + return sum; + } - for (int index = 0; index < _edges.Count; index++) - { - EdgeKey edgeKey = _edges[index]; - foreach (WordKey word in edgeKey.Value.Node.GetData()) - { - yield return word; - } - } + /// + /// Gets the data of the whole sub-tree rooted on this node. + /// + /// + public IEnumerable> GetData() + { + for (int index = 0; index < _data.Count; index++) + { + WordKey key = _data[index]; + yield return key; } - public void AddData(WordKey value) + for (int index = 0; index < _edges.Count; index++) { - if (_data.Contains(value)) + EdgeKey edgeKey = _edges[index]; + foreach (WordKey word in edgeKey.Value.Node.GetData()) { - return; + yield return word; } + } + } - _data.Add(value); - Suffix?.AddData(value); + public void AddData(WordKey value) + { + if (_data.Contains(value)) + { + return; } + + _data.Add(value); + Suffix?.AddData(value); + } - public void Remove(StringSlice slice, T value) + public void Remove(StringSlice slice, T value) + { + for (int index = _data.Count - 1; index >= 0; index--) { - for (int index = _data.Count - 1; index >= 0; index--) + WordKey key = _data[index]; + if (key.Key == slice.Original && _equalsFunc(key.Value, value)) { - WordKey key = _data[index]; - if (key.Key == slice.Original && _equalsFunc(key.Value, value)) - { - _data.RemoveAt(index); - } + _data.RemoveAt(index); } } + } - public void AddEdge(char ch, Edge edge) + public void AddEdge(char ch, Edge edge) + { + int index = IndexOf(ch); + if (index < 0) { - int index = IndexOf(ch); - if (index < 0) - { - _edges.Insert(~index, new EdgeKey(ch, edge)); - } - else - { - _edges[index] = new EdgeKey(ch, edge); - } + _edges.Insert(~index, new EdgeKey(ch, edge)); } - - public Edge GetEdge(char ch) + else { - int index = IndexOf(ch); - return index < 0 ? null : _edges[index].Value; + _edges[index] = new EdgeKey(ch, edge); } + } - // Perform binary search to find the place of this character - private int IndexOf(char ch) + public Edge GetEdge(char ch) + { + int index = IndexOf(ch); + return index < 0 ? null : _edges[index].Value; + } + + // Perform binary search to find the place of this character + private int IndexOf(char ch) + { + int min = 0; + int max = _edges.Count - 1; + while (min <= max) { - int min = 0; - int max = _edges.Count - 1; - while (min <= max) + int mid = min + (max - min) / 2; + char midTerm = _edges[mid].Key; + + if (ch < midTerm) { - int mid = min + (max - min) / 2; - char midTerm = _edges[mid].Key; - - if (ch < midTerm) - { - max = mid - 1; - } - else if (ch > midTerm) - { - min = mid + 1; - } - else - { - return mid; - } + max = mid - 1; + } + else if (ch > midTerm) + { + min = mid + 1; + } + else + { + return mid; } - - return ~min; } + + return ~min; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Trie/SplitResult.cs b/Oxide.Ext.Discord/Types/Trie/SplitResult.cs index fffa46a92..41222a326 100644 --- a/Oxide.Ext.Discord/Types/Trie/SplitResult.cs +++ b/Oxide.Ext.Discord/Types/Trie/SplitResult.cs @@ -1,17 +1,16 @@ // Originally from: https://github.com/gmamaladze/trienet // Modified by: MJSU -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +internal struct SplitResult { - internal struct SplitResult - { - public readonly Node Node; - public readonly bool Endpoint; + public readonly Node Node; + public readonly bool Endpoint; - public SplitResult(Node node, bool endpoint) - { - Node = node; - Endpoint = endpoint; - } + public SplitResult(Node node, bool endpoint) + { + Node = node; + Endpoint = endpoint; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Trie/StringSlice.cs b/Oxide.Ext.Discord/Types/Trie/StringSlice.cs index 691bba380..a09d0cde2 100644 --- a/Oxide.Ext.Discord/Types/Trie/StringSlice.cs +++ b/Oxide.Ext.Discord/Types/Trie/StringSlice.cs @@ -4,95 +4,94 @@ using System; using System.Diagnostics; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +[Serializable] +[DebuggerDisplay("{ToString()}")] +internal struct StringSlice : IEquatable { - [Serializable] - [DebuggerDisplay("{ToString()}")] - internal struct StringSlice : IEquatable + public readonly string Original; + private ushort _startIndex; + private ushort _endIndex; + + public int StartIndex { - public readonly string Original; - private ushort _startIndex; - private ushort _endIndex; + set => _startIndex = (ushort)Math.Max(0, Math.Min(value, _endIndex)); + get => _startIndex; + } - public int StartIndex - { - set => _startIndex = (ushort)Math.Max(0, Math.Min(value, _endIndex)); - get => _startIndex; - } + public int EndIndex + { + set => _endIndex = (ushort)Math.Max(StartIndex, Math.Min(value, Original.Length)); + get => _endIndex; + } - public int EndIndex - { - set => _endIndex = (ushort)Math.Max(StartIndex, Math.Min(value, Original.Length)); - get => _endIndex; - } + public int Length => _endIndex - _startIndex; - public int Length => _endIndex - _startIndex; + public StringSlice(string original) : this(original, 0, original.Length) {} - public StringSlice(string original) : this(original, 0, original.Length) {} + public StringSlice(string original, int startIndex) : this(original, startIndex, original.Length - startIndex) {} - public StringSlice(string original, int startIndex) : this(original, startIndex, original.Length - startIndex) {} + public StringSlice(string original, int startIndex, int length) + { + if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), "The value must be non negative."); + if (length < 0) throw new ArgumentOutOfRangeException(nameof(length), "The value must be non negative."); + Original = original; + _startIndex = (ushort)startIndex; + _endIndex = (ushort)Math.Min(original.Length, startIndex + length); + } - public StringSlice(string original, int startIndex, int length) - { - if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), "The value must be non negative."); - if (length < 0) throw new ArgumentOutOfRangeException(nameof(length), "The value must be non negative."); - Original = original; - _startIndex = (ushort)startIndex; - _endIndex = (ushort)Math.Min(original.Length, startIndex + length); - } + public char this[int index] => char.ToLower(Original[_startIndex + index]); - public char this[int index] => char.ToLower(Original[_startIndex + index]); + public bool Equals(StringSlice other) + { + return Original.Equals(other.Original, StringComparison.OrdinalIgnoreCase) + && _endIndex == other._endIndex + && _startIndex == other._startIndex; + } - public bool Equals(StringSlice other) - { - return Original.Equals(other.Original, StringComparison.OrdinalIgnoreCase) - && _endIndex == other._endIndex - && _startIndex == other._startIndex; - } + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is StringSlice sli && Equals(sli); + } - public override bool Equals(object obj) + public override int GetHashCode() + { + unchecked { - if (ReferenceEquals(null, obj)) return false; - return obj is StringSlice sli && Equals(sli); + int hashCode = StringComparer.OrdinalIgnoreCase.GetHashCode(Original); + hashCode = (hashCode * 397) ^ _endIndex; + hashCode = (hashCode * 397) ^ _startIndex; + return hashCode; } + } - public override int GetHashCode() + public StringSlice Slice(int startIndex) => Slice(startIndex, Length - startIndex); + public StringSlice Slice(int startIndex, int count) => new(Original, _startIndex + startIndex, Math.Min(count, Length - startIndex)); + + public bool StartsWith(StringSlice other) + { + if (Length < other.Length) { - unchecked - { - int hashCode = StringComparer.OrdinalIgnoreCase.GetHashCode(Original); - hashCode = (hashCode * 397) ^ _endIndex; - hashCode = (hashCode * 397) ^ _startIndex; - return hashCode; - } + return false; } - public StringSlice Slice(int startIndex) => Slice(startIndex, Length - startIndex); - public StringSlice Slice(int startIndex, int count) => new StringSlice(Original, _startIndex + startIndex, Math.Min(count, Length - startIndex)); - - public bool StartsWith(StringSlice other) + for (int i = 0; i < other.Length; i++) { - if (Length < other.Length) + if (char.ToUpperInvariant(this[i]) != char.ToUpperInvariant(other[i])) { return false; } - - for (int i = 0; i < other.Length; i++) - { - if (char.ToUpperInvariant(this[i]) != char.ToUpperInvariant(other[i])) - { - return false; - } - } - - return true; } - public StringSlice SliceLastChar() => Length == 0 ? this : Slice(0, Length - 1); + return true; + } + + public StringSlice SliceLastChar() => Length == 0 ? this : Slice(0, Length - 1); - public static bool operator ==(StringSlice left, StringSlice right) => left.Equals(right); - public static bool operator !=(StringSlice left, StringSlice right) => !(left == right); + public static bool operator ==(StringSlice left, StringSlice right) => left.Equals(right); + public static bool operator !=(StringSlice left, StringSlice right) => !(left == right); - public override string ToString() => Original.Substring(_startIndex, Length); - } + public override string ToString() => Original.Substring(_startIndex, Length); } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Trie/UkkonenTrie.cs b/Oxide.Ext.Discord/Types/Trie/UkkonenTrie.cs index 7fcfc8117..f0a4c8a6b 100644 --- a/Oxide.Ext.Discord/Types/Trie/UkkonenTrie.cs +++ b/Oxide.Ext.Discord/Types/Trie/UkkonenTrie.cs @@ -3,327 +3,325 @@ using System; using System.Collections.Generic; -using System.Linq; using Oxide.Ext.Discord.Libraries; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +/// +/// A Ukkonen Suffix Trie +/// +/// Type to store in the Trie +public class UkkonenTrie { + //The root of the suffix tree + private readonly Node _root; + private readonly Func _equalsFunc; + + /// + /// Constructor + /// + public UkkonenTrie() : this((left, right) => left.Equals(right)) { } + /// - /// A Ukkonen Suffix Trie + /// Constructor /// - /// Type to store in the Trie - public class UkkonenTrie + /// Function to match values when removing + public UkkonenTrie(Func equalsFunc) { - //The root of the suffix tree - private readonly Node _root; - private readonly Func _equalsFunc; - - /// - /// Constructor - /// - public UkkonenTrie() : this((left, right) => left.Equals(right)) { } - - /// - /// Constructor - /// - /// Function to match values when removing - public UkkonenTrie(Func equalsFunc) - { - _equalsFunc = equalsFunc; - _root = new Node(_equalsFunc); - } + _equalsFunc = equalsFunc; + _root = new Node(_equalsFunc); + } - /// - /// Size of the Trie - /// - public long Size => _root.Size(); - - /// - /// Search the trie for search value - /// - /// Text to search for - /// of matches - public IEnumerable Search(string search) + /// + /// Size of the Trie + /// + public long Size => _root.Size(); + + /// + /// Search the trie for search value + /// + /// Text to search for + /// of matches + public IEnumerable Search(string search) + { + HashSet matches = DiscordPool.Internal.GetHashSet(); + foreach (WordKey word in RetrieveSubstrings(search)) { - HashSet matches = DiscordPool.Internal.GetHashSet(); - foreach (WordKey word in RetrieveSubstrings(search)) + T value = word.Value; + if (matches.Add(value)) { - T value = word.Value; - if (matches.Add(value)) - { - yield return value; - } + yield return value; } + } - DiscordPool.Internal.FreeHashSet(matches); + DiscordPool.Internal.FreeHashSet(matches); + } + + private IEnumerable> RetrieveSubstrings(string word) + { + if (string.IsNullOrEmpty(word)) + { + return _root.GetData(); } - private IEnumerable> RetrieveSubstrings(string word) + StringSlice slice = new(word); + Node node = SearchNode(slice); + if (node == null) { - if (string.IsNullOrEmpty(word)) - { - return _root.GetData(); - } + return []; + } - StringSlice slice = new StringSlice(word); - Node node = SearchNode(slice); - if (node == null) - { - return Enumerable.Empty>(); - } + return node.GetData(); + } + + /// + /// Add a new record into the trie + /// + /// Key for the record + /// Value to be added + public void Add(string key, T value) + { + StringSlice keySlice = new(key); + AddState inputState = new(_root, _root, keySlice.Slice(0, 0), 0); + int size = key.Length; + // iterate over the string, one char at a time + for (int i = 0; i < size; i++) + { + inputState.Text.EndIndex += 1; - return node.GetData(); + //update the tree with the new transitions due to this new char + inputState = Update(inputState, keySlice.Slice(i), value); + //make sure the active state is canonical + inputState = GetFurthestNode(inputState); } - /// - /// Add a new record into the trie - /// - /// Key for the record - /// Value to be added - public void Add(string key, T value) + // add leaf suffix link, is necessary + if (inputState.Leaf.Suffix == null && inputState.Leaf != _root && inputState.Leaf != inputState.Node) { - StringSlice keySlice = new StringSlice(key); - AddState inputState = new AddState(_root, _root, keySlice.Slice(0, 0), 0); - int size = key.Length; - // iterate over the string, one char at a time - for (int i = 0; i < size; i++) - { - inputState.Text.EndIndex += 1; + inputState.Leaf.Suffix = inputState.Node; + } + } - //update the tree with the new transitions due to this new char - inputState = Update(inputState, keySlice.Slice(i), value); - //make sure the active state is canonical - inputState = GetFurthestNode(inputState); - } + /// + /// Removes a record from the trie + /// + /// Key for the record + /// Value of the record + public void Remove(string key, T value) + { + StringSlice keySlice = new(key); + StringSlice slice = keySlice.Slice(0, 0); + int size = key.Length; - // add leaf suffix link, is necessary - if (inputState.Leaf.Suffix == null && inputState.Leaf != _root && inputState.Leaf != inputState.Node) - { - inputState.Leaf.Suffix = inputState.Node; - } + for (int i = 0; i < size; i++) + { + slice.EndIndex += 1; + Node node = SearchNode(slice); + node?.Remove(slice, value); } + } - /// - /// Removes a record from the trie - /// - /// Key for the record - /// Value of the record - public void Remove(string key, T value) + private static bool RegionMatches(StringSlice first, int firstOffset, StringSlice second, int secondOffset, int length) + { + for (int i = 0; i < length; i++) { - StringSlice keySlice = new StringSlice(key); - StringSlice slice = keySlice.Slice(0, 0); - int size = key.Length; - - for (int i = 0; i < size; i++) + if (first[firstOffset + i] != second[secondOffset + i]) { - slice.EndIndex += 1; - Node node = SearchNode(slice); - node?.Remove(slice, value); + return false; } } - private static bool RegionMatches(StringSlice first, int firstOffset, StringSlice second, int secondOffset, int length) + return true; + } + + private Node SearchNode(StringSlice word) + { + Node currentNode = _root; + + for (int i = 0; i < word.Length; i++) { - for (int i = 0; i < length; i++) + char character = word[i]; + // follow the EdgeA corresponding to this char + Edge currentEdge = currentNode.GetEdge(character); + if (currentEdge == null) { - if (first[firstOffset + i] != second[secondOffset + i]) - { - return false; - } + // there is no Edge starting with this char + return null; } + + StringSlice label = currentEdge.Label; + int lenToMatch = Math.Min(word.Length - i, label.Length); - return true; - } - - private Node SearchNode(StringSlice word) - { - Node currentNode = _root; - - for (int i = 0; i < word.Length; i++) + if (!RegionMatches(word, i, label, 0, lenToMatch)) { - char character = word[i]; - // follow the EdgeA corresponding to this char - Edge currentEdge = currentNode.GetEdge(character); - if (currentEdge == null) - { - // there is no Edge starting with this char - return null; - } - - StringSlice label = currentEdge.Label; - int lenToMatch = Math.Min(word.Length - i, label.Length); - - if (!RegionMatches(word, i, label, 0, lenToMatch)) - { - // the label on the Edge does not correspond to the one in the string to search - return null; - } - - if (label.Length >= word.Length - i) - { - return currentEdge.Node; - } - - // advance to next Node - currentNode = currentEdge.Node; - i += lenToMatch - 1; + // the label on the Edge does not correspond to the one in the string to search + return null; } - return null; + if (label.Length >= word.Length - i) + { + return currentEdge.Node; + } + + // advance to next Node + currentNode = currentEdge.Node; + i += lenToMatch - 1; } + + return null; + } - private SplitResult TestAndSplit(AddState input, char character, StringSlice remainder, T value) + private SplitResult TestAndSplit(AddState input, char character, StringSlice remainder, T value) + { + // descend the tree as far as possible + input = GetFurthestNode(input); + + if (input.Text.Length > 0) { - // descend the tree as far as possible - input = GetFurthestNode(input); + Edge nodeEdge = input.Node.GetEdge(input.Text[0]); - if (input.Text.Length > 0) + StringSlice label = nodeEdge.Label; + // must see whether string is substring of the label of an Edge + if (label.Length > input.Text.Length && label[input.Text.Length].Equals(character)) { - Edge nodeEdge = input.Node.GetEdge(input.Text[0]); - - StringSlice label = nodeEdge.Label; - // must see whether string is substring of the label of an Edge - if (label.Length > input.Text.Length && label[input.Text.Length].Equals(character)) - { - return new SplitResult(input.Node, true); - } + return new SplitResult(input.Node, true); + } - // need to split the Edge - StringSlice remainingSlice = label.Slice(input.Text.Length); + // need to split the Edge + StringSlice remainingSlice = label.Slice(input.Text.Length); - // build a new EdgeA - nodeEdge.Label = remainingSlice; + // build a new EdgeA + nodeEdge.Label = remainingSlice; - // build a new Node - Node n = new Node(_equalsFunc); - n.AddEdge(remainingSlice[0], nodeEdge); - input.Node.AddEdge(input.Text[0], new Edge(input.Text, n)); + // build a new Node + Node n = new(_equalsFunc); + n.AddEdge(remainingSlice[0], nodeEdge); + input.Node.AddEdge(input.Text[0], new Edge(input.Text, n)); - return new SplitResult(n, false); - } + return new SplitResult(n, false); + } - Edge edge = input.Node.GetEdge(character); - if (edge == null) - { - // if there is no t-transtion from s - return new SplitResult(input.Node, false); - } + Edge edge = input.Node.GetEdge(character); + if (edge == null) + { + // if there is no t-transtion from s + return new SplitResult(input.Node, false); + } - StringSlice edgeLabel = edge.Label; - if (remainder == edgeLabel) - { - // update payload of destination Node - edge.Node.AddData(new WordKey(input.Text.Original, value)); - return new SplitResult(input.Node, true); - } + StringSlice edgeLabel = edge.Label; + if (remainder == edgeLabel) + { + // update payload of destination Node + edge.Node.AddData(new WordKey(input.Text.Original, value)); + return new SplitResult(input.Node, true); + } - if (remainder.StartsWith(edgeLabel) || !edgeLabel.StartsWith(remainder)) - { - return new SplitResult(input.Node, true); - } + if (remainder.StartsWith(edgeLabel) || !edgeLabel.StartsWith(remainder)) + { + return new SplitResult(input.Node, true); + } - // need to split as above - Node newNode = new Node(_equalsFunc); - newNode.AddData(new WordKey(input.Text.Original, value)); + // need to split as above + Node newNode = new(_equalsFunc); + newNode.AddData(new WordKey(input.Text.Original, value)); - edge.Label = edge.Label.Slice(remainder.Length); - newNode.AddEdge(edge.Label[0], edge); - input.Node.AddEdge(character, new Edge(remainder, newNode)); - return new SplitResult(input.Node, false); - // they are different words. No prefix. but they may still share some common substr - } + edge.Label = edge.Label.Slice(remainder.Length); + newNode.AddEdge(edge.Label[0], edge); + input.Node.AddEdge(character, new Edge(remainder, newNode)); + return new SplitResult(input.Node, false); + // they are different words. No prefix. but they may still share some common substr + } - private static AddState GetFurthestNode(AddState input) + private static AddState GetFurthestNode(AddState input) + { + if (input.Text.Length == 0) { - if (input.Text.Length == 0) - { - return input; - } + return input; + } - Edge edge = input.Node.GetEdge(input.Text[0]); - // descend the tree as long as a proper label is found - while (edge != null && input.Text.Length >= edge.Label.Length && input.Text.StartsWith(edge.Label)) + Edge edge = input.Node.GetEdge(input.Text[0]); + // descend the tree as long as a proper label is found + while (edge != null && input.Text.Length >= edge.Label.Length && input.Text.StartsWith(edge.Label)) + { + input.Text.StartIndex += edge.Label.Length; + input.Offset += edge.Label.Length; + input.Node = edge.Node; + if (input.Text.Length > 0) { - input.Text.StartIndex += edge.Label.Length; - input.Offset += edge.Label.Length; - input.Node = edge.Node; - if (input.Text.Length > 0) - { - edge = input.Node.GetEdge(input.Text[0]); - } + edge = input.Node.GetEdge(input.Text[0]); } - - return input; } + + return input; + } - private AddState Update(AddState input, StringSlice rest, T value) - { - char newChar = input.Text[input.Text.Length - 1]; + private AddState Update(AddState input, StringSlice rest, T value) + { + char newChar = input.Text[input.Text.Length - 1]; + + // line 1 + Node oldRoot = _root; - // line 1 - Node oldRoot = _root; + // line 1b + SplitResult result = TestAndSplit(input.SliceLastChar(), newChar, rest, value); - // line 1b - SplitResult result = TestAndSplit(input.SliceLastChar(), newChar, rest, value); + // line 2 + while (!result.Endpoint) + { + // line 3 + Edge edge = result.Node.GetEdge(newChar); + Node leaf; + if (edge != null) + { + // such a Node is already present. This is one of the main differences from Ukkonen's case: + // the tree can contain deeper nodes at this stage because different strings were added by previous iterations. + leaf = edge.Node; + } + else + { + // must build a new leaf + leaf = new Node(_equalsFunc); + leaf.AddData(new WordKey(input.Text.Original, value)); + result.Node.AddEdge(newChar, new Edge(rest, leaf)); + } - // line 2 - while (!result.Endpoint) + // update suffix link for newly created leaf + if (input.Leaf != _root) { - // line 3 - Edge edge = result.Node.GetEdge(newChar); - Node leaf; - if (edge != null) - { - // such a Node is already present. This is one of the main differences from Ukkonen's case: - // the tree can contain deeper nodes at this stage because different strings were added by previous iterations. - leaf = edge.Node; - } - else - { - // must build a new leaf - leaf = new Node(_equalsFunc); - leaf.AddData(new WordKey(input.Text.Original, value)); - result.Node.AddEdge(newChar, new Edge(rest, leaf)); - } - - // update suffix link for newly created leaf - if (input.Leaf != _root) - { - input.Leaf.Suffix = leaf; - } - - input.Leaf = leaf; - - if (oldRoot != _root) - { - oldRoot.Suffix = result.Node; - } + input.Leaf.Suffix = leaf; + } + + input.Leaf = leaf; - oldRoot = result.Node; + if (oldRoot != _root) + { + oldRoot.Suffix = result.Node; + } - if (input.Node.Suffix == null) - { - // root Node - // this is a special case to handle what is referred to as Node _|_ on the paper - input.Text = input.Text.Slice(1); - } - else - { - input.Text.EndIndex -= 1; - input = GetFurthestNode(input.TraverseNodeLevel()); - input.Text.EndIndex += 1; - } + oldRoot = result.Node; - result = TestAndSplit(input.SliceLastChar(), newChar, rest, value); + if (input.Node.Suffix == null) + { + // root Node + // this is a special case to handle what is referred to as Node _|_ on the paper + input.Text = input.Text.Slice(1); } - - if (oldRoot != _root) + else { - oldRoot.Suffix = result.Node; + input.Text.EndIndex -= 1; + input = GetFurthestNode(input.TraverseNodeLevel()); + input.Text.EndIndex += 1; } - - return input; + + result = TestAndSplit(input.SliceLastChar(), newChar, rest, value); } + + if (oldRoot != _root) + { + oldRoot.Suffix = result.Node; + } + + return input; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/Trie/WordKey.cs b/Oxide.Ext.Discord/Types/Trie/WordKey.cs index edbe910c8..d41c847af 100644 --- a/Oxide.Ext.Discord/Types/Trie/WordKey.cs +++ b/Oxide.Ext.Discord/Types/Trie/WordKey.cs @@ -5,38 +5,37 @@ using System.Collections.Generic; using System.Diagnostics; -namespace Oxide.Ext.Discord.Types +namespace Oxide.Ext.Discord.Types; + +[DebuggerDisplay("{DebuggerDisplay()}")] +internal readonly struct WordKey : IEquatable> { - [DebuggerDisplay("{DebuggerDisplay()}")] - internal struct WordKey : IEquatable> - { - public readonly string Key; - public readonly T Value; + public readonly string Key; + public readonly T Value; - public WordKey(string key, T value) - { - Key = key; - Value = value; - } + public WordKey(string key, T value) + { + Key = key; + Value = value; + } - public string DebuggerDisplay() => $"{Key}: {Value}"; + public string DebuggerDisplay() => $"{Key}: {Value}"; - public bool Equals(WordKey other) - { - return Key == other.Key && EqualityComparer.Default.Equals(Value, other.Value); - } + public bool Equals(WordKey other) + { + return Key == other.Key && EqualityComparer.Default.Equals(Value, other.Value); + } - public override bool Equals(object obj) - { - return obj is WordKey other && Equals(other); - } + public override bool Equals(object obj) + { + return obj is WordKey other && Equals(other); + } - public override int GetHashCode() + public override int GetHashCode() + { + unchecked { - unchecked - { - return ((Key != null ? Key.GetHashCode() : 0) * 397) ^ EqualityComparer.Default.GetHashCode(Value); - } + return ((Key != null ? Key.GetHashCode() : 0) * 397) ^ EqualityComparer.Default.GetHashCode(Value); } } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/Types/ValueStringBuilder.cs b/Oxide.Ext.Discord/Types/ValueStringBuilder.cs new file mode 100644 index 000000000..8f3e8fe53 --- /dev/null +++ b/Oxide.Ext.Discord/Types/ValueStringBuilder.cs @@ -0,0 +1,410 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Oxide.Ext.Discord.Types; + +public ref struct ValueStringBuilder +{ + private char[] _arrayToReturnToPool; + private Span _chars; + private int _pos; + + public ValueStringBuilder(Span initialBuffer) + { + _arrayToReturnToPool = null; + _chars = initialBuffer; + _pos = 0; + } + + public ValueStringBuilder(int initialCapacity) + { + _arrayToReturnToPool = System.Buffers.ArrayPool.Shared.Rent(initialCapacity); + _chars = _arrayToReturnToPool; + _pos = 0; + } + + public int Length + { + get => _pos; + set + { + Debug.Assert(value >= 0); + Debug.Assert(value <= _chars.Length); + _pos = value; + } + } + + public int Capacity => _chars.Length; + + public void EnsureCapacity(int capacity) + { + // This is not expected to be called this with negative capacity + Debug.Assert(capacity >= 0); + + // If the caller has a bug and calls this with negative capacity, make sure to call Grow to throw an exception. + if ((uint)capacity > (uint)_chars.Length) + Grow(capacity - _pos); + } + + /// + /// Get a pinnable reference to the builder. + /// Does not ensure there is a null char after + /// This overload is pattern matched in the C# 7.3+ compiler so you can omit + /// the explicit method call, and write eg "fixed (char* c = builder)" + /// + public ref char GetPinnableReference() + { + return ref MemoryMarshal.GetReference(_chars); + } + + /// + /// Get a pinnable reference to the builder. + /// + /// Ensures that the builder has a null char after + public ref char GetPinnableReference(bool terminate) + { + if (terminate) + { + EnsureCapacity(Length + 1); + _chars[Length] = '\0'; + } + return ref MemoryMarshal.GetReference(_chars); + } + + public ref char this[int index] + { + get + { + Debug.Assert(index < _pos); + return ref _chars[index]; + } + } + + public override string ToString() + { + string s = _chars.Slice(0, _pos).ToString(); + Dispose(); + return s; + } + + /// Returns the underlying storage of the builder. + public Span RawChars => _chars; + + /// + /// Returns a span around the contents of the builder. + /// + /// Ensures that the builder has a null char after + public ReadOnlySpan AsSpan(bool terminate) + { + if (terminate) + { + EnsureCapacity(Length + 1); + _chars[Length] = '\0'; + } + return _chars.Slice(0, _pos); + } + + public ReadOnlySpan AsSpan() => _chars.Slice(0, _pos); + public ReadOnlySpan AsSpan(int start) => _chars.Slice(start, _pos - start); + public ReadOnlySpan AsSpan(int start, int length) => _chars.Slice(start, length); + + public bool TryCopyTo(Span destination, out int charsWritten) + { + if (_chars.Slice(0, _pos).TryCopyTo(destination)) + { + charsWritten = _pos; + Dispose(); + return true; + } + + charsWritten = 0; + Dispose(); + return false; + } + + public void Insert(int index, char value, int count) + { + if (_pos > _chars.Length - count) + { + Grow(count); + } + + int remaining = _pos - index; + _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count)); + _chars.Slice(index, count).Fill(value); + _pos += count; + } + + public void Insert(int index, string s) + { + if (s == null) + { + return; + } + + int count = s.Length; + + if (_pos > (_chars.Length - count)) + { + Grow(count); + } + + int remaining = _pos - index; + _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count)); + s.AsSpan().CopyTo(_chars.Slice(index)); + _pos += count; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Append(char c) + { + int pos = _pos; + Span chars = _chars; + if ((uint)pos < (uint)chars.Length) + { + chars[pos] = c; + _pos = pos + 1; + } + else + { + GrowAndAppend(c); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Append(string s) + { + if (s == null) + { + return; + } + + int pos = _pos; + if (s.Length == 1 && (uint)pos < (uint)_chars.Length) // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc. + { + _chars[pos] = s[0]; + _pos = pos + 1; + } + else + { + AppendSlow(s); + } + } + + private void AppendSlow(string s) + { + int pos = _pos; + if (pos > _chars.Length - s.Length) + { + Grow(s.Length); + } + + s.AsSpan().CopyTo(_chars.Slice(pos)); + _pos += s.Length; + } + + public void Append(char c, int count) + { + if (_pos > _chars.Length - count) + { + Grow(count); + } + + Span dst = _chars.Slice(_pos, count); + for (int i = 0; i < dst.Length; i++) + { + dst[i] = c; + } + _pos += count; + } + + public void Append(scoped ReadOnlySpan value) + { + int pos = _pos; + if (pos > _chars.Length - value.Length) + { + Grow(value.Length); + } + + value.CopyTo(_chars.Slice(_pos)); + _pos += value.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AppendSpan(int length) + { + int origPos = _pos; + if (origPos > _chars.Length - length) + { + Grow(length); + } + + _pos = origPos + length; + return _chars.Slice(origPos, length); + } + + public void Append(byte value, string format = null, IFormatProvider provider = null) + { + if (value.TryFormat(_chars.Slice(_pos), out int charsWritten, format, provider)) + { + _pos += charsWritten; + } + else + { + Append(value.ToString(format, provider)); + } + } + + public void Append(sbyte value, string format = null, IFormatProvider provider = null) + { + if (value.TryFormat(_chars.Slice(_pos), out int charsWritten, format, provider)) + { + _pos += charsWritten; + } + else + { + Append(value.ToString(format, provider)); + } + } + + public void Append(short value, string format = null, IFormatProvider provider = null) + { + if (value.TryFormat(_chars.Slice(_pos), out int charsWritten, format, provider)) + { + _pos += charsWritten; + } + else + { + Append(value.ToString(format, provider)); + } + } + + public void Append(ushort value, string format = null, IFormatProvider provider = null) + { + if (value.TryFormat(_chars.Slice(_pos), out int charsWritten, format, provider)) + { + _pos += charsWritten; + } + else + { + Append(value.ToString(format, provider)); + } + } + + public void Append(int value, string format = null, IFormatProvider provider = null) + { + if (value.TryFormat(_chars.Slice(_pos), out int charsWritten, format, provider)) + { + _pos += charsWritten; + } + else + { + Append(value.ToString(format, provider)); + } + } + + public void Append(uint value, string format = null, IFormatProvider provider = null) + { + if (value.TryFormat(_chars.Slice(_pos), out int charsWritten, format, provider)) + { + _pos += charsWritten; + } + else + { + Append(value.ToString(format, provider)); + } + } + + public void Append(long value, string format = null, IFormatProvider provider = null) + { + if (value.TryFormat(_chars.Slice(_pos), out int charsWritten, format, provider)) + { + _pos += charsWritten; + } + else + { + Append(value.ToString(format, provider)); + } + } + + public void Append(ulong value, string format = null, IFormatProvider provider = null) + { + if (value.TryFormat(_chars.Slice(_pos), out int charsWritten, format, provider)) + { + _pos += charsWritten; + } + else + { + Append(value.ToString(format, provider)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AppendLine(string s) + { + Append(s); + AppendLine(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AppendLine() => Append(Environment.NewLine); + + [MethodImpl(MethodImplOptions.NoInlining)] + private void GrowAndAppend(char c) + { + Grow(1); + Append(c); + } + + /// + /// Resize the internal buffer either by doubling current buffer size or + /// by adding to + /// whichever is greater. + /// + /// + /// Number of chars requested beyond current position. + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private void Grow(int additionalCapacityBeyondPos) + { + Debug.Assert(additionalCapacityBeyondPos > 0); + Debug.Assert(_pos > _chars.Length - additionalCapacityBeyondPos, "Grow called incorrectly, no resize is needed."); + + const uint ArrayMaxLength = 0x7FFFFFC7; // same as Array.MaxLength + + // Increase to at least the required size (_pos + additionalCapacityBeyondPos), but try + // to double the size if possible, bounding the doubling to not go beyond the max array length. + int newCapacity = (int)Math.Max( + (uint)(_pos + additionalCapacityBeyondPos), + Math.Min((uint)_chars.Length * 2, ArrayMaxLength)); + + // Make sure to let Rent throw an exception if the caller has a bug and the desired capacity is negative. + // This could also go negative if the actual required length wraps around. + char[] poolArray = System.Buffers.ArrayPool.Shared.Rent(newCapacity); + + _chars.Slice(0, _pos).CopyTo(poolArray); + + char[] toReturn = _arrayToReturnToPool; + _chars = _arrayToReturnToPool = poolArray; + if (toReturn != null) + { + System.Buffers.ArrayPool.Shared.Return(toReturn); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + char[] toReturn = _arrayToReturnToPool; + this = default; // for safety, to avoid using pooled array if this instance is erroneously appended to again + if (toReturn != null) + { + System.Buffers.ArrayPool.Shared.Return(toReturn); + } + } +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/DiscordWebSocket.cs b/Oxide.Ext.Discord/WebSockets/DiscordWebSocket.cs index 5ef53ee0b..36b0ad0f5 100644 --- a/Oxide.Ext.Discord/WebSockets/DiscordWebSocket.cs +++ b/Oxide.Ext.Discord/WebSockets/DiscordWebSocket.cs @@ -9,393 +9,390 @@ using Oxide.Ext.Discord.Libraries; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +/// +/// Represents a websocket that connects to discord +/// +public class DiscordWebSocket : IDebugLoggable { /// - /// Represents a websocket that connects to discord + /// The current session ID for the connected bot /// - public class DiscordWebSocket : IDebugLoggable - { - /// - /// The current session ID for the connected bot - /// - private string _sessionId; - - /// - /// The URL to use when resuming a session - /// - private string _resumeSessionUrl; + private string _sessionId; + + /// + /// The URL to use when resuming a session + /// + private string _resumeSessionUrl; - /// - /// If we should attempt to reconnect to discord on disconnect - /// - public bool ShouldReconnect; + /// + /// If we should attempt to reconnect to discord on disconnect + /// + public bool ShouldReconnect; - /// - /// If we should attempt to resume our previous session after connecting - /// - public bool ShouldResume; - - /// - /// The current sequence number for the websocket - /// - private int _sequence; - - /// - /// If the bot has successfully connected to the websocket at least once - /// - public bool SocketHasConnected { get; private set; } - - internal GatewayIntents Intents { get; private set; } - - private readonly BotClient _client; - internal readonly WebSocketHandler Handler; - private readonly WebSocketEventHandler _listener; - private readonly WebSocketCommandHandler _commands; - private readonly DiscordHeartbeatHandler _heartbeat; - private readonly WebSocketReconnectHandler _reconnect; - private readonly ILogger _logger; - - private bool _isShutdown; - - /// - /// Socket used by the BotClient - /// - /// Client using the socket - /// Logger for the bot client - public DiscordWebSocket(BotClient client, ILogger logger) - { - _client = client; - _logger = logger; - - _reconnect = new WebSocketReconnectHandler(client, this, logger); - _commands = new WebSocketCommandHandler(client, this, logger); - _heartbeat = new DiscordHeartbeatHandler(client, this, logger); - _listener = new WebSocketEventHandler(client, this, logger); - Handler = new WebSocketHandler(_listener, logger); - } - - /// - /// Connect to the websocket - /// - /// Thrown if the socket still exists. Must call disconnect before trying to connect - public void Connect() - { - _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Connect)} Start websocket connection"); - string url = Gateway.WebsocketUrl; - if (ShouldResume && !string.IsNullOrEmpty(_resumeSessionUrl)) - { - url = _resumeSessionUrl; - } - - //We haven't gotten the websocket url. Get url then attempt to connect. - //There has been more than 3 tries to reconnect. Discord suggests trying to update gateway url. - if (string.IsNullOrEmpty(url) || (_reconnect.AttemptGatewayUpdate && Gateway.LastUpdate + TimeSpan.FromMinutes(5) <= DateTime.UtcNow)) - { - Gateway.UpdateGatewayUrl(_client) - .Then(_ => Connect()) - .Catch(OnGatewayUrlUpdateFailed); - return; - } + /// + /// If we should attempt to resume our previous session after connecting + /// + public bool ShouldResume; - ShouldReconnect = false; - ShouldResume = false; + /// + /// The current sequence number for the websocket + /// + private int _sequence; - Intents = _client.Connection.Intents; - - _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Connect)} Websocket connecting to: {{0}}", url); - Handler.Connect(url); - } + /// + /// If the bot has successfully connected to the websocket at least once + /// + public bool SocketHasConnected { get; private set; } - private void OnGatewayUrlUpdateFailed(ResponseError error) - { - _logger.Warning("Failed to update gateway url. Attempting reconnect."); - WebsocketReconnectCallback.Start(_reconnect); - } + internal GatewayIntents Intents { get; private set; } - /// - /// Disconnects the websocket from discord - /// - /// Should we attempt to reconnect to discord after disconnecting - /// Should we attempt to resume our previous session - /// If discord requested that we reconnect to discord - public async void Disconnect(bool reconnect, bool resume, bool requested = false) - { - _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Disconnect)} Disconnecting Web Socket. Socket State: {{0}} Reconnect: {{1}} Resume: {{2}} Requested {{3}}", Handler.SocketState, reconnect, resume, requested); - ShouldReconnect = reconnect; - ShouldResume = resume; - _reconnect.CancelReconnect(); + private readonly BotClient _client; + internal readonly WebSocketHandler Handler; + private readonly WebSocketEventHandler _listener; + private readonly WebSocketCommandHandler _commands; + private readonly DiscordHeartbeatHandler _heartbeat; + private readonly WebSocketReconnectHandler _reconnect; + private readonly ILogger _logger; - if (!IsDisconnected() && !IsDisconnecting()) - { - OnSocketDisconnected(); - - if (requested) - { - await Handler.Disconnect(4199, "Discord Requested Reconnect").ConfigureAwait(false); - } - else - { - await Handler.Disconnect(WebSocketCloseStatus.NormalClosure, "Normal Websocket Disconnect Requested").ConfigureAwait(false); - } - } + private bool _isShutdown; - ReconnectIfRequested(); - } + /// + /// Socket used by the BotClient + /// + /// Client using the socket + /// Logger for the bot client + public DiscordWebSocket(BotClient client, ILogger logger) + { + _client = client; + _logger = logger; + + _reconnect = new WebSocketReconnectHandler(client, this, logger); + _commands = new WebSocketCommandHandler(client, this, logger); + _heartbeat = new DiscordHeartbeatHandler(client, this, logger); + _listener = new WebSocketEventHandler(client, this, logger); + Handler = new WebSocketHandler(_listener, logger); + } - /// - /// Returns if the given websocket matches our current websocket. - /// If socket is null we return false - /// - /// ID of the socket - /// True if current socket is not null and socket matches current socket; False otherwise. - internal bool IsCurrentSocket(Snowflake webSocketId) => !Handler.WebsocketId.IsValid() || Handler.WebsocketId == webSocketId; - - /// - /// Shutdowns the websocket completely. Used when bot is being shutdown - /// - public void Shutdown() + /// + /// Connect to the websocket + /// + /// Thrown if the socket still exists. Must call disconnect before trying to connect + public void Connect() + { + _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Connect)} Start websocket connection"); + string url = Gateway.WebsocketUrl; + if (ShouldResume && !string.IsNullOrEmpty(_resumeSessionUrl)) { - _isShutdown = true; - Disconnect(false, false); - _reconnect.OnSocketShutdown(); - _heartbeat.OnSocketShutdown(); - _commands.OnSocketShutdown(); + url = _resumeSessionUrl; } - - /// - /// Send a command to discord over the websocket - /// - /// Client sending the command - /// Command code to send - /// Data to send - public void Send(DiscordClient client, GatewayCommandCode opCode, object data) + + //We haven't gotten the websocket url. Get url then attempt to connect. + //There has been more than 3 tries to reconnect. Discord suggests trying to update gateway url. + if (string.IsNullOrEmpty(url) || (_reconnect.AttemptGatewayUpdate && Gateway.LastUpdate + TimeSpan.FromMinutes(5) <= DateTime.UtcNow)) { - WebSocketCommand command = WebSocketCommand.CreateCommand(client, opCode, data); - _commands.Enqueue(command); + Gateway.UpdateGatewayUrl(_client) + .Then(_ => Connect()) + .Catch(OnGatewayUrlUpdateFailed); + return; } - - /// - /// Send a command to discord over the websocket - /// - /// Command code to send - /// Data to send - private async ValueTask SendImmediatelyAsync(GatewayCommandCode opCode, object data) + + ShouldReconnect = false; + ShouldResume = false; + + Intents = _client.Connection.Intents; + + _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Connect)} Websocket connecting to: {{0}}", url); + Handler.Connect(url); + } + + private void OnGatewayUrlUpdateFailed(ResponseError error) + { + _logger.Warning("Failed to update gateway url. Attempting reconnect."); + WebsocketReconnectCallback.Start(_reconnect); + } + + /// + /// Disconnects the websocket from discord + /// + /// Should we attempt to reconnect to discord after disconnecting + /// Should we attempt to resume our previous session + /// If discord requested that we reconnect to discord + public async void Disconnect(bool reconnect, bool resume, bool requested = false) + { + _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Disconnect)} Disconnecting Web Socket. Socket State: {{0}} Reconnect: {{1}} Resume: {{2}} Requested {{3}}", Handler.SocketState, reconnect, resume, requested); + ShouldReconnect = reconnect; + ShouldResume = resume; + _reconnect.CancelReconnect(); + + if (!IsDisconnected() && !IsDisconnecting()) { - CommandPayload payload = CommandPayload.CreatePayload(opCode, data); - if (!await SendAsync(payload).ConfigureAwait(false)) + OnSocketDisconnected(); + + if (requested) { - _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(SendImmediatelyAsync)} Failed to send command! {{0}}", opCode); + await Handler.Disconnect((int)DiscordWebsocketCloseCode.DiscordExtensionReconnect, "Discord Requested Reconnect").ConfigureAwait(false); } - payload.Dispose(); - } - - internal ValueTask SendAsync(CommandPayload payload) - { - if (Handler == null) + else { - return new ValueTask(false); + await Handler.Disconnect(WebSocketCloseStatus.NormalClosure, "Normal Websocket Disconnect Requested").ConfigureAwait(false); } + } - using (DiscordJsonWriter writer = DiscordJsonWriter.Get(DiscordPool.Internal)) - { - writer.Write(_client.JsonSerializer, payload); - writer.Stream.Position = 0; + ReconnectIfRequested(); + } - if (_client.Logger.IsLogging(DiscordLogLevel.Verbose)) - { - string json = writer.ReadAsString(); - if (payload.OpCode == GatewayCommandCode.Identify) - { - json = json.Replace(_client.Connection.ApiToken, _client.Connection.HiddenToken); - } + /// + /// Returns if the given websocket matches our current websocket. + /// If socket is null we return false + /// + /// ID of the socket + /// True if current socket is not null and socket matches current socket; False otherwise. + internal bool IsCurrentSocket(Snowflake webSocketId) => !Handler.WebsocketId.IsValid() || Handler.WebsocketId == webSocketId; - _logger.Verbose($"{nameof(DiscordWebSocket)}.{nameof(SendAsync)} Sending Payload {{0}} Body: {{1}}", payload.OpCode, json); - } + /// + /// Shutdowns the websocket completely. Used when bot is being shutdown + /// + public void Shutdown() + { + _isShutdown = true; + Disconnect(false, false); + _reconnect.OnSocketShutdown(); + _heartbeat.OnSocketShutdown(); + _commands.OnSocketShutdown(); + } - return Handler.SendAsync(writer.Stream); - } + /// + /// Send a command to discord over the websocket + /// + /// Client sending the command + /// Command code to send + /// Data to send + public void Send(DiscordClient client, GatewayCommandCode opCode, object data) + { + WebSocketCommand command = WebSocketCommand.CreateCommand(client, opCode, data); + _commands.Enqueue(command); + } + + /// + /// Send a command to discord over the websocket + /// + /// Command code to send + /// Data to send + private async ValueTask SendImmediatelyAsync(GatewayCommandCode opCode, object data) + { + CommandPayload payload = CommandPayload.CreatePayload(opCode, data); + if (!await SendAsync(payload).ConfigureAwait(false)) + { + _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(SendImmediatelyAsync)} Failed to send command! {{0}}", opCode); + } + payload.Dispose(); + } + + internal ValueTask SendAsync(CommandPayload payload) + { + if (Handler == null) + { + return new ValueTask(false); } - /// - /// Reconnected to the websocket is a reconnect is requested and we are not shutting down - /// - public void ReconnectIfRequested() + using DiscordJsonWriter writer = DiscordJsonWriter.Get(DiscordPool.Internal); + writer.Write(_client.JsonSerializer, payload); + writer.Stream.Position = 0; + + if (_client.Logger.IsLogging(DiscordLogLevel.Verbose)) { - if (ShouldReconnect && !_isShutdown) + string json = writer.ReadAsString(); + if (payload.OpCode == GatewayCommandCode.Identify) { - _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Disconnect)} Attempting Reconnect"); - ShouldReconnect = false; - WebsocketReconnectCallback.Start(_reconnect); + json = json.Replace(_client.Connection.ApiToken, _client.Connection.HiddenToken); } + + _logger.Verbose($"{nameof(DiscordWebSocket)}.{nameof(SendAsync)} Sending Payload {{0}} Body: {{1}}", payload.OpCode, json); } - internal void OnSocketConnected() + return Handler.SendAsync(writer.Stream); + } + + /// + /// Reconnected to the websocket is a reconnect is requested and we are not shutting down + /// + public void ReconnectIfRequested() + { + if (ShouldReconnect && !_isShutdown) { - _reconnect.CancelReconnect(); + _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Disconnect)} Attempting Reconnect"); + ShouldReconnect = false; + WebsocketReconnectCallback.Start(_reconnect); } + } + + internal void OnSocketConnected() + { + _reconnect.CancelReconnect(); + } - internal void OnSocketReady(GatewayReadyEvent ready) - { - _sessionId = ready.SessionId; - _resumeSessionUrl = ready.ResumeSessionUrl; - SocketHasConnected = true; - ShouldResume = true; - _reconnect.OnWebsocketReady(); - _commands.OnWebSocketReady(); - } + internal void OnSocketReady(GatewayReadyEvent ready) + { + _sessionId = ready.SessionId; + _resumeSessionUrl = ready.ResumeSessionUrl; + SocketHasConnected = true; + ShouldResume = true; + _reconnect.OnWebsocketReady(); + _commands.OnWebSocketReady(); + } + + internal void OnSocketDisconnected() + { + _commands.OnSocketDisconnected(); + } - internal void OnSocketDisconnected() + internal void OnSequenceUpdate(int? sequence) + { + if (sequence.HasValue) { - _commands.OnSocketDisconnected(); + _sequence = sequence.Value; } + } + + internal async ValueTask OnDiscordHello(GatewayHelloEvent hello) + { + _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(OnDiscordHello)}"); - internal void OnSequenceUpdate(int? sequence) + // Client should now perform identification + if (ShouldResume && !string.IsNullOrEmpty(_sessionId)) { - if (sequence.HasValue) - { - _sequence = sequence.Value; - } + await Resume().ConfigureAwait(false); } - - internal async ValueTask OnDiscordHello(GatewayHelloEvent hello) + else { - _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(OnDiscordHello)}"); - - // Client should now perform identification - if (ShouldResume && !string.IsNullOrEmpty(_sessionId)) - { - await Resume().ConfigureAwait(false); - } - else - { - await Identify().ConfigureAwait(false); - } - - _heartbeat.SetupHeartbeat(hello.HeartbeatInterval); + await Identify().ConfigureAwait(false); } + + _heartbeat.SetupHeartbeat(hello.HeartbeatInterval); + } - /// - /// Used to Identify the bot with discord - /// - internal ValueTask Identify() + /// + /// Used to Identify the bot with discord + /// + internal ValueTask Identify() + { + // Sent immediately after connecting. Opcode 2: Identify + // Ref: https://discord.com/developers/docs/topics/gateway#identifying + if (!_client.Initialized) { - // Sent immediately after connecting. Opcode 2: Identify - // Ref: https://discord.com/developers/docs/topics/gateway#identifying - if (!_client.Initialized) - { - return new ValueTask(); - } + return new ValueTask(); + } - _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Identify)} Identifying bot with discord."); + _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Identify)} Identifying bot with discord."); - IdentifyCommand identify = new IdentifyCommand - { - Token = _client.Connection.ApiToken, - Properties = Gateway.Properties, - Intents = _client.Connection.Intents, - Compress = false, - LargeThreshold = 50, - Shard = Gateway.Shard - }; - - return SendImmediatelyAsync(GatewayCommandCode.Identify, identify); - } + IdentifyCommand identify = new() + { + Token = _client.Connection.ApiToken, + Properties = Gateway.Properties, + Intents = _client.Connection.Intents, + Compress = false, + LargeThreshold = 50, + Shard = Gateway.Shard + }; + + return SendImmediatelyAsync(GatewayCommandCode.Identify, identify); + } - /// - /// Used to resume the current session with discord - /// - private ValueTask Resume() + /// + /// Used to resume the current session with discord + /// + private ValueTask Resume() + { + if (!_client.Initialized) { - if (!_client.Initialized) - { - return new ValueTask(); - } + return new ValueTask(); + } - ResumeSessionCommand resume = new ResumeSessionCommand - { - Sequence = _sequence, - SessionId = _sessionId, - Token = _client.Connection.ApiToken - }; + ResumeSessionCommand resume = new() + { + Sequence = _sequence, + SessionId = _sessionId, + Token = _client.Connection.ApiToken + }; - _sessionId = null; + _sessionId = null; - _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Resume)} Attempting to resume session with ID: {{0}} Sequence: {{1}}", _sessionId, _sequence); - return SendImmediatelyAsync(GatewayCommandCode.Resume, resume); - } + _logger.Debug($"{nameof(DiscordWebSocket)}.{nameof(Resume)} Attempting to resume session with ID: {{0}} Sequence: {{1}}", _sessionId, _sequence); + return SendImmediatelyAsync(GatewayCommandCode.Resume, resume); + } - internal void OnHeartbeatAcknowledge() - { - _heartbeat.OnHeartbeatAcknowledge(); - } + internal void OnHeartbeatAcknowledge() + { + _heartbeat.OnHeartbeatAcknowledge(); + } - /// - /// Sends a heartbeat to Discord - /// - internal ValueTask SendHeartbeat() + /// + /// Sends a heartbeat to Discord + /// + internal ValueTask SendHeartbeat() + { + if (IsConnected()) { - if (IsConnected()) - { - return SendImmediatelyAsync(GatewayCommandCode.Heartbeat, _sequence); - } - - return new ValueTask(); + return SendImmediatelyAsync(GatewayCommandCode.Heartbeat, _sequence); } + + return new ValueTask(); + } - internal void OnInvalidSession(bool resume) + internal void OnInvalidSession(bool resume) + { + bool shouldResume = !string.IsNullOrEmpty(_sessionId) && resume; + _logger.Warning("Invalid Session ID opcode received! Attempting to reconnect. Should Resume? {0}", shouldResume); + if (!resume) { - bool shouldResume = !string.IsNullOrEmpty(_sessionId) && resume; - _logger.Warning("Invalid Session ID opcode received! Attempting to reconnect. Should Resume? {0}", shouldResume); - if (!resume) - { - _sessionId = null; - } - Disconnect(true, shouldResume); + _sessionId = null; } + Disconnect(true, shouldResume); + } - internal void OnReconnectRequested() - { - _logger.Debug("Discord has requested a reconnect. Reconnecting..."); - //If we disconnect normally our session becomes invalid per: https://discord.com/developers/docs/topics/gateway#resuming - Disconnect(true, true, true); - } + internal void OnReconnectRequested() + { + _logger.Debug("Discord has requested a reconnect. Reconnecting..."); + //If we disconnect normally, our session becomes invalid per: https://discord.com/developers/docs/topics/gateway#resuming + Disconnect(true, true, true); + } - /// - /// Returns if the websocket is in the connecting state - /// - /// Returns if the websocket is in connecting state - public bool IsConnecting() => Handler.SocketState == SocketState.Connecting; - - /// - /// Returns if the websocket is in the open state - /// - /// Returns if the websocket is in open state - public bool IsConnected() => Handler.SocketState == SocketState.Connected; - - /// - /// Returns if the socket is waiting to reconnect - /// - /// Returns if the socket is waiting to reconnect - public bool IsPendingReconnect() => _reconnect.IsPendingReconnect; - - /// - /// Returns if the websocket is null or is currently closing / closed - /// - /// Returns if the websocket is null or is currently closing / closed - public bool IsDisconnecting() => Handler.SocketState == SocketState.Disconnecting; - - /// - /// Returns if the websocket is null or is currently closing / closed - /// - /// Returns if the websocket is null or is currently closing / closed - public bool IsDisconnected() => Handler.SocketState == SocketState.Disconnected; - - /// - public void LogDebug(DebugLogger logger) - { - logger.AppendFieldEnum("State", Handler.SocketState); - logger.AppendList("Pending Commands", _commands.GetPendingCommands()); - } + /// + /// Returns if the websocket is in the connecting state + /// + /// Returns if the websocket is in connecting state + public bool IsConnecting() => Handler.SocketState == SocketState.Connecting; + + /// + /// Returns if the websocket is in the open state + /// + /// Returns if the websocket is in open state + public bool IsConnected() => Handler.SocketState == SocketState.Connected; + + /// + /// Returns if the socket is waiting to reconnect + /// + /// Returns if the socket is waiting to reconnect + public bool IsPendingReconnect() => _reconnect.IsPendingReconnect; + + /// + /// Returns if the websocket is null or is currently closing / closed + /// + /// Returns if the websocket is null or is currently closing / closed + public bool IsDisconnecting() => Handler.SocketState == SocketState.Disconnecting; + + /// + /// Returns if the websocket is null or is currently closing / closed + /// + /// Returns if the websocket is null or is currently closing / closed + public bool IsDisconnected() => Handler.SocketState == SocketState.Disconnected; + + /// + public void LogDebug(DebugLogger logger) + { + logger.AppendFieldEnum("State", Handler.SocketState); + logger.AppendList("Pending Commands", _commands.GetPendingCommands()); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/DiscordWebsocketClient.cs b/Oxide.Ext.Discord/WebSockets/DiscordWebsocketClient.cs index a36989bee..1771fd922 100644 --- a/Oxide.Ext.Discord/WebSockets/DiscordWebsocketClient.cs +++ b/Oxide.Ext.Discord/WebSockets/DiscordWebsocketClient.cs @@ -7,96 +7,95 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +internal class DiscordWebsocketClient : IDisposable { - internal class DiscordWebsocketClient : IDisposable - { - public readonly Snowflake WebsocketId; - public SocketState SocketState { get; private set; } + public readonly Snowflake WebsocketId; + public SocketState SocketState { get; private set; } - public CancellationToken Token => _source.Token; - public WebSocketState WebSocketState => _socket.State; - public bool IsCancelRequested => _source.IsCancellationRequested; - public WebSocketCloseStatus? CloseStatus => _socket.CloseStatus; - public string CloseStatusDescription => _socket.CloseStatusDescription; + public CancellationToken Token => _source.Token; + public WebSocketState WebSocketState => _socket.State; + public bool IsCancelRequested => _source.IsCancellationRequested; + public WebSocketCloseStatus? CloseStatus => _socket.CloseStatus; + public string CloseStatusDescription => _socket.CloseStatusDescription; - private readonly ClientWebSocket _socket = new ClientWebSocket(); - private readonly CancellationTokenSource _source = new CancellationTokenSource(); - private readonly ILogger _logger; + private readonly ClientWebSocket _socket = new(); + private readonly CancellationTokenSource _source = new(); + private readonly ILogger _logger; - private bool _isDisposed; - private bool _socketClosed; + private bool _isDisposed; + private bool _socketClosed; - public DiscordWebsocketClient(ILogger logger) - { - _logger = logger; - WebsocketId = SnowflakeIdFactory.Instance.Generate(); - SocketState = SocketState.Connecting; - _socket.Options.KeepAliveInterval = TimeSpan.Zero; - } + public DiscordWebsocketClient(ILogger logger) + { + _logger = logger; + WebsocketId = SnowflakeIdFactory.Instance.Generate(); + SocketState = SocketState.Connecting; + _socket.Options.KeepAliveInterval = TimeSpan.Zero; + } - private void SetSocketState(SocketState state) + private void SetSocketState(SocketState state) + { + if (SocketState > state) { - if (SocketState > state) - { - throw new Exception($"Trying to set SocketState to a lower state {state} < {SocketState}"); - } - - SocketState = state; + throw new Exception($"Trying to set SocketState to a lower state {state} < {SocketState}"); } - public async ValueTask ConnectAsync(Uri uri) - { - await _socket.ConnectAsync(uri, Token).ConfigureAwait(false); - SetSocketState(SocketState.Connected); - } + SocketState = state; + } - public ValueTask ReceiveAsync(Memory buffer) => _socket.ReceiveAsync(buffer, Token); + public async ValueTask ConnectAsync(Uri uri) + { + await _socket.ConnectAsync(uri, Token).ConfigureAwait(false); + SetSocketState(SocketState.Connected); + } - public ValueTask SendAsync(Memory buffer, WebSocketMessageType messageType, bool endOfMessage) => _socket.SendAsync(buffer, messageType, endOfMessage, Token); + public ValueTask ReceiveAsync(Memory buffer) => _socket.ReceiveAsync(buffer, Token); - public async ValueTask CloseSocket(WebSocketCloseStatus status, string reason) - { - SetSocketState(SocketState.Disconnecting); + public ValueTask SendAsync(Memory buffer, WebSocketMessageType messageType, bool endOfMessage) => _socket.SendAsync(buffer, messageType, endOfMessage, Token); - if (_socket.State == WebSocketState.CloseReceived) - { - _logger.Debug("Closing Socket Output for ID: {0}", WebsocketId); - await _socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, string.Empty, Token).ConfigureAwait(false); - } - else - { - _logger.Debug("Closing Socket for ID: {0}", WebsocketId); - await _socket.CloseAsync(status, reason, Token).ConfigureAwait(false); - } + public async ValueTask CloseSocket(WebSocketCloseStatus status, string reason) + { + SetSocketState(SocketState.Disconnecting); - _socketClosed = true; - _logger.Debug("{0} Socket Closed Successfully", WebsocketId); + if (_socket.State == WebSocketState.CloseReceived) + { + _logger.Debug("Closing Socket Output for ID: {0}", WebsocketId); + await _socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, string.Empty, Token).ConfigureAwait(false); + } + else + { + _logger.Debug("Closing Socket for ID: {0}", WebsocketId); + await _socket.CloseAsync(status, reason, Token).ConfigureAwait(false); } - public void Dispose() + _socketClosed = true; + _logger.Debug("{0} Socket Closed Successfully", WebsocketId); + } + + public void Dispose() + { + _logger.Debug("Disposing Client {0}", WebsocketId); + if (_isDisposed) { - _logger.Debug("Disposing Client {0}", WebsocketId); - if (_isDisposed) - { - _logger.Debug("{0} already disposed", WebsocketId); - return; - } + _logger.Debug("{0} already disposed", WebsocketId); + return; + } - _isDisposed = true; - - SetSocketState(SocketState.Disconnected); - if (Token.CanBeCanceled) - { - _source.Cancel(); - } + _isDisposed = true; - if (!_socketClosed) - { - _socket.Dispose(); - } + SetSocketState(SocketState.Disconnected); + if (Token.CanBeCanceled) + { + _source.Cancel(); + } - _logger.Debug("{0} Dispose Complete", WebsocketId); + if (!_socketClosed) + { + _socket.Dispose(); } + + _logger.Debug("{0} Dispose Complete", WebsocketId); } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/DiscordWebsocketCloseCode.cs b/Oxide.Ext.Discord/WebSockets/DiscordWebsocketCloseCode.cs index 2668d6536..13bdf06ba 100644 --- a/Oxide.Ext.Discord/WebSockets/DiscordWebsocketCloseCode.cs +++ b/Oxide.Ext.Discord/WebSockets/DiscordWebsocketCloseCode.cs @@ -1,87 +1,86 @@ -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +/// +/// Represents Socket Close Event Codes +/// +public enum DiscordWebsocketCloseCode { /// - /// Represents Socket Close Event Codes - /// - public enum DiscordWebsocketCloseCode - { - /// - /// We're not sure what went wrong. Try reconnecting? - /// - UnknownError = 4000, - /// - /// You sent an invalid Gateway opcode or an invalid payload for an opcode. Don't do that! - /// - UnknownOpcode = 4001, + /// We're not sure what went wrong. Try reconnecting? + /// + UnknownError = 4000, + /// + /// You sent an invalid Gateway opcode or an invalid payload for an opcode. Don't do that! + /// + UnknownOpcode = 4001, - /// - /// You sent an invalid payload to us. Don't do that! - /// - DecodeError = 4002, + /// + /// You sent an invalid payload to us. Don't do that! + /// + DecodeError = 4002, - /// - /// You sent us a payload prior to identifying. - /// - NotAuthenticated = 4003, + /// + /// You sent us a payload prior to identifying. + /// + NotAuthenticated = 4003, - /// - /// The account token sent with your identify payload is incorrect. - /// - AuthenticationFailed = 4004, + /// + /// The account token sent with your identify payload is incorrect. + /// + AuthenticationFailed = 4004, - /// - /// You sent more than one identify payload. Don't do that! - /// - AlreadyAuthenticated = 4005, + /// + /// You sent more than one identify payload. Don't do that! + /// + AlreadyAuthenticated = 4005, - /// - /// The sequence sent when resuming the session was invalid. Reconnect and start a new session. - /// - InvalidSequence = 4007, + /// + /// The sequence sent when resuming the session was invalid. Reconnect and start a new session. + /// + InvalidSequence = 4007, - /// - /// Woah nelly! You're sending payloads to us too quickly. Slow it down! You will be disconnected on receiving this. - /// - RateLimited = 4008, + /// + /// Woah nelly! You're sending payloads to us too quickly. Slow it down! You will be disconnected on receiving this. + /// + RateLimited = 4008, - /// - /// Your session timed out. Reconnect and start a new one. - /// - SessionTimedOut = 4009, + /// + /// Your session timed out. Reconnect and start a new one. + /// + SessionTimedOut = 4009, - /// - /// You sent us an invalid shard when identifying. - /// - InvalidShard = 4010, + /// + /// You sent us an invalid shard when identifying. + /// + InvalidShard = 4010, - /// - /// The session would have handled too many guilds - you are required to shard your connection in order to connect. - /// - ShardingRequired = 4011, + /// + /// The session would have handled too many guilds - you are required to shard your connection to connect. + /// + ShardingRequired = 4011, - /// - /// You sent an invalid version for the gateway. - /// - InvalidApiVersion = 4012, + /// + /// You sent an invalid version for the gateway. + /// + InvalidApiVersion = 4012, - /// - /// You sent an invalid intent for a Gateway Intent. You may have incorrectly calculated the bitwise value. - /// - InvalidIntents = 4013, + /// + /// You sent an invalid intent for a Gateway Intent. You may have incorrectly calculated the bitwise value. + /// + InvalidIntents = 4013, - /// - /// You sent a disallowed intent for a Gateway Intent. You may have tried to specify an intent that you have not enabled or are not whitelisted for. - /// - DisallowedIntent = 4014, + /// + /// You sent a disallowed intent for a Gateway Intent. You may have tried to specify an intent that you have not enabled or are not allowlisted for. + /// + DisallowedIntent = 4014, - /// - /// Used to identify a reconnect should occur to discord - /// - DiscordExtensionReconnect = 4199, + /// + /// Used to identify a reconnect should occur to discord + /// + DiscordExtensionReconnect = 4199, - /// - /// Used when a code is sent that we don't have yet. - /// - UnknownCloseCode = 4999 - } + /// + /// Used when a code is sent that we don't have yet. + /// + UnknownCloseCode = 4999 } \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/Handlers/DiscordDispatchCode.cs b/Oxide.Ext.Discord/WebSockets/Handlers/DiscordDispatchCode.cs index ba289e8f3..17d74d6d1 100644 --- a/Oxide.Ext.Discord/WebSockets/Handlers/DiscordDispatchCode.cs +++ b/Oxide.Ext.Discord/WebSockets/Handlers/DiscordDispatchCode.cs @@ -2,337 +2,346 @@ using Oxide.Ext.Discord.Attributes; using Oxide.Ext.Discord.Json; -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +/// +/// Represents the Gateway Event Codes +/// +[JsonConverter(typeof(DiscordEnumConverter))] +public enum DiscordDispatchCode : byte { /// - /// Represents the Gateway Event Codes - /// - [JsonConverter(typeof(DiscordEnumConverter))] - public enum DiscordDispatchCode : byte - { - /// - /// Used when we don't have a matching Dispatch Code - /// - Unknown, - - /// - /// Represents the READY gateway event - /// - [DiscordEnum("READY")] Ready, - - /// - /// Represents the RESUMED gateway event - /// - [DiscordEnum("RESUMED")] Resumed, - - /// - /// Represents the CHANNEL_CREATE gateway event - /// - [DiscordEnum("CHANNEL_CREATE")] ChannelCreated, - - /// - /// Represents the CHANNEL_UPDATE gateway event - /// - [DiscordEnum("CHANNEL_UPDATE")] ChannelUpdated, - - /// - /// Represents the CHANNEL_DELETE gateway event - /// - [DiscordEnum("CHANNEL_DELETE")] ChannelDeleted, - - /// - /// Represents the CHANNEL_PINS_UPDATE gateway event - /// - [DiscordEnum("CHANNEL_PINS_UPDATE")] ChannelPinsUpdate, - - /// - /// Represents the ENTITLEMENT_CREATE gateway event - /// - [DiscordEnum("ENTITLEMENT_CREATE")] EntitlementCreate, - - /// - /// Represents the ENTITLEMENT_UPDATE gateway event - /// - [DiscordEnum("ENTITLEMENT_UPDATE")] EntitlementUpdate, - - /// - /// Represents the ENTITLEMENT_DELETE gateway event - /// - [DiscordEnum("ENTITLEMENT_DELETE")] EntitlementDelete, - - /// - /// Represents the GUILD_CREATE gateway event - /// - [DiscordEnum("GUILD_CREATE")] GuildCreated, - - /// - /// Represents the GUILD_UPDATE gateway event - /// - [DiscordEnum("GUILD_UPDATE")] GuildUpdated, - - /// - /// Represents the GUILD_DELETE gateway event - /// - [DiscordEnum("GUILD_DELETE")] GuildDeleted, - - /// - /// Represents the GUILD_BAN_ADD gateway event - /// - [DiscordEnum("GUILD_BAN_ADD")] GuildBanAdded, - - /// - /// Represents the GUILD_BAN_REMOVE gateway event - /// - [DiscordEnum("GUILD_BAN_REMOVE")] GuildBanRemoved, - - /// - /// Represents the GUILD_EMOJIS_UPDATE gateway event - /// - [DiscordEnum("GUILD_EMOJIS_UPDATE")] GuildEmojisUpdated, - - /// - /// Represents the GUILD_STICKERS_UPDATE gateway event - /// - [DiscordEnum("GUILD_STICKERS_UPDATE")] GuildStickersUpdate, - - /// - /// Represents the GUILD_INTEGRATIONS_UPDATE gateway event - /// - [DiscordEnum("GUILD_INTEGRATIONS_UPDATE")] GuildIntegrationsUpdated, - - /// - /// Represents the GUILD_MEMBER_ADD gateway event - /// - [DiscordEnum("GUILD_MEMBER_ADD")] GuildMemberAdded, - - /// - /// Represents the GUILD_MEMBER_REMOVE gateway event - /// - [DiscordEnum("GUILD_MEMBER_REMOVE")] GuildMemberRemoved, - - /// - /// Represents the GUILD_MEMBER_UPDATE gateway event - /// - [DiscordEnum("GUILD_MEMBER_UPDATE")] GuildMemberUpdated, - - /// - /// Represents the GUILD_MEMBERS_CHUNK gateway event - /// - [DiscordEnum("GUILD_MEMBERS_CHUNK")] GuildMembersChunk, - - /// - /// Represents the GUILD_ROLE_CREATE gateway event - /// - [DiscordEnum("GUILD_ROLE_CREATE")] GuildRoleCreated, - - /// - /// Represents the GUILD_ROLE_UPDATE gateway event - /// - [DiscordEnum("GUILD_ROLE_UPDATE")] GuildRoleUpdated, - - /// - /// Represents the GUILD_ROLE_DELETE gateway event - /// - [DiscordEnum("GUILD_ROLE_DELETE")] GuildRoleDeleted, - - /// - /// Represents the GUILD_SCHEDULED_EVENT_CREATE gateway event - /// - [DiscordEnum("GUILD_SCHEDULED_EVENT_CREATE")] GuildScheduledEventCreate, - - /// - /// Represents the GUILD_SCHEDULED_EVENT_UPDATE gateway event - /// - [DiscordEnum("GUILD_SCHEDULED_EVENT_UPDATE")] GuildScheduledEventUpdate, - - /// - /// Represents the GUILD_SCHEDULED_EVENT_DELETE gateway event - /// - [DiscordEnum("GUILD_SCHEDULED_EVENT_DELETE")] GuildScheduledEventDelete, - - /// - /// Represents the GUILD_SCHEDULED_EVENT_USER_ADD gateway event - /// - [DiscordEnum("GUILD_SCHEDULED_EVENT_USER_ADD")] GuildScheduledEventUserAdd, - - /// - /// Represents the GUILD_SCHEDULED_EVENT_USER_REMOVE gateway event - /// - [DiscordEnum("GUILD_SCHEDULED_EVENT_USER_REMOVE")] GuildScheduledEventUserRemove, - - /// - /// Represents the INTEGRATION_CREATE gateway event - /// - [DiscordEnum("INTEGRATION_CREATE")] IntegrationCreated, - - /// - /// Represents the INTEGRATION_UPDATE gateway event - /// - [DiscordEnum("INTEGRATION_UPDATE")] IntegrationUpdated, - - /// - /// Represents the INTEGRATION_DELETE gateway event - /// - [DiscordEnum("INTEGRATION_DELETE")] IntegrationDeleted, - - /// - /// Represents the MESSAGE_CREATE gateway event - /// - [DiscordEnum("MESSAGE_CREATE")] MessageCreated, - - /// - /// Represents the MESSAGE_UPDATE gateway event - /// - [DiscordEnum("MESSAGE_UPDATE")] MessageUpdated, - - /// - /// Represents the MESSAGE_DELETE gateway event - /// - [DiscordEnum("MESSAGE_DELETE")] MessageDeleted, - - /// - /// Represents the MESSAGE_DELETE_BULK gateway event - /// - [DiscordEnum("MESSAGE_DELETE_BULK")] MessageBulkDeleted, - - /// - /// Represents the MESSAGE_REACTION_ADD gateway event - /// - [DiscordEnum("MESSAGE_REACTION_ADD")] MessageReactionAdded, - - /// - /// Represents the MESSAGE_REACTION_REMOVE gateway event - /// - [DiscordEnum("MESSAGE_REACTION_REMOVE")] MessageReactionRemoved, - - /// - /// Represents the MESSAGE_REACTION_REMOVE_ALL gateway event - /// - [DiscordEnum("MESSAGE_REACTION_REMOVE_ALL")] MessageReactionAllRemoved, - - /// - /// Represents the MESSAGE_REACTION_REMOVE_EMOJI gateway event - /// - [DiscordEnum("MESSAGE_REACTION_REMOVE_EMOJI")] MessageReactionEmojiRemoved, - - /// - /// Represents the PRESENCE_UPDATE gateway event - /// - [DiscordEnum("PRESENCE_UPDATE")] PresenceUpdated, - - /// - /// Represents the PRESENCES_REPLACE gateway event - /// - [DiscordEnum("PRESENCES_REPLACE")] PresenceReplace, - - /// - /// Represents the TYPING_START gateway event - /// - [DiscordEnum("TYPING_START")] TypingStarted, - - /// - /// Represents the USER_UPDATE gateway event - /// - [DiscordEnum("USER_UPDATE")] UserUpdated, - - /// - /// Represents the VOICE_STATE_UPDATE gateway event - /// - [DiscordEnum("VOICE_STATE_UPDATE")] VoiceStateUpdated, - - /// - /// Represents the VOICE_SERVER_UPDATE gateway event - /// - [DiscordEnum("VOICE_SERVER_UPDATE")] VoiceServerUpdated, - - /// - /// Represents the WEBHOOKS_UPDATE gateway event - /// - [DiscordEnum("WEBHOOKS_UPDATE")] WebhooksUpdated, - - /// - /// Represents the INVITE_CREATE gateway event - /// - [DiscordEnum("INVITE_CREATE")] InviteCreated, - - /// - /// Represents the INVITE_DELETE gateway event - /// - [DiscordEnum("INVITE_DELETE")] InviteDeleted, - - /// - /// Represents the APPLICATION_COMMANDS_PERMISSIONS_UPDATE gateway event - /// - [DiscordEnum("APPLICATION_COMMANDS_PERMISSIONS_UPDATE")] ApplicationCommandsPermissionsUpdate, - - /// - /// Represents the INTERACTION_CREATE gateway event - /// - [DiscordEnum("INTERACTION_CREATE")] InteractionCreated, + /// Used when we don't have a matching Dispatch Code + /// + Unknown, + + /// + /// Represents the READY gateway event + /// + [DiscordEnum("READY")] Ready, + + /// + /// Represents the RESUMED gateway event + /// + [DiscordEnum("RESUMED")] Resumed, + + /// + /// Represents the CHANNEL_CREATE gateway event + /// + [DiscordEnum("CHANNEL_CREATE")] ChannelCreated, + + /// + /// Represents the CHANNEL_UPDATE gateway event + /// + [DiscordEnum("CHANNEL_UPDATE")] ChannelUpdated, + + /// + /// Represents the CHANNEL_DELETE gateway event + /// + [DiscordEnum("CHANNEL_DELETE")] ChannelDeleted, + + /// + /// Represents the CHANNEL_PINS_UPDATE gateway event + /// + [DiscordEnum("CHANNEL_PINS_UPDATE")] ChannelPinsUpdate, + + /// + /// Represents the ENTITLEMENT_CREATE gateway event + /// + [DiscordEnum("ENTITLEMENT_CREATE")] EntitlementCreate, + + /// + /// Represents the ENTITLEMENT_UPDATE gateway event + /// + [DiscordEnum("ENTITLEMENT_UPDATE")] EntitlementUpdate, + + /// + /// Represents the ENTITLEMENT_DELETE gateway event + /// + [DiscordEnum("ENTITLEMENT_DELETE")] EntitlementDelete, + + /// + /// Represents the GUILD_CREATE gateway event + /// + [DiscordEnum("GUILD_CREATE")] GuildCreated, + + /// + /// Represents the GUILD_UPDATE gateway event + /// + [DiscordEnum("GUILD_UPDATE")] GuildUpdated, + + /// + /// Represents the GUILD_DELETE gateway event + /// + [DiscordEnum("GUILD_DELETE")] GuildDeleted, + + /// + /// Represents the GUILD_BAN_ADD gateway event + /// + [DiscordEnum("GUILD_BAN_ADD")] GuildBanAdded, + + /// + /// Represents the GUILD_BAN_REMOVE gateway event + /// + [DiscordEnum("GUILD_BAN_REMOVE")] GuildBanRemoved, + + /// + /// Represents the GUILD_EMOJIS_UPDATE gateway event + /// + [DiscordEnum("GUILD_EMOJIS_UPDATE")] GuildEmojisUpdated, + + /// + /// Represents the GUILD_STICKERS_UPDATE gateway event + /// + [DiscordEnum("GUILD_STICKERS_UPDATE")] GuildStickersUpdate, + + /// + /// Represents the GUILD_INTEGRATIONS_UPDATE gateway event + /// + [DiscordEnum("GUILD_INTEGRATIONS_UPDATE")] GuildIntegrationsUpdated, + + /// + /// Represents the GUILD_MEMBER_ADD gateway event + /// + [DiscordEnum("GUILD_MEMBER_ADD")] GuildMemberAdded, + + /// + /// Represents the GUILD_MEMBER_REMOVE gateway event + /// + [DiscordEnum("GUILD_MEMBER_REMOVE")] GuildMemberRemoved, + + /// + /// Represents the GUILD_MEMBER_UPDATE gateway event + /// + [DiscordEnum("GUILD_MEMBER_UPDATE")] GuildMemberUpdated, + + /// + /// Represents the GUILD_MEMBERS_CHUNK gateway event + /// + [DiscordEnum("GUILD_MEMBERS_CHUNK")] GuildMembersChunk, + + /// + /// Represents the GUILD_ROLE_CREATE gateway event + /// + [DiscordEnum("GUILD_ROLE_CREATE")] GuildRoleCreated, + + /// + /// Represents the GUILD_ROLE_UPDATE gateway event + /// + [DiscordEnum("GUILD_ROLE_UPDATE")] GuildRoleUpdated, + + /// + /// Represents the GUILD_ROLE_DELETE gateway event + /// + [DiscordEnum("GUILD_ROLE_DELETE")] GuildRoleDeleted, + + /// + /// Represents the GUILD_SCHEDULED_EVENT_CREATE gateway event + /// + [DiscordEnum("GUILD_SCHEDULED_EVENT_CREATE")] GuildScheduledEventCreate, + + /// + /// Represents the GUILD_SCHEDULED_EVENT_UPDATE gateway event + /// + [DiscordEnum("GUILD_SCHEDULED_EVENT_UPDATE")] GuildScheduledEventUpdate, + + /// + /// Represents the GUILD_SCHEDULED_EVENT_DELETE gateway event + /// + [DiscordEnum("GUILD_SCHEDULED_EVENT_DELETE")] GuildScheduledEventDelete, + + /// + /// Represents the GUILD_SCHEDULED_EVENT_USER_ADD gateway event + /// + [DiscordEnum("GUILD_SCHEDULED_EVENT_USER_ADD")] GuildScheduledEventUserAdd, + + /// + /// Represents the GUILD_SCHEDULED_EVENT_USER_REMOVE gateway event + /// + [DiscordEnum("GUILD_SCHEDULED_EVENT_USER_REMOVE")] GuildScheduledEventUserRemove, + + /// + /// Represents the INTEGRATION_CREATE gateway event + /// + [DiscordEnum("INTEGRATION_CREATE")] IntegrationCreated, + + /// + /// Represents the INTEGRATION_UPDATE gateway event + /// + [DiscordEnum("INTEGRATION_UPDATE")] IntegrationUpdated, + + /// + /// Represents the INTEGRATION_DELETE gateway event + /// + [DiscordEnum("INTEGRATION_DELETE")] IntegrationDeleted, + + /// + /// Represents the MESSAGE_CREATE gateway event + /// + [DiscordEnum("MESSAGE_CREATE")] MessageCreated, + + /// + /// Represents the MESSAGE_UPDATE gateway event + /// + [DiscordEnum("MESSAGE_UPDATE")] MessageUpdated, + + /// + /// Represents the MESSAGE_DELETE gateway event + /// + [DiscordEnum("MESSAGE_DELETE")] MessageDeleted, + + /// + /// Represents the MESSAGE_DELETE_BULK gateway event + /// + [DiscordEnum("MESSAGE_DELETE_BULK")] MessageBulkDeleted, + + /// + /// Represents the MESSAGE_REACTION_ADD gateway event + /// + [DiscordEnum("MESSAGE_REACTION_ADD")] MessageReactionAdded, + + /// + /// Represents the MESSAGE_REACTION_REMOVE gateway event + /// + [DiscordEnum("MESSAGE_REACTION_REMOVE")] MessageReactionRemoved, + + /// + /// Represents the MESSAGE_REACTION_REMOVE_ALL gateway event + /// + [DiscordEnum("MESSAGE_REACTION_REMOVE_ALL")] MessageReactionAllRemoved, + + /// + /// Represents the MESSAGE_REACTION_REMOVE_EMOJI gateway event + /// + [DiscordEnum("MESSAGE_REACTION_REMOVE_EMOJI")] MessageReactionEmojiRemoved, + + /// + /// Represents the PRESENCE_UPDATE gateway event + /// + [DiscordEnum("PRESENCE_UPDATE")] PresenceUpdated, + + /// + /// Represents the PRESENCES_REPLACE gateway event + /// + [DiscordEnum("PRESENCES_REPLACE")] PresenceReplace, + + /// + /// Represents the TYPING_START gateway event + /// + [DiscordEnum("TYPING_START")] TypingStarted, + + /// + /// Represents the USER_UPDATE gateway event + /// + [DiscordEnum("USER_UPDATE")] UserUpdated, + + /// + /// Represents the VOICE_STATE_UPDATE gateway event + /// + [DiscordEnum("VOICE_STATE_UPDATE")] VoiceStateUpdated, + + /// + /// Represents the VOICE_SERVER_UPDATE gateway event + /// + [DiscordEnum("VOICE_SERVER_UPDATE")] VoiceServerUpdated, + + /// + /// Represents the WEBHOOKS_UPDATE gateway event + /// + [DiscordEnum("WEBHOOKS_UPDATE")] WebhooksUpdated, + + /// + /// Represents the INVITE_CREATE gateway event + /// + [DiscordEnum("INVITE_CREATE")] InviteCreated, + + /// + /// Represents the INVITE_DELETE gateway event + /// + [DiscordEnum("INVITE_DELETE")] InviteDeleted, + + /// + /// Represents the APPLICATION_COMMANDS_PERMISSIONS_UPDATE gateway event + /// + [DiscordEnum("APPLICATION_COMMANDS_PERMISSIONS_UPDATE")] ApplicationCommandsPermissionsUpdate, + + /// + /// Represents the INTERACTION_CREATE gateway event + /// + [DiscordEnum("INTERACTION_CREATE")] InteractionCreated, - /// - /// Represents the THREAD_CREATE gateway event - /// - [DiscordEnum("THREAD_CREATE")] ThreadCreated, - - /// - /// Represents the THREAD_UPDATE gateway event - /// - [DiscordEnum("THREAD_UPDATE")] ThreadUpdated, - - /// - /// Represents the THREAD_DELETE gateway event - /// - [DiscordEnum("THREAD_DELETE")] ThreadDeleted, - - /// - /// Represents the THREAD_LIST_SYNC gateway event - /// - [DiscordEnum("THREAD_LIST_SYNC")] ThreadListSync, - - /// - /// Represents the THREAD_MEMBER_UPDATE gateway event - /// - [DiscordEnum("THREAD_MEMBER_UPDATE")] ThreadMemberUpdated, - - /// - /// Represents the THREAD_MEMBERS_UPDATE gateway event - /// - [DiscordEnum("THREAD_MEMBERS_UPDATE")] ThreadMembersUpdated, - - /// - /// Represents the STAGE_INSTANCE_CREATE gateway event - /// - [DiscordEnum("STAGE_INSTANCE_CREATE")] StageInstanceCreated, - - /// - /// Represents the STAGE_INSTANCE_CREATE gateway event - /// - [DiscordEnum("STAGE_INSTANCE_UPDATE")] StageInstanceUpdated, - - /// - /// Represents the STAGE_INSTANCE_CREATE gateway event - /// - [DiscordEnum("STAGE_INSTANCE_DELETE")] StageInstanceDeleted, - - /// - /// Represents the AUTO_MODERATION_RULE_CREATE gateway event - /// - [DiscordEnum("AUTO_MODERATION_RULE_CREATE")] AutoModerationRuleCreate, - - /// - /// Represents the AUTO_MODERATION_RULE_UPDATE gateway event - /// - [DiscordEnum("AUTO_MODERATION_RULE_UPDATE")] AutoModerationRuleUpdate, - - /// - /// Represents the AUTO_MODERATION_RULE_DELETE gateway event - /// - [DiscordEnum("AUTO_MODERATION_RULE_DELETE")] AutoModerationRuleDelete, - - /// - /// Represents the AUTO_MODERATION_ACTION_EXECUTION gateway event - /// - [DiscordEnum("AUTO_MODERATION_ACTION_EXECUTION")] AutoModerationActionExecution, - } + /// + /// Represents the THREAD_CREATE gateway event + /// + [DiscordEnum("THREAD_CREATE")] ThreadCreated, + + /// + /// Represents the THREAD_UPDATE gateway event + /// + [DiscordEnum("THREAD_UPDATE")] ThreadUpdated, + + /// + /// Represents the THREAD_DELETE gateway event + /// + [DiscordEnum("THREAD_DELETE")] ThreadDeleted, + + /// + /// Represents the THREAD_LIST_SYNC gateway event + /// + [DiscordEnum("THREAD_LIST_SYNC")] ThreadListSync, + + /// + /// Represents the THREAD_MEMBER_UPDATE gateway event + /// + [DiscordEnum("THREAD_MEMBER_UPDATE")] ThreadMemberUpdated, + + /// + /// Represents the THREAD_MEMBERS_UPDATE gateway event + /// + [DiscordEnum("THREAD_MEMBERS_UPDATE")] ThreadMembersUpdated, + + /// + /// Represents the STAGE_INSTANCE_CREATE gateway event + /// + [DiscordEnum("STAGE_INSTANCE_CREATE")] StageInstanceCreated, + + /// + /// Represents the STAGE_INSTANCE_CREATE gateway event + /// + [DiscordEnum("STAGE_INSTANCE_UPDATE")] StageInstanceUpdated, + + /// + /// Represents the STAGE_INSTANCE_CREATE gateway event + /// + [DiscordEnum("STAGE_INSTANCE_DELETE")] StageInstanceDeleted, + + /// + /// Represents the AUTO_MODERATION_RULE_CREATE gateway event + /// + [DiscordEnum("AUTO_MODERATION_RULE_CREATE")] AutoModerationRuleCreate, + + /// + /// Represents the AUTO_MODERATION_RULE_UPDATE gateway event + /// + [DiscordEnum("AUTO_MODERATION_RULE_UPDATE")] AutoModerationRuleUpdate, + + /// + /// Represents the AUTO_MODERATION_RULE_DELETE gateway event + /// + [DiscordEnum("AUTO_MODERATION_RULE_DELETE")] AutoModerationRuleDelete, + + /// + /// Represents the AUTO_MODERATION_ACTION_EXECUTION gateway event + /// + [DiscordEnum("AUTO_MODERATION_ACTION_EXECUTION")] AutoModerationActionExecution, + + /// + /// Represents the MESSAGE_POLL_VOTE_ADD gateway event + /// + [DiscordEnum("MESSAGE_POLL_VOTE_ADD")] MessagePollVoteAdded, + + /// + /// Represents the MESSAGE_POLL_VOTE_REMOVE gateway event + /// + [DiscordEnum("MESSAGE_POLL_VOTE_REMOVE")] MessagePollVoteRemoved, } \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/Handlers/DiscordHeartbeatHandler.cs b/Oxide.Ext.Discord/WebSockets/Handlers/DiscordHeartbeatHandler.cs index 21dcfa4d3..f0bead4e5 100644 --- a/Oxide.Ext.Discord/WebSockets/Handlers/DiscordHeartbeatHandler.cs +++ b/Oxide.Ext.Discord/WebSockets/Handlers/DiscordHeartbeatHandler.cs @@ -5,148 +5,147 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +/// +/// Handles the heartbeating for the websocket connection +/// +public class DiscordHeartbeatHandler { /// - /// Handles the heartbeating for the websocket connection + /// Discord Acknowledged our heartbeat successfully /// - public class DiscordHeartbeatHandler + private bool _heartbeatAcknowledged; + + private readonly BotClient _client; + private readonly DiscordWebSocket _socket; + private readonly ILogger _logger; + private Timer _timer; + private float _interval; + private bool _initial; + + /// + /// Constructor for Heartbeat Handler + /// + /// Client for the handler + /// Socket for the heartbeat + /// Logger for the bot + public DiscordHeartbeatHandler(BotClient client, DiscordWebSocket socket, ILogger logger) { - /// - /// Discord Acknowledged our heartbeat successfully - /// - private bool _heartbeatAcknowledged; + _client = client; + _socket = socket; + _logger = logger; + _timer = new Timer(); + _timer.Elapsed += HeartbeatElapsed; + } - private readonly BotClient _client; - private readonly DiscordWebSocket _socket; - private readonly ILogger _logger; - private Timer _timer; - private float _interval; - private bool _initial; + #region Heartbeat + /// + /// Setup a heartbeat for this bot with the given interval + /// + /// + internal void SetupHeartbeat(float interval) + { + _timer.Stop(); + _heartbeatAcknowledged = true; + _interval = interval; + _initial = true; + _timer.Interval = _interval * Random.Range(0f, 1f); + _timer.Start(); + _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(SetupHeartbeat)} Creating heartbeat with interval {{0}}ms.", interval); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordSetupHeartbeat, interval); + } + + internal void OnHeartbeatAcknowledge() + { + _heartbeatAcknowledged = true; + } - /// - /// Constructor for Heartbeat Handler - /// - /// Client for the handler - /// Socket for the heartbeat - /// Logger for the bot - public DiscordHeartbeatHandler(BotClient client, DiscordWebSocket socket, ILogger logger) + /// + /// Destroy the heartbeat timer on this bot + /// + public void OnSocketShutdown() + { + if(_timer != null) { - _client = client; - _socket = socket; - _logger = logger; - _timer = new Timer(); - _timer.Elapsed += HeartbeatElapsed; + _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(OnSocketShutdown)} Destroy Heartbeat"); + _timer.Dispose(); + _timer = null; } - - #region Heartbeat - /// - /// Setup a heartbeat for this bot with the given interval - /// - /// - internal void SetupHeartbeat(float interval) + } + + private void HeartbeatElapsed(object sender, ElapsedEventArgs e) + { + _logger.Verbose($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Heartbeat Elapsed"); + + if (_initial) { - _timer.Stop(); - _heartbeatAcknowledged = true; - _interval = interval; - _initial = true; - _timer.Interval = _interval * Random.Range(0f, 1f); - _timer.Start(); - _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(SetupHeartbeat)} Creating heartbeat with interval {{0}}ms.", interval); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordSetupHeartbeat, interval); + _timer.Interval = _interval; + _initial = false; } - internal void OnHeartbeatAcknowledge() + if (!_socket.SocketHasConnected) { - _heartbeatAcknowledged = true; + _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Websocket has not yet connected successfully. Skipping Heartbeat."); + return; } - - /// - /// Destroy the heartbeat timer on this bot - /// - public void OnSocketShutdown() + + if (_socket.IsPendingReconnect()) { - if(_timer != null) - { - _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(OnSocketShutdown)} Destroy Heartbeat"); - _timer.Dispose(); - _timer = null; - } + _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Websocket is offline and is waiting to connect."); + return; } - private void HeartbeatElapsed(object sender, ElapsedEventArgs e) + if (_socket.IsDisconnected()) { - _logger.Verbose($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Heartbeat Elapsed"); - - if (_initial) - { - _timer.Interval = _interval; - _initial = false; - } + _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Websocket is offline and is NOT connecting. Attempt Reconnect."); + _socket.ShouldReconnect = true; + _socket.ReconnectIfRequested(); + return; + } - if (!_socket.SocketHasConnected) - { - _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Websocket has not yet connected successfully. Skipping Heartbeat."); - return; - } + if (_socket.IsDisconnecting()) + { + _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Websocket is currently in the process of disconnecting"); + return; + } - if (_socket.IsPendingReconnect()) + if(!_heartbeatAcknowledged) + { + //Discord did not acknowledge our last sent heartbeat. This is a zombie connection we should reconnect. + if (_socket.IsConnected()) { - _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Websocket is offline and is waiting to connect."); + _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Heartbeat Elapsed and WebSocket is connected. Forcing reconnect."); + _socket.Disconnect(true, true, true); return; } - if (_socket.IsDisconnected()) + //Websocket isn't connected or waiting to reconnect. We should reconnect. + if (!_socket.IsConnecting() && !_socket.IsPendingReconnect()) { - _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Websocket is offline and is NOT connecting. Attempt Reconnect."); + _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Heartbeat Elapsed and bot is not online or connecting."); _socket.ShouldReconnect = true; _socket.ReconnectIfRequested(); return; } - if (_socket.IsDisconnecting()) - { - _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Websocket is currently in the process of disconnecting"); - return; - } - - if(!_heartbeatAcknowledged) - { - //Discord did not acknowledge our last sent heartbeat. This is a zombie connection we should reconnect. - if (_socket.IsConnected()) - { - _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Heartbeat Elapsed and WebSocket is connected. Forcing reconnect."); - _socket.Disconnect(true, true, true); - return; - } - - //Websocket isn't connected or waiting to reconnect. We should reconnect. - if (!_socket.IsConnecting() && !_socket.IsPendingReconnect()) - { - _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Heartbeat Elapsed and bot is not online or connecting."); - _socket.ShouldReconnect = true; - _socket.ReconnectIfRequested(); - return; - } - - _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Heartbeat Elapsed and bot is not online but is waiting to connecting or waiting to reconnect."); - return; - } - - SendHeartbeat(); + _logger.Debug($"{nameof(DiscordHeartbeatHandler)}.{nameof(HeartbeatElapsed)} Heartbeat Elapsed and bot is not online but is waiting to connecting or waiting to reconnect."); + return; } + + SendHeartbeat(); + } - /// - /// Sends a heartbeat to discord. - /// If the previous heartbeat wasn't acknowledged then we will attempt to reconnect - /// - private void SendHeartbeat() - { - _heartbeatAcknowledged = false; - _socket.SendHeartbeat(); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordHeartbeatSent); - _logger.Verbose("Heartbeat sent - {0}ms interval.", _timer.Interval); - } - #endregion + /// + /// Sends a heartbeat to discord. + /// If the previous heartbeat wasn't acknowledged, then we will attempt to reconnect + /// + private void SendHeartbeat() + { + _heartbeatAcknowledged = false; + _socket.SendHeartbeat(); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordHeartbeatSent); + _logger.Verbose("Heartbeat sent - {0}ms interval.", _timer.Interval); } + #endregion } \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketCommandHandler.cs b/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketCommandHandler.cs index 377723c85..89e81d4d8 100644 --- a/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketCommandHandler.cs +++ b/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketCommandHandler.cs @@ -10,201 +10,200 @@ using Oxide.Ext.Discord.Logging; using Oxide.Ext.Discord.Types; -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +/// +/// Handles command queueing when the websocket is down +/// +public class WebSocketCommandHandler { + private readonly BotClient _client; + private readonly DiscordWebSocket _webSocket; + private readonly ILogger _logger; + private readonly ConcurrentQueue _pendingCommands = new(); + private readonly WebsocketRateLimit _rateLimit; + private readonly AutoResetEvent _online = new(false); + private readonly AutoResetEvent _commands = new(false); + private readonly CancellationTokenSource _source; + private readonly CancellationToken _token; + private bool _isSocketReady; + private bool _isDisposed; + /// - /// Handles command queueing when the websocket is down + /// Constructor /// - public class WebSocketCommandHandler + /// Bot Client for socket commands + /// Websocket to handle commands for + /// Logger for this handler + public WebSocketCommandHandler(BotClient client, DiscordWebSocket webSocket, ILogger logger) { - private readonly BotClient _client; - private readonly DiscordWebSocket _webSocket; - private readonly ILogger _logger; - private readonly ConcurrentQueue _pendingCommands = new ConcurrentQueue(); - private readonly WebsocketRateLimit _rateLimit; - private readonly AutoResetEvent _online = new AutoResetEvent(false); - private readonly AutoResetEvent _commands = new AutoResetEvent(false); - private readonly CancellationTokenSource _source; - private readonly CancellationToken _token; - private bool _isSocketReady; - private bool _isDisposed; - - /// - /// Constructor - /// - /// Bot Client for socket commands - /// Websocket to handle commands for - /// Logger for this handler - public WebSocketCommandHandler(BotClient client, DiscordWebSocket webSocket, ILogger logger) - { - _client = client; - _webSocket = webSocket; - _logger = logger; - _rateLimit = new WebsocketRateLimit(_logger); + _client = client; + _webSocket = webSocket; + _logger = logger; + _rateLimit = new WebsocketRateLimit(_logger); - _source = new CancellationTokenSource(); - _token = _source.Token; + _source = new CancellationTokenSource(); + _token = _source.Token; - Task.Factory.StartNew(RunInternal, _token, TaskCreationOptions.LongRunning, TaskScheduler.Default); - } + Task.Factory.StartNew(RunInternal, _token, TaskCreationOptions.LongRunning, TaskScheduler.Default); + } - private async void RunInternal() + private async void RunInternal() + { + try { - try - { - await SendCommandsInternal().ConfigureAwait(false); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.Exception($"Unhandled exception in {nameof(WebSocketCommandHandler)}.{nameof(RunInternal)}", ex); - } + await SendCommandsInternal().ConfigureAwait(false); } + catch (OperationCanceledException) { } + catch (Exception ex) + { + _logger.Exception($"Unhandled exception in {nameof(WebSocketCommandHandler)}.{nameof(RunInternal)}", ex); + } + } - private async ValueTask SendCommandsInternal() + private async ValueTask SendCommandsInternal() + { + while (_source is {IsCancellationRequested: false}) { - while (_source != null && !_source.IsCancellationRequested) + WebSocketCommand command = null; + try { - WebSocketCommand command = null; - try - { - _online.WaitOne(); - _commands.WaitOne(); + _online.WaitOne(); + _commands.WaitOne(); - if (_rateLimit.HasReachedRateLimit) + if (_rateLimit.HasReachedRateLimit) + { + DateTimeOffset reset = _rateLimit.NextReset(); + if (reset > DateTimeOffset.UtcNow) { - DateTimeOffset reset = _rateLimit.NextReset(); - if (reset > DateTimeOffset.UtcNow) - { - await reset.DelayUntil(_token).ConfigureAwait(false); - } - - continue; + await reset.DelayUntil(_token).ConfigureAwait(false); } + + continue; + } - command = GetNextCommand(); - if (command == null) - { - continue; - } + command = GetNextCommand(); + if (command == null) + { + continue; + } - //If the client has been disconnect don't run it's command - if (command.Client.Bot == null) - { - RemoveCommand(command); - continue; - } + //If the client has been disconnect don't run it's command + if (command.Client.Bot == null) + { + RemoveCommand(command); + continue; + } - if (!_rateLimit.CanFireRequest(command)) - { - _logger.Warning($"{nameof(WebSocketCommandHandler)}.{nameof(SendCommandsInternal)} Skipping websocket command for plugin {{0}} Exceeded Rate Limit of {{1}} Requests in {{2}} Seconds! Report this error to the plugin author.", command.Client.PluginName, WebsocketRateLimit.MaxRequestPerPlugin, WebsocketRateLimit.RateLimitInterval / 1000); - RemoveCommand(command); - continue; - } + if (!_rateLimit.CanFireRequest(command)) + { + _logger.Warning($"{nameof(WebSocketCommandHandler)}.{nameof(SendCommandsInternal)} Skipping websocket command for plugin {{0}} Exceeded Rate Limit of {{1}} Requests in {{2}} Seconds! Report this error to the plugin author.", command.Client.PluginName, WebsocketRateLimit.MaxRequestPerPlugin, WebsocketRateLimit.RateLimitInterval / 1000); + RemoveCommand(command); + continue; + } - _logger.Debug($"{nameof(WebSocketCommandHandler)}.{nameof(SendCommandsInternal)} {{0}} Sending Command {{1}}", command.Client.PluginName, command.Payload.OpCode); + _logger.Debug($"{nameof(WebSocketCommandHandler)}.{nameof(SendCommandsInternal)} {{0}} Sending Command {{1}}", command.Client.PluginName, command.Payload.OpCode); - _rateLimit.FiredRequest(command); + _rateLimit.FiredRequest(command); - await _webSocket.SendAsync(command.Payload).ConfigureAwait(false); + await _webSocket.SendAsync(command.Payload).ConfigureAwait(false); + RemoveCommand(command); + } + catch(OperationCanceledException) {} + catch (Exception ex) + { + _logger.Exception("An error occured sending commands", ex); + if (command != null) + { RemoveCommand(command); } - catch(OperationCanceledException) {} - catch (Exception ex) - { - _logger.Exception("An error occured sending commands", ex); - if (command != null) - { - RemoveCommand(command); - } - await Task.Delay(1000, _token).ConfigureAwait(false); - } - finally + await Task.Delay(1000, _token).ConfigureAwait(false); + } + finally + { + if (_isSocketReady) { - if (_isSocketReady) - { - _online.Set(); - } + _online.Set(); + } - if (!_pendingCommands.IsEmpty) - { - _commands.Set(); - } + if (!_pendingCommands.IsEmpty) + { + _commands.Set(); } } } + } - private WebSocketCommand GetNextCommand() + private WebSocketCommand GetNextCommand() + { + if (_isSocketReady && _pendingCommands.TryPeek(out WebSocketCommand command)) { - if (_isSocketReady && _pendingCommands.TryPeek(out WebSocketCommand command)) - { - return command; - } - - return null; + return command; } - private void RemoveCommand(WebSocketCommand command) - { - _pendingCommands.TryDequeue(out WebSocketCommand _); - command.Dispose(); - } + return null; + } - /// - /// Enqueue a payload to be sent over the websocket - /// If the websocket is connected it will be sent immediately - /// If the websocket is not connected it will be queued until it is back online - /// - /// Command to send over the websocket - public void Enqueue(WebSocketCommand command) - { - _logger.Debug($"{nameof(WebSocketCommandHandler)}.{nameof(Enqueue)} {{0}} Queuing command {{1}}", command.Client.PluginName, command.Payload.OpCode); - _pendingCommands.Enqueue(command); - _commands.Set(); - } + private void RemoveCommand(WebSocketCommand command) + { + _pendingCommands.TryDequeue(out WebSocketCommand _); + command.Dispose(); + } + + /// + /// Enqueue a payload to be sent over the websocket + /// If the websocket is connected it will be sent immediately + /// If the websocket is not connected it will be queued until it is back online + /// + /// Command to send over the websocket + public void Enqueue(WebSocketCommand command) + { + _logger.Debug($"{nameof(WebSocketCommandHandler)}.{nameof(Enqueue)} {{0}} Queuing command {{1}}", command.Client.PluginName, command.Payload.OpCode); + _pendingCommands.Enqueue(command); + _commands.Set(); + } - internal void OnWebSocketReady() - { - _logger.Debug($"{nameof(WebSocketCommandHandler)}.{nameof(OnWebSocketReady)} Socket Connected. Sending queued commands."); - _isSocketReady = true; - _online.Set(); - } + internal void OnWebSocketReady() + { + _logger.Debug($"{nameof(WebSocketCommandHandler)}.{nameof(OnWebSocketReady)} Socket Connected. Sending queued commands."); + _isSocketReady = true; + _online.Set(); + } - internal void OnSocketDisconnected() + internal void OnSocketDisconnected() + { + if (_isDisposed) { - if (_isDisposed) - { - return; - } - - _logger.Debug($"{nameof(WebSocketCommandHandler)}.{nameof(OnSocketDisconnected)} Socket Disconnected. Queuing Commands."); - _online.Reset(); - while (!_pendingCommands.IsEmpty) - { - _pendingCommands.TryDequeue(out WebSocketCommand _); - } - _isSocketReady = false; + return; } - - internal void OnSocketShutdown() + + _logger.Debug($"{nameof(WebSocketCommandHandler)}.{nameof(OnSocketDisconnected)} Socket Disconnected. Queuing Commands."); + _online.Reset(); + while (!_pendingCommands.IsEmpty) { - if (_isDisposed) - { - return; - } - - _isDisposed = true; - _online.Reset(); - _commands.Reset(); - _online?.Dispose(); - _commands?.Dispose(); - _source?.Cancel(); + _pendingCommands.TryDequeue(out WebSocketCommand _); } + _isSocketReady = false; + } - internal IReadOnlyCollection GetPendingCommands() + internal void OnSocketShutdown() + { + if (_isDisposed) { - return _pendingCommands; + return; } + + _isDisposed = true; + _online.Reset(); + _commands.Reset(); + _online?.Dispose(); + _commands?.Dispose(); + _source?.Cancel(); + } + + internal IReadOnlyCollection GetPendingCommands() + { + return _pendingCommands; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketHandler.cs b/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketHandler.cs index 0b97ad3d1..615f636f1 100644 --- a/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketHandler.cs +++ b/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketHandler.cs @@ -9,274 +9,273 @@ using Oxide.Ext.Discord.Json; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +/// +/// Handles the web socket connection and events +/// +internal class WebSocketHandler { - /// - /// Handles the web socket connection and events - /// - internal class WebSocketHandler - { - private readonly IWebSocketEventHandler _handler; - private readonly ILogger _logger; + private readonly IWebSocketEventHandler _handler; + private readonly ILogger _logger; - private readonly Memory _receiveBuffer; - private readonly Memory _sendBuffer; - private readonly AutoResetEvent _sendLock = new AutoResetEvent(true); + private readonly Memory _receiveBuffer; + private readonly Memory _sendBuffer; + private readonly AutoResetEvent _sendLock = new(true); - private DiscordWebsocketClient _client; - public SocketState SocketState => _client?.SocketState ?? SocketState.Disconnected; - public Snowflake WebsocketId => _client?.WebsocketId ?? default(Snowflake); + private DiscordWebsocketClient _client; + public SocketState SocketState => _client?.SocketState ?? SocketState.Disconnected; + public Snowflake WebsocketId => _client?.WebsocketId ?? default(Snowflake); - //private readonly ZlibDecompressorHandler _decompressor; + //private readonly ZlibDecompressorHandler _decompressor; - private const int SendChunkSize = 1024; - private const int ReceiveChunkSize = 2048; + private const int SendChunkSize = 1024; + private const int ReceiveChunkSize = 2048; - /// - /// Constructor - /// - /// Handles for web socket events - /// - public WebSocketHandler(IWebSocketEventHandler handler, ILogger logger) - { - _handler = handler; - _logger = logger; - _receiveBuffer = new byte[Math.Max(ReceiveChunkSize, SendChunkSize)]; - _sendBuffer = new byte[SendChunkSize]; - } + /// + /// Constructor + /// + /// Handles for web socket events + /// + public WebSocketHandler(IWebSocketEventHandler handler, ILogger logger) + { + _handler = handler; + _logger = logger; + _receiveBuffer = new byte[Math.Max(ReceiveChunkSize, SendChunkSize)]; + _sendBuffer = new byte[SendChunkSize]; + } - /// - /// Connects to the websocket at the given URL - /// - /// - /// - public void Connect(string url) + /// + /// Connects to the websocket at the given URL + /// + /// + /// + public void Connect(string url) + { + if (SocketState == SocketState.Connecting || SocketState == SocketState.Connected) { - if (SocketState == SocketState.Connecting || SocketState == SocketState.Connected) - { - throw new DiscordWebSocketException("Socket is already running. Please disconnect before attempting to connect."); - } + throw new DiscordWebSocketException("Socket is already running. Please disconnect before attempting to connect."); + } - DisposeSocket(); - _client = new DiscordWebsocketClient(_logger); + DisposeSocket(); + _client = new DiscordWebsocketClient(_logger); - Task.Factory.StartNew(RunInternal, url, _client.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); - } + Task.Factory.StartNew(RunInternal, url, _client.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); + } - private async void RunInternal(object url) - { - await RunWebsocket((string)url).ConfigureAwait(false); - } + private async void RunInternal(object url) + { + await RunWebsocket((string)url).ConfigureAwait(false); + } - private async ValueTask RunWebsocket(string url) + private async ValueTask RunWebsocket(string url) + { + DiscordWebsocketClient client = _client; + Snowflake id = client.WebsocketId; + try { - DiscordWebsocketClient client = _client; - Snowflake id = client.WebsocketId; - try - { - _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(Connect)} Connecting Websocket To: {{0}}", url); - await client.ConnectAsync(new Uri(url)).ConfigureAwait(false); - await _handler.SocketOpened(id).ConfigureAwait(false); - _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(Connect)} Websocket Connected"); - await ReceiveHandlerAsync(client).ConfigureAwait(false); - _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(Connect)} Websocket Disconnecting State: {{0}} Websocket: {{1}}", client.SocketState, client.WebSocketState); - if (client.SocketState == SocketState.Connected) - { - await client.CloseSocket(WebSocketCloseStatus.NormalClosure, "Websocket completed").ConfigureAwait(false); - DisposeSocket(); - } - } - catch (OperationCanceledException) + _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(Connect)} Connecting Websocket To: {{0}}", url); + await client.ConnectAsync(new Uri(url)).ConfigureAwait(false); + await _handler.SocketOpened(id).ConfigureAwait(false); + _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(Connect)} Websocket Connected"); + await ReceiveHandlerAsync(client).ConfigureAwait(false); + _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(Connect)} Websocket Disconnecting State: {{0}} Websocket: {{1}}", client.SocketState, client.WebSocketState); + if (client.SocketState == SocketState.Connected) { + await client.CloseSocket(WebSocketCloseStatus.NormalClosure, "Websocket completed").ConfigureAwait(false); DisposeSocket(); } - catch (WebSocketException ex) + } + catch (OperationCanceledException) + { + DisposeSocket(); + } + catch (WebSocketException ex) + { + DisposeSocket(); + if (ex.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely) { - DisposeSocket(); - if (ex.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely) - { - _logger.Verbose("Disconnected Socket Because: {0} Error Code: {1} HResult:{2}\n{3}", ex.WebSocketErrorCode, ex.ErrorCode, ex.HResult, ex); - await _handler.SocketClosed(id, WebSocketCloseStatus.NormalClosure, string.Empty).ConfigureAwait(false); - } - else - { - _logger.Debug("Disconnected Socket Because: {0} Error Code: {1} HResult:{2}\n{3}", ex.WebSocketErrorCode, ex.ErrorCode, ex.HResult, ex); - await _handler.SocketErrored(id, ex).ConfigureAwait(false); - } + _logger.Verbose("Disconnected Socket Because: {0} Error Code: {1} HResult:{2}\n{3}", ex.WebSocketErrorCode, ex.ErrorCode, ex.HResult, ex); + await _handler.SocketClosed(id, WebSocketCloseStatus.NormalClosure, string.Empty).ConfigureAwait(false); } - catch (Exception ex) + else { - DisposeSocket(); + _logger.Debug("Disconnected Socket Because: {0} Error Code: {1} HResult:{2}\n{3}", ex.WebSocketErrorCode, ex.ErrorCode, ex.HResult, ex); await _handler.SocketErrored(id, ex).ConfigureAwait(false); - _logger.Exception("A Unhandled Websocket Error Occured", ex); } } - - private async ValueTask ReceiveHandlerAsync(DiscordWebsocketClient client) + catch (Exception ex) { - DiscordJsonReader reader = new DiscordJsonReader(); - MemoryStream input = reader.Stream; - Memory array = _receiveBuffer; + DisposeSocket(); + await _handler.SocketErrored(id, ex).ConfigureAwait(false); + _logger.Exception("A Unhandled Websocket Error Occured", ex); + } + } + + private async ValueTask ReceiveHandlerAsync(DiscordWebsocketClient client) + { + DiscordJsonReader reader = new(); + MemoryStream input = reader.Stream; + Memory array = _receiveBuffer; - _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(ReceiveHandlerAsync)} Start Receive for {{0}}", client.WebsocketId); - while (!client.IsCancelRequested && client.WebSocketState == WebSocketState.Open && client.SocketState == SocketState.Connected) + _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(ReceiveHandlerAsync)} Start Receive for {{0}}", client.WebsocketId); + while (!client.IsCancelRequested && client.WebSocketState == WebSocketState.Open && client.SocketState == SocketState.Connected) + { + _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(ReceiveHandlerAsync)} Waiting to receive for {{0}} State: {{1}} Is Cancelled: {{2}}", client.WebsocketId, client.SocketState, client.IsCancelRequested); + ValueWebSocketReceiveResult result = await client.ReceiveAsync(array).ConfigureAwait(false); + if (client.Token.IsCancellationRequested) { - _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(ReceiveHandlerAsync)} Waiting to receive for {{0}} State: {{1}} Is Cancelled: {{2}}", client.WebsocketId, client.SocketState, client.IsCancelRequested); - ValueWebSocketReceiveResult result = await client.ReceiveAsync(array).ConfigureAwait(false); - if (client.Token.IsCancellationRequested) - { - return; - } + return; + } - await input.WriteAsync(array.Slice(0, result.Count), client.Token).ConfigureAwait(false); + await input.WriteAsync(array.Slice(0, result.Count), client.Token).ConfigureAwait(false); - if (result.EndOfMessage) + if (result.EndOfMessage) + { + try { - try - { - input.Position = 0; - await ProcessReceivedMessageAsync(client, result, reader).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.Exception("An error occured processing websocket message.", ex); - } - finally - { - input.SetLength(0); - } + input.Position = 0; + await ProcessReceivedMessageAsync(client, result, reader).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.Exception("An error occured processing websocket message.", ex); + } + finally + { + input.SetLength(0); } } } + } - private ValueTask ProcessReceivedMessageAsync(DiscordWebsocketClient client, ValueWebSocketReceiveResult result, DiscordJsonReader reader) - { - _logger.Verbose($"{nameof(WebSocketHandler)}.{nameof(ProcessReceivedMessageAsync)} Processing Receive Message For: {{0}} State: {{1}} Type: {{2}} Size: {{3}}", client.WebsocketId, client.SocketState, result.MessageType, reader.Stream.Length); + private ValueTask ProcessReceivedMessageAsync(DiscordWebsocketClient client, ValueWebSocketReceiveResult result, DiscordJsonReader reader) + { + _logger.Verbose($"{nameof(WebSocketHandler)}.{nameof(ProcessReceivedMessageAsync)} Processing Receive Message For: {{0}} State: {{1}} Type: {{2}} Size: {{3}}", client.WebsocketId, client.SocketState, result.MessageType, reader.Stream.Length); - if (client.WebSocketState == WebSocketState.CloseReceived && result.MessageType == WebSocketMessageType.Close) + if (client.WebSocketState == WebSocketState.CloseReceived && result.MessageType == WebSocketMessageType.Close) + { + if (client.SocketState != SocketState.Disconnected && client.SocketState != SocketState.Disconnecting) { - if (client.SocketState != SocketState.Disconnected && client.SocketState != SocketState.Disconnecting) - { - WebSocketCloseStatus closeStatus = client.CloseStatus ?? WebSocketCloseStatus.NormalClosure; - return DisconnectInternal(client, closeStatus, $"Websocket closed by Discord. {client.CloseStatusDescription}", true); - } - - return new ValueTask(); + WebSocketCloseStatus closeStatus = client.CloseStatus ?? WebSocketCloseStatus.NormalClosure; + return DisconnectInternal(client, closeStatus, $"Websocket closed by Discord. {client.CloseStatusDescription}", true); } - //_logger.Debug($"{nameof(WebSocketHandler)}.{nameof(ProcessReceivedMessage)} Invoke On Message: {{0}}", message); - return _handler.SocketMessage(client.WebsocketId, reader); + return new ValueTask(); } - /// - /// Sends the string message over the web socket - /// - /// Stream to send - public ValueTask SendAsync(MemoryStream stream) + //_logger.Debug($"{nameof(WebSocketHandler)}.{nameof(ProcessReceivedMessage)} Invoke On Message: {{0}}", message); + return _handler.SocketMessage(client.WebsocketId, reader); + } + + /// + /// Sends the string message over the web socket + /// + /// Stream to send + public ValueTask SendAsync(MemoryStream stream) + { + if (stream.Length == 0) + { + return new ValueTask(false); + } + + _sendLock.WaitOne(); + try { - if (stream.Length == 0) + DiscordWebsocketClient client = _client; + if (client == null || client.WebSocketState != WebSocketState.Open) { return new ValueTask(false); } - _sendLock.WaitOne(); - try - { - DiscordWebsocketClient client = _client; - if (client == null || client.WebSocketState != WebSocketState.Open) - { - return new ValueTask(false); - } - - return SendInternalAsync(_client, stream); - } - finally - { - _sendLock.Set(); - } + return SendInternalAsync(_client, stream); + } + finally + { + _sendLock.Set(); } + } - private async ValueTask SendInternalAsync(DiscordWebsocketClient client, MemoryStream stream) + private async ValueTask SendInternalAsync(DiscordWebsocketClient client, MemoryStream stream) + { + stream.Position = 0; + int readIndex = 0; + while (!client.IsCancelRequested) { - stream.Position = 0; - int readIndex = 0; - while (!client.IsCancelRequested) + int read = await stream.ReadAsync(_sendBuffer, client.Token).ConfigureAwait(false); + readIndex += read; + bool endOfMessage = readIndex == stream.Length; + //_logger.Debug($"{nameof(WebSocketHandler)}.{nameof(SendInternalAsync)} Sending Message Amount: {{0}} ({{1}}/{{2}}) Message: {{3}} - {{4}} End Of Message: {{5}}", read, readIndex, stream.Length, g, g.Length, endOfMessage); + await client.SendAsync(_sendBuffer.Slice(0, read), WebSocketMessageType.Text, endOfMessage).ConfigureAwait(false); + if (endOfMessage) { - int read = await stream.ReadAsync(_sendBuffer, client.Token).ConfigureAwait(false); - readIndex += read; - bool endOfMessage = readIndex == stream.Length; - //_logger.Debug($"{nameof(WebSocketHandler)}.{nameof(SendInternalAsync)} Sending Message Amount: {{0}} ({{1}}/{{2}}) Message: {{3}} - {{4}} End Of Message: {{5}}", read, readIndex, stream.Length, g, g.Length, endOfMessage); - await client.SendAsync(_sendBuffer.Slice(0, read), WebSocketMessageType.Text, endOfMessage).ConfigureAwait(false); - if (endOfMessage) - { - return true; - } + return true; } - - return false; } - /// - /// Disconnects from the websocket with the given code and reason - /// - /// Code to close with - /// Reason for the close - /// - public ValueTask Disconnect(int code, string reason) - { - return Disconnect((WebSocketCloseStatus)code, reason); - } + return false; + } + + /// + /// Disconnects from the websocket with the given code and reason + /// + /// Code to close with + /// Reason for the close + /// + public ValueTask Disconnect(int code, string reason) + { + return Disconnect((WebSocketCloseStatus)code, reason); + } - /// - /// Disconnects from the websocket with the given code and reason - /// - /// to close with - /// Reason for the close - /// - public ValueTask Disconnect(WebSocketCloseStatus status, string reason) - { - return DisconnectInternal(_client, status, reason, false); - } + /// + /// Disconnects from the websocket with the given code and reason + /// + /// to close with + /// Reason for the close + /// + public ValueTask Disconnect(WebSocketCloseStatus status, string reason) + { + return DisconnectInternal(_client, status, reason, false); + } - /// - /// Disconnects from the websocket with the given code and reason - /// - /// Client for the websockk - /// Status to close with - /// Reason for the close - /// If we received a close from the websocket - /// - private async ValueTask DisconnectInternal(DiscordWebsocketClient client, WebSocketCloseStatus status, string reason, bool closeReceived) - { - _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(Disconnect)} Status: {{0}} Reason: {{1}} Close Received: {{2}} Socket State: {{3}} Client State: {{4}} Cancel Requested {{5}}", - status, reason, closeReceived, client?.WebSocketState, client?.SocketState, client?.IsCancelRequested); + /// + /// Disconnects from the websocket with the given code and reason + /// + /// Client for the websocket + /// Status to close with + /// Reason for the close + /// If we received a close from the websocket + /// + private async ValueTask DisconnectInternal(DiscordWebsocketClient client, WebSocketCloseStatus status, string reason, bool closeReceived) + { + _logger.Debug($"{nameof(WebSocketHandler)}.{nameof(Disconnect)} Status: {{0}} Reason: {{1}} Close Received: {{2}} Socket State: {{3}} Client State: {{4}} Cancel Requested {{5}}", + status, reason, closeReceived, client?.WebSocketState, client?.SocketState, client?.IsCancelRequested); - if (client == null) - { - return; - } + if (client == null) + { + return; + } - Snowflake id = client.WebsocketId; + Snowflake id = client.WebsocketId; - try - { - if (client.SocketState == SocketState.Connected && !client.IsCancelRequested) - { - await client.CloseSocket(status, reason).ConfigureAwait(false); - DisposeSocket(); - await _handler.SocketClosed(id, status, reason).ConfigureAwait(false); - } - } - catch (Exception ex) + try + { + if (client.SocketState == SocketState.Connected && !client.IsCancelRequested) { - _logger.Exception("An error occured closing socket ID: {0}", id, ex); + await client.CloseSocket(status, reason).ConfigureAwait(false); + DisposeSocket(); + await _handler.SocketClosed(id, status, reason).ConfigureAwait(false); } } - - private void DisposeSocket() + catch (Exception ex) { - _client?.Dispose(); - _client = null; + _logger.Exception("An error occured closing socket ID: {0}", id, ex); } } + + private void DisposeSocket() + { + _client?.Dispose(); + _client = null; + } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketReconnectHandler.cs b/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketReconnectHandler.cs index 062a7072f..b85af835b 100644 --- a/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketReconnectHandler.cs +++ b/Oxide.Ext.Discord/WebSockets/Handlers/WebSocketReconnectHandler.cs @@ -5,129 +5,131 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +/// +/// Handles reconnecting to the web socket +/// +internal class WebSocketReconnectHandler { + internal readonly DiscordWebSocket WebSocket; + private readonly BotClient _client; + private readonly ILogger _logger; + private int _reconnectRetries; + private CancellationTokenSource _source; + + public bool IsPendingReconnect { get; private set; } + + internal bool AttemptGatewayUpdate => _reconnectRetries >= 3; + /// - /// Handles reconnecting to the web socket + /// Constructor /// - internal class WebSocketReconnectHandler + /// + /// + /// + public WebSocketReconnectHandler(BotClient client, DiscordWebSocket webSocket, ILogger logger) { - internal readonly DiscordWebSocket WebSocket; - private readonly BotClient _client; - private readonly ILogger _logger; - private int _reconnectRetries; - private CancellationTokenSource _source; - - public bool IsPendingReconnect { get; private set; } - - internal bool AttemptGatewayUpdate => _reconnectRetries >= 3; + _client = client; + WebSocket = webSocket; + _logger = logger; + } - /// - /// Constructor - /// - /// - /// - /// - public WebSocketReconnectHandler(BotClient client, DiscordWebSocket webSocket, ILogger logger) + /// + /// Starts the reconnect process + /// + public async ValueTask StartReconnect() + { + if (!_client.Initialized) { - _client = client; - WebSocket = webSocket; - _logger = logger; + _logger.Debug("Skipping reconnect. BotClient is not Initialized"); + return; } - /// - /// Starts the reconnect process - /// - public async ValueTask StartReconnect() + if (!WebSocket.IsDisconnected() && !WebSocket.IsDisconnecting()) { - if (!_client.Initialized) - { - _logger.Debug("Skipping reconnect. BotClient is not Initialized"); - return; - } - - if (!WebSocket.IsDisconnected() && !WebSocket.IsDisconnecting()) - { - _logger.Debug("Skipping reconnect. Websocket is not Disconnected or Disconnecting"); - return; - } - - if (IsPendingReconnect) - { - _logger.Debug("Skipping reconnect. Reconnect is already in progress."); - return; - } + _logger.Debug("Skipping reconnect. Websocket is not Disconnected or Disconnecting"); + return; + } - try - { - IsPendingReconnect = true; - CancelReconnect(); - _source = new CancellationTokenSource(); + if (IsPendingReconnect) + { + _logger.Debug("Skipping reconnect. Reconnect is already in progress."); + return; + } - int delay = GetReconnectDelay(); + try + { + IsPendingReconnect = true; + CancelReconnect(); + _source = new CancellationTokenSource(); - if (_reconnectRetries == 0) - { - _logger.Info("Reconnecting to Discord."); - } - else - { - _logger.Info("Reconnecting to Discord. Retry: #{0} Delay: {1}ms", _reconnectRetries, delay); - } + int delay = GetReconnectDelay(); - _reconnectRetries++; - await Task.Delay(delay, _source.Token).ConfigureAwait(false); - Connect(); - } - catch (OperationCanceledException) { } - catch (Exception ex) + if (_reconnectRetries == 0) { - _logger.Exception("An error occured during websocket reconnect", ex); + _logger.Info("Reconnecting to Discord."); } - finally + else { - IsPendingReconnect = false; + _logger.Info("Reconnecting to Discord. Retry: #{0} Delay: {1}ms", _reconnectRetries, delay); } + + _reconnectRetries++; + await Task.Delay(delay, _source.Token).ConfigureAwait(false); + Connect(); + } + catch (OperationCanceledException) { } + catch (Exception ex) + { + _logger.Exception("An error occured during websocket reconnect", ex); } + finally + { + IsPendingReconnect = false; + } + } - private void Connect() + private void Connect() + { + if (WebSocket.IsConnected() || WebSocket.IsConnecting()) { - if (WebSocket.IsConnected() || WebSocket.IsConnecting()) - { - _logger.Debug("Skipping Connect. Socket is: {0}", WebSocket.Handler.SocketState); - return; - } - - WebSocket.Connect(); + _logger.Debug("Skipping Connect. Socket is: {0}", WebSocket.Handler.SocketState); + return; } + + WebSocket.Connect(); + } - /// - /// Cancels the reconnect timer - /// - public void CancelReconnect() + /// + /// Cancels the reconnect timer + /// + public void CancelReconnect() + { + if (_source is {IsCancellationRequested: false}) { - if (_source != null && !_source.IsCancellationRequested) - { - _source.Cancel(); - } + _source.Cancel(); } + } - /// - /// Called when the websocket received a ready event from discord - /// - public void OnWebsocketReady() => _reconnectRetries = 0; + /// + /// Called when the websocket received a ready event from discord + /// + public void OnWebsocketReady() => _reconnectRetries = 0; - /// - /// Called when the bot is shutting down - /// - public void OnSocketShutdown() => CancelReconnect(); + /// + /// Called when the bot is shutting down + /// + public void OnSocketShutdown() => CancelReconnect(); - private int GetReconnectDelay() + private int GetReconnectDelay() + { + return _reconnectRetries switch { - if (_reconnectRetries == 0) return 1000 / 60; - if (_reconnectRetries <= 3) return 1 * 1000 + Core.Random.Range(100, 250); - if (_reconnectRetries <= 25) return 15 * 1000 + Core.Random.Range(250, 500); - return 60 * 1000 + Core.Random.Range(500, 1000); - } + 0 => 1000 / 60, + <= 3 => 1 * 1000 + Core.Random.Range(100, 250), + <= 25 => 15 * 1000 + Core.Random.Range(250, 500), + _ => 60 * 1000 + Core.Random.Range(500, 1000) + }; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/Handlers/WebsocketEventHandler.cs b/Oxide.Ext.Discord/WebSockets/Handlers/WebsocketEventHandler.cs index 52bdcdad6..046667888 100644 --- a/Oxide.Ext.Discord/WebSockets/Handlers/WebsocketEventHandler.cs +++ b/Oxide.Ext.Discord/WebSockets/Handlers/WebsocketEventHandler.cs @@ -15,1960 +15,1981 @@ using Oxide.Ext.Discord.Logging; using Oxide.Plugins; -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +/// +/// Handles websocket events +/// +public class WebSocketEventHandler : IWebSocketEventHandler { + private readonly BotClient _client; + private readonly DiscordWebSocket _webSocket; + private readonly ILogger _logger; + /// - /// Handles websocket events + /// Creates a new socket listener /// - public class WebSocketEventHandler : IWebSocketEventHandler + /// Client this listener is for + /// Socket this listener is for + /// Logger for the client + public WebSocketEventHandler(BotClient client, DiscordWebSocket socket, ILogger logger) { - private readonly BotClient _client; - private readonly DiscordWebSocket _webSocket; - private readonly ILogger _logger; - - /// - /// Creates a new socket listener - /// - /// Client this listener is for - /// Socket this listener is for - /// Logger for the client - public WebSocketEventHandler(BotClient client, DiscordWebSocket socket, ILogger logger) - { - _client = client; - _webSocket = socket; - _logger = logger; - } - - #region Socket Events - /// - /// Called when a socket is open - /// - public ValueTask SocketOpened(Snowflake websocketId) - { - _logger.Info("Discord socket connected!"); - _webSocket.OnSocketConnected(); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordWebsocketOpened); + _client = client; + _webSocket = socket; + _logger = logger; + } + + #region Socket Events + /// + /// Called when a socket is open + /// + public ValueTask SocketOpened(Snowflake websocketId) + { + _logger.Info("Discord socket connected!"); + _webSocket.OnSocketConnected(); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordWebsocketOpened); + return new ValueTask(); + } + + /// + /// Called when a socket is closed + /// + /// ID of the web socket + /// for the web socket + /// Close message from the web socket + public ValueTask SocketClosed(Snowflake websocketId, WebSocketCloseStatus status, string message) + { + //If the socket close came from the extension, then this will be true + if (!_webSocket.IsCurrentSocket(websocketId)) + { + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(SocketClosed)} Socket closed event for non matching socket. Code: {{0}}, reason: {{1}}", status, message); return new ValueTask(); } - /// - /// Called when a socket is closed - /// - /// ID of the web socket - /// for the web socket - /// Close message from the web socket - public ValueTask SocketClosed(Snowflake websocketId, WebSocketCloseStatus status, string message) + int code = (int)status; + if(code is >= 1000 and < 2000) { - //If the socket close came from the extension then this will be true - if (!_webSocket.IsCurrentSocket(websocketId)) - { - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(SocketClosed)} Socket closed event for non matching socket. Code: {{0}}, reason: {{1}}", status, message); - return new ValueTask(); - } - - int code = (int)status; - if(code >= 1000 && code < 2000) - { - if (status != WebSocketCloseStatus.NormalClosure) - { - _logger.Warning($"{nameof(WebSocketEventHandler)}.{nameof(SocketClosed)} Discord WebSocket closed. Code: {{1}}, reason: {{2}}", status, code, message); - } - else - { - _webSocket.ShouldReconnect = true; - } - } - else if (code >= 4000 && code < 5000) + if (status != WebSocketCloseStatus.NormalClosure) { - HandleDiscordClosedSocket(code, message); + _logger.Warning($"{nameof(WebSocketEventHandler)}.{nameof(SocketClosed)} Discord WebSocket closed. Code: {{1}}, reason: {{2}}", status, code, message); } else { - _logger.Warning("Discord WebSocket closed with abnormal close code. Code: {0}, reason: {1}", code, message); _webSocket.ShouldReconnect = true; - _logger.Debug($"{nameof(WebSocketEventHandler)}.{nameof(SocketClosed)} Discord WebSocket closed. Code: {{0}}, reason: {{1}}", code, message); } + } + else if (code is >= 4000 and < 5000) + { + HandleDiscordClosedSocket(code, message); + } + else + { + _logger.Warning("Discord WebSocket closed with abnormal close code. Code: {0}, reason: {1}", code, message); + _webSocket.ShouldReconnect = true; + _logger.Debug($"{nameof(WebSocketEventHandler)}.{nameof(SocketClosed)} Discord WebSocket closed. Code: {{0}}, reason: {{1}}", code, message); + } - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordWebsocketClosed, message, code); - _webSocket.OnSocketDisconnected(); - - if (_client.Initialized) - { - _webSocket.ReconnectIfRequested(); - } + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordWebsocketClosed, message, code); + _webSocket.OnSocketDisconnected(); - return new ValueTask(); + if (_client.Initialized) + { + _webSocket.ReconnectIfRequested(); } - /// - /// Parse out the closing reason if discord closed the socket - /// - /// Socket close code - /// Socket close reason - /// True if discord closed the socket with one of it's close codes - private void HandleDiscordClosedSocket(int code, string reason) + return new ValueTask(); + } + + /// + /// Parse out the closing reason if discord closed the socket + /// + /// Socket close code + /// Socket close reason + /// True if discord closed the socket with one of it's close codes + private void HandleDiscordClosedSocket(int code, string reason) + { + DiscordWebsocketCloseCode closeCode; + if (Enum.IsDefined(typeof(DiscordWebsocketCloseCode), code)) { - DiscordWebsocketCloseCode closeCode; - if (Enum.IsDefined(typeof(DiscordWebsocketCloseCode), code)) - { - closeCode = (DiscordWebsocketCloseCode)code; - } - else - { - closeCode = DiscordWebsocketCloseCode.UnknownCloseCode; - } + closeCode = (DiscordWebsocketCloseCode)code; + } + else + { + closeCode = DiscordWebsocketCloseCode.UnknownCloseCode; + } - bool shouldResume = false; - bool shouldReconnect = true; - switch (closeCode) - { - case DiscordWebsocketCloseCode.UnknownError: - _logger.Error("Unknown Discord error {0}", reason); - break; + bool shouldResume = false; + bool shouldReconnect = true; + switch (closeCode) + { + case DiscordWebsocketCloseCode.UnknownError: + _logger.Error("Unknown Discord error {0}", reason); + break; - case DiscordWebsocketCloseCode.UnknownOpcode: - _logger.Error("Unknown gateway opcode sent: {0}", reason); - break; + case DiscordWebsocketCloseCode.UnknownOpcode: + _logger.Error("Unknown gateway opcode sent: {0}", reason); + break; - case DiscordWebsocketCloseCode.DecodeError: - _logger.Error("Invalid gateway payload sent: {0}", reason); - break; + case DiscordWebsocketCloseCode.DecodeError: + _logger.Error("Invalid gateway payload sent: {0}", reason); + break; - case DiscordWebsocketCloseCode.NotAuthenticated: - _logger.Error("Tried to send a payload before identifying: {0}", reason); - break; + case DiscordWebsocketCloseCode.NotAuthenticated: + _logger.Error("Tried to send a payload before identifying: {0}", reason); + break; - case DiscordWebsocketCloseCode.AuthenticationFailed: - _logger.Error("The given bot token is invalid. Please enter a valid token. Token: {0} Plugins: {1} Reason: {2}", _client.Connection.HiddenToken, _client.GetClientPluginList(), reason); - shouldReconnect = false; - break; + case DiscordWebsocketCloseCode.AuthenticationFailed: + _logger.Error("The given bot token is invalid. Please enter a valid token. Token: {0} Plugins: {1} Reason: {2}", _client.Connection.HiddenToken, _client.GetClientPluginList(), reason); + shouldReconnect = false; + break; - case DiscordWebsocketCloseCode.AlreadyAuthenticated: - _logger.Error("The bot has already authenticated. Please don't identify more than once. Reason: {0} Plugins: {1}", reason, _client.GetClientPluginList()); - break; + case DiscordWebsocketCloseCode.AlreadyAuthenticated: + _logger.Error("The bot has already authenticated. Please don't identify more than once. Reason: {0} Plugins: {1}", reason, _client.GetClientPluginList()); + break; - case DiscordWebsocketCloseCode.InvalidSequence: - _logger.Error("Invalid resume sequence. Doing full reconnect. Reason {0}", reason); - break; + case DiscordWebsocketCloseCode.InvalidSequence: + _logger.Error("Invalid resume sequence. Doing full reconnect. Reason {0}", reason); + break; - case DiscordWebsocketCloseCode.RateLimited: - _logger.Error("You're being rate limited. Please slow down how quickly you're sending requests. Reason: {0} Plugins: {1}", reason, _client.GetClientPluginList()); - shouldResume = true; - break; + case DiscordWebsocketCloseCode.RateLimited: + _logger.Error("You're being rate limited. Please slow down how quickly you're sending requests. Reason: {0} Plugins: {1}", reason, _client.GetClientPluginList()); + shouldResume = true; + break; - case DiscordWebsocketCloseCode.SessionTimedOut: - _logger.Error("Session has timed out. Starting a new one: {0}", reason); - break; + case DiscordWebsocketCloseCode.SessionTimedOut: + _logger.Error("Session has timed out. Starting a new one: {0}", reason); + break; - case DiscordWebsocketCloseCode.InvalidShard: - _logger.Error("Invalid shared has been specified: {0}", reason); - shouldReconnect = false; - break; + case DiscordWebsocketCloseCode.InvalidShard: + _logger.Error("Invalid shared has been specified: {0}", reason); + shouldReconnect = false; + break; - case DiscordWebsocketCloseCode.ShardingRequired: - _logger.Error("Bot is in too many guilds. You must shard your bot: {0}", reason); - shouldReconnect = false; - break; + case DiscordWebsocketCloseCode.ShardingRequired: + _logger.Error("Bot is in too many guilds. You must shard your bot: {0}", reason); + shouldReconnect = false; + break; - case DiscordWebsocketCloseCode.InvalidApiVersion: - _logger.Error("Gateway is using invalid API version: {0}. Please contact Discord Extension Devs immediately!", Gateway.WebsocketUrl); - shouldReconnect = false; - break; + case DiscordWebsocketCloseCode.InvalidApiVersion: + _logger.Error("Gateway is using invalid API version: {0}. Please contact Discord Extension Devs immediately!", Gateway.WebsocketUrl); + shouldReconnect = false; + break; - case DiscordWebsocketCloseCode.InvalidIntents: - _logger.Error("Invalid intent(s) specified for the gateway. Please check that you're using valid intents in the connect. Plugins: {0}", _client.GetClientPluginList(), reason); - shouldReconnect = false; - break; + case DiscordWebsocketCloseCode.InvalidIntents: + _logger.Error("Invalid intent(s) specified for the gateway. Please check that you're using valid intents in the connect. Plugins: {0}", _client.GetClientPluginList(), reason); + shouldReconnect = false; + break; - case DiscordWebsocketCloseCode.DisallowedIntent: - DiscordClient client = _client.GetFirstClient(); - _logger.Warning("A plugin is asking for an intent you have not granted your bot. Attempting to update intents. Plugins: {0}", _client.GetClientPluginList()); - DiscordApplication.Get(client).Then(app => - { - ProcessGatewayIntents(app)? - .Then(updatedApp => - { - _client.Application.Flags = updatedApp.Flags; - _webSocket.Connect(); - }) - .Catch(err => _logger.Exception("An error occurred trying to update disallowed intents. Plugins: {0} Reason: {1}", _client.GetClientPluginList(), reason, err)); - }).Catch(err => _logger.Exception("An error occurred trying to correct disallowed intents. Plugins: {0} Reason: {1}", _client.GetClientPluginList(), reason, err)); - shouldReconnect = false; - break; + case DiscordWebsocketCloseCode.DisallowedIntent: + DiscordClient client = _client.GetFirstClient(); + _logger.Warning("A plugin is asking for an intent you have not granted your bot. Attempting to update intents. Plugins: {0}", _client.GetClientPluginList()); + DiscordApplication.Get(client).Then(app => + { + ProcessGatewayIntents(app)? + .Then(updatedApp => + { + _client.Application.Flags = updatedApp.Flags; + _webSocket.Connect(); + }) + .Catch(err => _logger.Exception("An error occurred trying to update disallowed intents. Plugins: {0} Reason: {1}", _client.GetClientPluginList(), reason, err)); + }).Catch(err => _logger.Exception("An error occurred trying to correct disallowed intents. Plugins: {0} Reason: {1}", _client.GetClientPluginList(), reason, err)); + shouldReconnect = false; + break; - case DiscordWebsocketCloseCode.UnknownCloseCode: - _logger.Error("Discord has closed the gateway with a code we do not recognize. Please Contact Discord Extension Authors. Code: {0}. Reason: {1}.", code, reason); - break; - } - - _webSocket.ShouldResume = shouldResume; - _webSocket.ShouldReconnect = shouldReconnect; + case DiscordWebsocketCloseCode.UnknownCloseCode: + _logger.Error("Discord has closed the gateway with a code we do not recognize. Please Contact Discord Extension Authors. Code: {0}. Reason: {1}.", code, reason); + break; } - /// - /// Called when an error occurs on a socket - /// - /// ID of the web socket - /// Exception throw - public ValueTask SocketErrored(Snowflake webSocketId, Exception ex) + _webSocket.ShouldResume = shouldResume; + _webSocket.ShouldReconnect = shouldReconnect; + } + + /// + /// Called when an error occurs on a socket + /// + /// ID of the web socket + /// Exception throw + public ValueTask SocketErrored(Snowflake webSocketId, Exception ex) + { + if (!_webSocket.IsCurrentSocket(webSocketId)) { - if (!_webSocket.IsCurrentSocket(webSocketId)) - { - return new ValueTask(); - } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordWebsocketErrored, ex, ex.Message); - _logger.Exception("An error has occured in the websocket. Attempting to reconnect to discord.", ex); - _webSocket.Disconnect(true, false); return new ValueTask(); } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordWebsocketErrored, ex, ex.Message); + _logger.Exception("An error has occured in the websocket. Attempting to reconnect to discord.", ex); + _webSocket.Disconnect(true, false); + return new ValueTask(); + } - /// - /// Called when a socket receives a message - /// - /// ID of the web socket - /// Json Reader containing the message - public async ValueTask SocketMessage(Snowflake webSocketId, DiscordJsonReader reader) - { - EventPayload payload = reader.Deserialize(_client.JsonSerializer); - _webSocket.OnSequenceUpdate(payload.Sequence); + /// + /// Called when a socket receives a message + /// + /// ID of the web socket + /// JSON Reader containing the message + public async ValueTask SocketMessage(Snowflake webSocketId, DiscordJsonReader reader) + { + EventPayload payload = reader.Deserialize(_client.JsonSerializer); + _webSocket.OnSequenceUpdate(payload.Sequence); - if (_logger.IsLogging(DiscordLogLevel.Verbose)) - { - _logger.Verbose("Received socket message, OpCode: {0} Payload: {1}", payload.OpCode, reader.ReadAsString()); - } - else - { - _logger.Debug("Received socket message, OpCode: {0}", payload.OpCode); - } - - try - { - switch (payload.OpCode) - { - // Dispatch (dispatches an event) - case GatewayEventCode.Dispatch: - HandleDispatch(payload); - break; - - // Heartbeat - // https://discord.com/developers/docs/topics/gateway#gateway-heartbeat - case GatewayEventCode.Heartbeat: - await HandleHeartbeat().ConfigureAwait(false); - break; - - // Reconnect (used to tell clients to reconnect to the gateway) - // we should immediately reconnect here - case GatewayEventCode.Reconnect: - HandleReconnect(); - break; - - // Invalid Session (used to notify client they have an invalid session ID) - case GatewayEventCode.InvalidSession: - HandleInvalidSession(payload.ShouldResume); - break; - - // Hello (sent immediately after connecting, contains heartbeat and server debug information) - case GatewayEventCode.Hello: - await HandleHello(payload).ConfigureAwait(false); - break; - - // Heartbeat ACK (sent immediately following a client heartbeat - // that was received) - // (See 'zombied or failed connections') - case GatewayEventCode.HeartbeatAcknowledge: - HandleHeartbeatAcknowledge(); - break; - } - } - catch (Exception ex) - { - _logger.Exception($"{nameof(WebSocketEventHandler)}.{nameof(SocketMessage)} Please give error message below to Discord Extension Authors. An error occured for: {payload.DispatchCode}.\nBody{reader.ReadAsString()}", ex); - } - finally - { - payload.Dispose(); - } + if (_logger.IsLogging(DiscordLogLevel.Verbose)) + { + _logger.Verbose("Received socket message, OpCode: {0} Payload: {1}", payload.OpCode, reader.ReadAsString()); } - #endregion - - #region Discord Events - private void HandleDispatch(EventPayload payload) + else { - _logger.Debug("Received OpCode: Dispatch, event: {0}", payload.DispatchCode); - - // Listed here: https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events - switch (payload.DispatchCode) + _logger.Debug("Received socket message, OpCode: {0}", payload.OpCode); + } + + try + { + switch (payload.OpCode) { - case DiscordDispatchCode.Ready: - HandleDispatchReady(payload.GetData(_client)); + // Dispatch (dispatches an event) + case GatewayEventCode.Dispatch: + HandleDispatch(payload); break; - case DiscordDispatchCode.Resumed: - HandleDispatchResumed(payload.GetData(_client)); + // Heartbeat + // https://discord.com/developers/docs/topics/gateway#gateway-heartbeat + case GatewayEventCode.Heartbeat: + await HandleHeartbeat().ConfigureAwait(false); break; - case DiscordDispatchCode.ChannelCreated: - HandleDispatchChannelCreate(payload.GetData(_client)); + // Reconnect (used to tell clients to reconnect to the gateway) + // we should immediately reconnect here + case GatewayEventCode.Reconnect: + HandleReconnect(); break; - case DiscordDispatchCode.ChannelUpdated: - HandleDispatchChannelUpdate(payload.GetData(_client)); + // Invalid Session (used to notify the client they have an invalid session ID) + case GatewayEventCode.InvalidSession: + HandleInvalidSession(payload.ShouldResume); break; - case DiscordDispatchCode.ChannelDeleted: - HandleDispatchChannelDelete(payload.GetData(_client)); + // Hello (sent immediately after connecting, contains heartbeat and server debug information) + case GatewayEventCode.Hello: + await HandleHello(payload).ConfigureAwait(false); break; - case DiscordDispatchCode.ChannelPinsUpdate: - HandleDispatchChannelPinUpdate(payload.GetData(_client)); + // Heartbeat ACK (sent immediately following a client heartbeat + // that was received) + // (See 'zombied or failed connections') + case GatewayEventCode.HeartbeatAcknowledge: + HandleHeartbeatAcknowledge(); break; + } + } + catch (Exception ex) + { + _logger.Exception($"{nameof(WebSocketEventHandler)}.{nameof(SocketMessage)} Please give error message below to Discord Extension Authors. An error occured for: {payload.DispatchCode}.\nBody{reader.ReadAsString()}", ex); + } + finally + { + payload.Dispose(); + } + } + #endregion + + #region Discord Events + private void HandleDispatch(EventPayload payload) + { + _logger.Debug("Received OpCode: Dispatch, event: {0}", payload.DispatchCode); + + // Listed here: https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events + switch (payload.DispatchCode) + { + case DiscordDispatchCode.Ready: + HandleDispatchReady(payload.GetData(_client)); + break; + + case DiscordDispatchCode.Resumed: + HandleDispatchResumed(payload.GetData(_client)); + break; + + case DiscordDispatchCode.ChannelCreated: + HandleDispatchChannelCreate(payload.GetData(_client)); + break; + + case DiscordDispatchCode.ChannelUpdated: + HandleDispatchChannelUpdate(payload.GetData(_client)); + break; + + case DiscordDispatchCode.ChannelDeleted: + HandleDispatchChannelDelete(payload.GetData(_client)); + break; + + case DiscordDispatchCode.ChannelPinsUpdate: + HandleDispatchChannelPinUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.EntitlementCreate: - HandleDispatchEntitlementCreate(payload.GetData(_client)); - break; + case DiscordDispatchCode.EntitlementCreate: + HandleDispatchEntitlementCreate(payload.GetData(_client)); + break; - case DiscordDispatchCode.EntitlementUpdate: - HandleDispatchEntitlementUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.EntitlementUpdate: + HandleDispatchEntitlementUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.EntitlementDelete: - HandleDispatchEntitlementDelete(payload.GetData(_client)); - break; + case DiscordDispatchCode.EntitlementDelete: + HandleDispatchEntitlementDelete(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildCreated: - HandleDispatchGuildCreate(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildCreated: + HandleDispatchGuildCreate(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildUpdated: - HandleDispatchGuildUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildUpdated: + HandleDispatchGuildUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildDeleted: - HandleDispatchGuildDelete(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildDeleted: + HandleDispatchGuildDelete(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildBanAdded: - HandleDispatchGuildBanAdd(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildBanAdded: + HandleDispatchGuildBanAdd(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildBanRemoved: - HandleDispatchGuildBanRemove(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildBanRemoved: + HandleDispatchGuildBanRemove(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildEmojisUpdated: - HandleDispatchGuildEmojisUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildEmojisUpdated: + HandleDispatchGuildEmojisUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildStickersUpdate: - HandleDispatchGuildStickersUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildStickersUpdate: + HandleDispatchGuildStickersUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildIntegrationsUpdated: - HandleDispatchGuildIntegrationsUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildIntegrationsUpdated: + HandleDispatchGuildIntegrationsUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildMemberAdded: - HandleDispatchGuildMemberAdd(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildMemberAdded: + HandleDispatchGuildMemberAdd(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildMemberRemoved: - HandleDispatchGuildMemberRemove(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildMemberRemoved: + HandleDispatchGuildMemberRemove(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildMemberUpdated: - HandleDispatchGuildMemberUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildMemberUpdated: + HandleDispatchGuildMemberUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildMembersChunk: - HandleDispatchGuildMembersChunk(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildMembersChunk: + HandleDispatchGuildMembersChunk(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildRoleCreated: - HandleDispatchGuildRoleCreate(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildRoleCreated: + HandleDispatchGuildRoleCreate(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildRoleUpdated: - HandleDispatchGuildRoleUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildRoleUpdated: + HandleDispatchGuildRoleUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildRoleDeleted: - HandleDispatchGuildRoleDelete(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildRoleDeleted: + HandleDispatchGuildRoleDelete(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildScheduledEventCreate: - HandleDispatchGuildScheduledEventCreate(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildScheduledEventCreate: + HandleDispatchGuildScheduledEventCreate(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildScheduledEventUpdate: - HandleDispatchGuildScheduledEventUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildScheduledEventUpdate: + HandleDispatchGuildScheduledEventUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildScheduledEventDelete: - HandleDispatchGuildScheduledEventDelete(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildScheduledEventDelete: + HandleDispatchGuildScheduledEventDelete(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildScheduledEventUserAdd: - HandleDispatchGuildScheduledEventUserAdd(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildScheduledEventUserAdd: + HandleDispatchGuildScheduledEventUserAdd(payload.GetData(_client)); + break; - case DiscordDispatchCode.GuildScheduledEventUserRemove: - HandleDispatchGuildScheduledEventUserRemove(payload.GetData(_client)); - break; + case DiscordDispatchCode.GuildScheduledEventUserRemove: + HandleDispatchGuildScheduledEventUserRemove(payload.GetData(_client)); + break; - case DiscordDispatchCode.IntegrationCreated: - HandleDispatchIntegrationCreate(payload.GetData(_client)); - break; + case DiscordDispatchCode.IntegrationCreated: + HandleDispatchIntegrationCreate(payload.GetData(_client)); + break; - case DiscordDispatchCode.IntegrationUpdated: - HandleDispatchIntegrationUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.IntegrationUpdated: + HandleDispatchIntegrationUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.IntegrationDeleted: - HandleDispatchIntegrationDelete(payload.GetData(_client)); - break; + case DiscordDispatchCode.IntegrationDeleted: + HandleDispatchIntegrationDelete(payload.GetData(_client)); + break; - case DiscordDispatchCode.MessageCreated: - HandleDispatchMessageCreate(payload.GetData(_client)); - break; + case DiscordDispatchCode.MessageCreated: + HandleDispatchMessageCreate(payload.GetData(_client)); + break; - case DiscordDispatchCode.MessageUpdated: - HandleDispatchMessageUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.MessageUpdated: + HandleDispatchMessageUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.MessageDeleted: - HandleDispatchMessageDelete(payload.GetData(_client)); - break; + case DiscordDispatchCode.MessageDeleted: + HandleDispatchMessageDelete(payload.GetData(_client)); + break; - case DiscordDispatchCode.MessageBulkDeleted: - HandleDispatchMessageDeleteBulk(payload.GetData(_client)); - break; + case DiscordDispatchCode.MessageBulkDeleted: + HandleDispatchMessageDeleteBulk(payload.GetData(_client)); + break; - case DiscordDispatchCode.MessageReactionAdded: - HandleDispatchMessageReactionAdd(payload.GetData(_client)); - break; + case DiscordDispatchCode.MessageReactionAdded: + HandleDispatchMessageReactionAdd(payload.GetData(_client)); + break; - case DiscordDispatchCode.MessageReactionRemoved: - HandleDispatchMessageReactionRemove(payload.GetData(_client)); - break; + case DiscordDispatchCode.MessageReactionRemoved: + HandleDispatchMessageReactionRemove(payload.GetData(_client)); + break; - case DiscordDispatchCode.MessageReactionAllRemoved: - HandleDispatchMessageReactionRemoveAll(payload.GetData(_client)); - break; + case DiscordDispatchCode.MessageReactionAllRemoved: + HandleDispatchMessageReactionRemoveAll(payload.GetData(_client)); + break; - case DiscordDispatchCode.MessageReactionEmojiRemoved: - HandleDispatchMessageReactionRemoveEmoji(payload.GetData(_client)); - break; + case DiscordDispatchCode.MessageReactionEmojiRemoved: + HandleDispatchMessageReactionRemoveEmoji(payload.GetData(_client)); + break; - case DiscordDispatchCode.PresenceUpdated: - HandleDispatchPresenceUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.PresenceUpdated: + HandleDispatchPresenceUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.TypingStarted: - HandleDispatchTypingStart(payload.GetData(_client)); - break; + case DiscordDispatchCode.TypingStarted: + HandleDispatchTypingStart(payload.GetData(_client)); + break; - case DiscordDispatchCode.UserUpdated: - HandleDispatchUserUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.UserUpdated: + HandleDispatchUserUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.VoiceStateUpdated: - HandleDispatchVoiceStateUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.VoiceStateUpdated: + HandleDispatchVoiceStateUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.VoiceServerUpdated: - HandleDispatchVoiceServerUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.VoiceServerUpdated: + HandleDispatchVoiceServerUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.WebhooksUpdated: - HandleDispatchWebhooksUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.WebhooksUpdated: + HandleDispatchWebhooksUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.InviteCreated: - HandleDispatchInviteCreate(payload.GetData(_client)); - break; + case DiscordDispatchCode.InviteCreated: + HandleDispatchInviteCreate(payload.GetData(_client)); + break; - case DiscordDispatchCode.InviteDeleted: - HandleDispatchInviteDelete(payload.GetData(_client)); - break; + case DiscordDispatchCode.InviteDeleted: + HandleDispatchInviteDelete(payload.GetData(_client)); + break; - case DiscordDispatchCode.ApplicationCommandsPermissionsUpdate: - HandleApplicationCommandsPermissionsUpdate(payload.GetData(_client)); - break; + case DiscordDispatchCode.ApplicationCommandsPermissionsUpdate: + HandleApplicationCommandsPermissionsUpdate(payload.GetData(_client)); + break; - case DiscordDispatchCode.InteractionCreated: - HandleDispatchInteractionCreate(payload.GetData(_client)); - break; + case DiscordDispatchCode.InteractionCreated: + HandleDispatchInteractionCreate(payload.GetData(_client)); + break; - case DiscordDispatchCode.ThreadCreated: - HandleDispatchThreadCreated(payload.GetData(_client)); - break; + case DiscordDispatchCode.ThreadCreated: + HandleDispatchThreadCreated(payload.GetData(_client)); + break; - case DiscordDispatchCode.ThreadUpdated: - HandleDispatchThreadUpdated(payload.GetData(_client)); - break; + case DiscordDispatchCode.ThreadUpdated: + HandleDispatchThreadUpdated(payload.GetData(_client)); + break; - case DiscordDispatchCode.ThreadDeleted: - HandleDispatchThreadDeleted(payload.GetData(_client)); - break; + case DiscordDispatchCode.ThreadDeleted: + HandleDispatchThreadDeleted(payload.GetData(_client)); + break; - case DiscordDispatchCode.ThreadListSync: - HandleDispatchThreadListSync(payload.GetData(_client)); - break; + case DiscordDispatchCode.ThreadListSync: + HandleDispatchThreadListSync(payload.GetData(_client)); + break; - case DiscordDispatchCode.ThreadMemberUpdated: - HandleDispatchThreadMemberUpdated(payload.GetData(_client)); - break; + case DiscordDispatchCode.ThreadMemberUpdated: + HandleDispatchThreadMemberUpdated(payload.GetData(_client)); + break; - case DiscordDispatchCode.ThreadMembersUpdated: - HandleDispatchThreadMembersUpdated(payload.GetData(_client)); - break; + case DiscordDispatchCode.ThreadMembersUpdated: + HandleDispatchThreadMembersUpdated(payload.GetData(_client)); + break; - case DiscordDispatchCode.StageInstanceCreated: - HandleDispatchStageInstanceCreated(payload.GetData(_client)); - break; + case DiscordDispatchCode.StageInstanceCreated: + HandleDispatchStageInstanceCreated(payload.GetData(_client)); + break; - case DiscordDispatchCode.StageInstanceUpdated: - HandleDispatchStageInstanceUpdated(payload.GetData(_client)); - break; + case DiscordDispatchCode.StageInstanceUpdated: + HandleDispatchStageInstanceUpdated(payload.GetData(_client)); + break; - case DiscordDispatchCode.StageInstanceDeleted: - HandleDispatchStageInstanceDeleted(payload.GetData(_client)); - break; + case DiscordDispatchCode.StageInstanceDeleted: + HandleDispatchStageInstanceDeleted(payload.GetData(_client)); + break; - case DiscordDispatchCode.AutoModerationRuleCreate: - HandleDispatchAutoModRuleCreated(payload.GetData(_client)); - break; + case DiscordDispatchCode.AutoModerationRuleCreate: + HandleDispatchAutoModRuleCreated(payload.GetData(_client)); + break; - case DiscordDispatchCode.AutoModerationRuleUpdate: - HandleDispatchAutoModRuleUpdated(payload.GetData(_client)); - break; + case DiscordDispatchCode.AutoModerationRuleUpdate: + HandleDispatchAutoModRuleUpdated(payload.GetData(_client)); + break; - case DiscordDispatchCode.AutoModerationRuleDelete: - HandleDispatchAutoModRuleDeleted(payload.GetData(_client)); - break; + case DiscordDispatchCode.AutoModerationRuleDelete: + HandleDispatchAutoModRuleDeleted(payload.GetData(_client)); + break; - case DiscordDispatchCode.AutoModerationActionExecution: - HandleDispatchAutoModActionExecuted(payload.GetData(_client)); - break; + case DiscordDispatchCode.AutoModerationActionExecution: + HandleDispatchAutoModActionExecuted(payload.GetData(_client)); + break; - // Bots should ignore this - case DiscordDispatchCode.PresenceReplace: - break; + case DiscordDispatchCode.MessagePollVoteAdded: + HandleDispatchMessagePollVoteAdded(payload.GetData(_client)); + break; - default: - HandleDispatchUnhandledEvent(payload); - break; - } + case DiscordDispatchCode.MessagePollVoteRemoved: + HandleDispatchMessagePollVoteRemoved(payload.GetData(_client)); + break; + + // Bots should ignore this + case DiscordDispatchCode.PresenceReplace: + break; + + default: + HandleDispatchUnhandledEvent(payload); + break; } - - //https://discord.com/developers/docs/topics/gateway-events#ready - private void HandleDispatchReady(GatewayReadyEvent ready) + } + + //https://discord.com/developers/docs/topics/gateway-events#ready + private void HandleDispatchReady(GatewayReadyEvent ready) + { + foreach (DiscordGuild guild in ready.Guilds.Values) { - foreach (DiscordGuild guild in ready.Guilds.Values) - { - _client.AddGuildOrUpdate(guild); - } + _client.AddGuildOrUpdate(guild); + } + + _webSocket.OnSocketReady(ready); + _client.OnClientReady(ready); + + _logger.Info("Your bot was found in {0} Guilds!", ready.Guilds.Count); + } + + private IPromise ProcessGatewayIntents(DiscordApplication app) + { + if (!DiscordConfig.Instance.Bot.AutomaticallyApplyGatewayIntents) + { + return null; + } - _webSocket.OnSocketReady(ready); - _client.OnClientReady(ready); + ApplicationFlags flags = app.Flags ?? ApplicationFlags.None; + if (_client.Connection.HasIntents(GatewayIntents.GuildMessages) && !app.HasAnyApplicationFlags(ApplicationFlags.GatewayMessageContentLimited | ApplicationFlags.GatewayMessageContent)) + { + _logger.Info("Applying GatewayMessageContent App Flag since it is currently disabled"); + flags |= ApplicationFlags.GatewayMessageContentLimited; + } - _logger.Info("Your bot was found in {0} Guilds!", ready.Guilds.Count); + if (!app.HasAnyApplicationFlags(ApplicationFlags.GatewayGuildMembersLimited | ApplicationFlags.GatewayGuildMembers)) + { + _logger.Info("Applying GatewayGuildMembers App Flag since it is currently disabled"); + flags |= ApplicationFlags.GatewayGuildMembersLimited; } - private IPromise ProcessGatewayIntents(DiscordApplication app) + if (flags != app.Flags) { - if (!DiscordConfig.Instance.Bot.AutomaticallyApplyGatewayIntents) + IPromise promise = app.Edit(_client.GetFirstClient(), new ApplicationUpdate { Flags = flags }); + promise.Then(_ => { - return null; - } - - ApplicationFlags flags = app.Flags ?? ApplicationFlags.None; - if (_client.Connection.HasIntents(GatewayIntents.GuildMessages) && !app.HasAnyApplicationFlags(ApplicationFlags.GatewayMessageContentLimited | ApplicationFlags.GatewayMessageContent)) + _logger.Info("Successfully Applied Application Flags: {0}", EnumCache.Instance.ToString(flags)); + }).Catch(error => { - _logger.Info("Applying GatewayMessageContent App Flag since it is currently disabled"); - flags |= ApplicationFlags.GatewayMessageContentLimited; - } + _logger.Error("An error occurred applying application flags: {0}\n{1}", EnumCache.Instance.ToString(flags), error.ResponseMessage); + }); + return promise; + } - if (!app.HasAnyApplicationFlags(ApplicationFlags.GatewayGuildMembersLimited | ApplicationFlags.GatewayGuildMembers)) - { - _logger.Info("Applying GatewayGuildMembers App Flag since it is currently disabled"); - flags |= ApplicationFlags.GatewayGuildMembersLimited; - } + return null; + } + + //https://discord.com/developers/docs/topics/gateway-events#resumed` + private void HandleDispatchResumed(GatewayResumedEvent resumed) + { + _logger.Debug("Session resumed successfully!"); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGatewayResumed, resumed); + } - if (flags != app.Flags) + //https://discord.com/developers/docs/topics/gateway-events#channel-create + private void HandleDispatchChannelCreate(DiscordChannel channel) + { + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchChannelCreate)}: ID: {{0}} Type: {{1}}. Guild ID: {{2}}", channel.Id, channel.Type, channel.GuildId); + + if (channel.IsDmChannel()) + { + _client.AddDirectChannel(channel); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectChannelCreated, channel); + } + else + { + DiscordGuild guild = _client.GetGuild(channel.GuildId); + if (guild is {IsAvailable: true}) { - IPromise promise = app.Edit(_client.GetFirstClient(), new ApplicationUpdate { Flags = flags }); - promise.Then(da => + if (channel.IsThreadChannel()) { - _logger.Info("Successfully Applied Application Flags: {0}", EnumCache.Instance.ToString(flags)); - }).Catch(error => + guild.Threads[channel.Id] = channel; + } + else { - _logger.Error("An error occurred applying application flags: {0}\n{1}", EnumCache.Instance.ToString(flags), error.ResponseMessage); - }); - return promise; - } + guild.Channels[channel.Id] = channel; + } - return null; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildChannelCreated, channel, guild); + } } + } - //https://discord.com/developers/docs/topics/gateway-events#resumed` - private void HandleDispatchResumed(GatewayResumedEvent resumed) - { - _logger.Debug("Session resumed successfully!"); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGatewayResumed, resumed); - } + //https://discord.com/developers/docs/topics/gateway-events#channel-update + private void HandleDispatchChannelUpdate(DiscordChannel update) + { + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchChannelUpdate)} ID: {{0}} Type: {{1}} Guild ID: {{2}}", update.Id, update.Type, update.GuildId); - //https://discord.com/developers/docs/topics/gateway-events#channel-create - private void HandleDispatchChannelCreate(DiscordChannel channel) + if (update.IsDmChannel()) { - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchChannelCreate)}: ID: {{0}} Type: {{1}}. Guild ID: {{2}}", channel.Id, channel.Type, channel.GuildId); - - if (channel.IsDmChannel()) + DiscordChannel channel = _client.GetChannel(update.Id, null); + if (channel == null) { - _client.AddDirectChannel(channel); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectChannelCreated, channel); + _client.AddDirectChannel(update); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectChannelUpdated, update, (DiscordChannel)null); } else { - DiscordGuild guild = _client.GetGuild(channel.GuildId); - if (guild != null && guild.IsAvailable) - { - if (channel.IsThreadChannel()) - { - guild.Threads[channel.Id] = channel; - } - else - { - guild.Channels[channel.Id] = channel; - } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildChannelCreated, channel, guild); - } + DiscordChannel previous = channel.Update(update); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectChannelUpdated, channel, previous); } } - - //https://discord.com/developers/docs/topics/gateway-events#channel-update - private void HandleDispatchChannelUpdate(DiscordChannel update) + else { - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchChannelUpdate)} ID: {{0}} Type: {{1}} Guild ID: {{2}}", update.Id, update.Type, update.GuildId); - - if (update.IsDmChannel()) + DiscordGuild guild = _client.GetGuild(update.GuildId); + if (guild is {IsAvailable: true}) { - DiscordChannel channel = _client.GetChannel(update.Id, null); - if (channel == null) - { - _client.AddDirectChannel(update); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectChannelUpdated, update, (DiscordChannel)null); - } - else + DiscordChannel channel = guild.GetChannel(update.Id); + if (channel != null) { DiscordChannel previous = channel.Update(update); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectChannelUpdated, channel, previous); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildChannelUpdated, channel, previous, guild); } - } - else - { - DiscordGuild guild = _client.GetGuild(update.GuildId); - if (guild != null && guild.IsAvailable) + else { - DiscordChannel channel = guild.GetChannel(update.Id); - if (channel != null) + if (update.IsThreadChannel()) { - DiscordChannel previous = channel.Update(update); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildChannelUpdated, channel, previous, guild); + guild.Threads[update.Id] = update; } else { - if (update.IsThreadChannel()) - { - guild.Threads[update.Id] = update; - } - else - { - guild.Channels[update.Id] = update; - } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildChannelUpdated, update, update, guild); + guild.Channels[update.Id] = update; } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildChannelUpdated, update, update, guild); } } } + } - //https://discord.com/developers/docs/topics/gateway-events#channel-delete - private void HandleDispatchChannelDelete(DiscordChannel channel) + //https://discord.com/developers/docs/topics/gateway-events#channel-delete + private void HandleDispatchChannelDelete(DiscordChannel channel) + { + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchChannelDelete)} ID: {{0}} Type: {{1}} Guild ID: {{2}}", channel.Id, channel.Type, channel.GuildId); + DiscordGuild guild = _client.GetGuild(channel.GuildId); + if (channel.IsDmChannel()) { - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchChannelDelete)} ID: {{0}} Type: {{1}} Guild ID: {{2}}", channel.Id, channel.Type, channel.GuildId); - DiscordGuild guild = _client.GetGuild(channel.GuildId); - if (channel.IsDmChannel()) - { - _client.RemoveDirectMessageChannel(channel.Id); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectChannelDeleted, channel); - } - else - { - guild.Channels.Remove(channel.Id); - guild.Threads.Remove(channel.Id); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildChannelDeleted, channel, guild); - } + _client.RemoveDirectMessageChannel(channel.Id); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectChannelDeleted, channel); } - - //https://discord.com/developers/docs/topics/gateway-events#channel-pins-update - private void HandleDispatchChannelPinUpdate(ChannelPinsUpdatedEvent pins) + else { - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchChannelPinUpdate)} Channel ID: {{0}} Guild ID: {{1}}", pins.GuildId, pins.GuildId); - - DiscordChannel channel = _client.GetChannel(pins.ChannelId, pins.GuildId); - if (pins.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(pins.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildChannelPinsUpdated, pins, channel, guild); - } - else - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectChannelPinsUpdated, pins, channel); - } + guild.Channels.Remove(channel.Id); + guild.Threads.Remove(channel.Id); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildChannelDeleted, channel, guild); } - - //https://discord.com/developers/docs/topics/gateway-events#entitlement-create - private void HandleDispatchEntitlementCreate(DiscordEntitlement entitlement) + } + + //https://discord.com/developers/docs/topics/gateway-events#channel-pins-update + private void HandleDispatchChannelPinUpdate(ChannelPinsUpdatedEvent pins) + { + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchChannelPinUpdate)} Channel ID: {{0}} Guild ID: {{1}}", pins.GuildId, pins.GuildId); + + DiscordChannel channel = _client.GetChannel(pins.ChannelId, pins.GuildId); + if (pins.GuildId.HasValue) { - DiscordGuild guild = _client.GetGuild(entitlement.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordEntitlementCreated, entitlement, guild); + DiscordGuild guild = _client.GetGuild(pins.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildChannelPinsUpdated, pins, channel, guild); } - - //https://discord.com/developers/docs/topics/gateway-events#entitlement-update - private void HandleDispatchEntitlementUpdate(DiscordEntitlement entitlement) + else { - DiscordGuild guild = _client.GetGuild(entitlement.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordEntitlementUpdated, entitlement, guild); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectChannelPinsUpdated, pins, channel); } + } + + //https://discord.com/developers/docs/topics/gateway-events#entitlement-create + private void HandleDispatchEntitlementCreate(DiscordEntitlement entitlement) + { + DiscordGuild guild = _client.GetGuild(entitlement.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordEntitlementCreated, entitlement, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#entitlement-update + private void HandleDispatchEntitlementUpdate(DiscordEntitlement entitlement) + { + DiscordGuild guild = _client.GetGuild(entitlement.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordEntitlementUpdated, entitlement, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#entitlement-delete + private void HandleDispatchEntitlementDelete(DiscordEntitlement entitlement) + { + DiscordGuild guild = _client.GetGuild(entitlement.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordEntitlementDeleted, entitlement, guild); + } - //https://discord.com/developers/docs/topics/gateway-events#entitlement-delete - private void HandleDispatchEntitlementDelete(DiscordEntitlement entitlement) + // NOTE: Some elements of Guild object is only sent with GUILD_CREATE + //https://discord.com/developers/docs/topics/gateway-events#guild-create + private void HandleDispatchGuildCreate(DiscordGuild guild) + { + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildCreate)} Guild ID: {{0}} Name: {{1}}", guild.Id, guild.Name); + + DiscordGuild existing = _client.GetGuild(guild.Id); + if (existing == null || !existing.IsAvailable && guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(entitlement.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordEntitlementDeleted, entitlement, guild); + _client.AddGuildOrUpdate(guild); + existing = _client.GetGuild(guild.Id); + existing.HasLoadedAllMembers = false; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildCreated, existing); } - // NOTE: Some elements of Guild object is only sent with GUILD_CREATE - //https://discord.com/developers/docs/topics/gateway-events#guild-create - private void HandleDispatchGuildCreate(DiscordGuild guild) + if (_client.Connection.HasIntents(GatewayIntents.GuildMembers)) { - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildCreate)} Guild ID: {{0}} Name: {{1}}", guild.Id, guild.Name); - - DiscordGuild existing = _client.GetGuild(guild.Id); - if (existing == null || !existing.IsAvailable && guild.IsAvailable) - { - _client.AddGuildOrUpdate(guild); - existing = _client.GetGuild(guild.Id); - existing.HasLoadedAllMembers = false; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildCreated, existing); - } - - if (_client.Connection.HasIntents(GatewayIntents.GuildMembers)) + if (!existing.HasLoadedAllMembers) { - if (!existing.HasLoadedAllMembers) + _client.GetFirstClient().RequestGuildMembers(new GuildMembersRequestCommand { - _client.GetFirstClient().RequestGuildMembers(new GuildMembersRequestCommand - { - Nonce = "DiscordExtension", - GuildId = guild.Id, - }); + Nonce = "DiscordExtension", + GuildId = guild.Id, + }); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildCreate)} Guild is now requesting all guild members."); - } + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildCreate)} Guild is now requesting all guild members."); } - else + } + else + { + if (_client.Servers.Values.All(value => value.IsAvailable)) { - if (_client.Servers.Values.All(value => value.IsAvailable)) - { - _client.OnBotFullyLoaded(); - } + _client.OnBotFullyLoaded(); } } + } - //https://discord.com/developers/docs/topics/gateway-events#guild-update - private void HandleDispatchGuildUpdate(DiscordGuild guild) - { - DiscordGuild previous =_client.GetGuild(guild.Id)?.Edit(guild); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildUpdated, guild, previous); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildUpdate)} Guild ID: {{0}}", guild.Id); - } + //https://discord.com/developers/docs/topics/gateway-events#guild-update + private void HandleDispatchGuildUpdate(DiscordGuild guild) + { + DiscordGuild previous =_client.GetGuild(guild.Id)?.Edit(guild); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildUpdated, guild, previous); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildUpdate)} Guild ID: {{0}}", guild.Id); + } - //https://discord.com/developers/docs/topics/gateway-events#guild-delete - private void HandleDispatchGuildDelete(DiscordGuild guild) + //https://discord.com/developers/docs/topics/gateway-events#guild-delete + private void HandleDispatchGuildDelete(DiscordGuild guild) + { + DiscordGuild existing = _client.GetGuild(guild.Id); + if (!guild.IsAvailable) // There is an outage with Discord { - DiscordGuild existing = _client.GetGuild(guild.Id); - if (!guild.IsAvailable) // There is an outage with Discord - { - if (existing != null) - { - existing.Unavailable = guild.Unavailable; - } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildUnavailable, existing ?? guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildDelete)} There is an outage with the guild. Guild ID: {{0}}", guild.Id); - } - else + if (existing != null) { - _client.RemoveGuild(guild.Id); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildDeleted, existing ?? guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildDelete)} Guild deleted or user removed from guild. Guild ID: {{0}} Name: {{1}}", guild.Id, existing?.Name ?? guild.Name); + existing.Unavailable = guild.Unavailable; } - } - //https://discord.com/developers/docs/topics/gateway-events#guild-ban-add - private void HandleDispatchGuildBanAdd(GuildMemberBannedEvent ban) + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildUnavailable, existing ?? guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildDelete)} There is an outage with the guild. Guild ID: {{0}}", guild.Id); + } + else { - DiscordGuild guild = _client.GetGuild(ban.GuildId); - - if (guild == null || !guild.IsAvailable) - { - return; - } - - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildBanAdd)} User was banned from the guild. Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}} User Name: {{3}}", ban.GuildId, guild.Name, ban.User.Id, ban.User.FullUserName); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberBanned, ban, guild); + _client.RemoveGuild(guild.Id); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildDeleted, existing ?? guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildDelete)} Guild deleted or user removed from guild. Guild ID: {{0}} Name: {{1}}", guild.Id, existing?.Name ?? guild.Name); } + } - //https://discord.com/developers/docs/topics/gateway-events#guild-ban-remove - private void HandleDispatchGuildBanRemove(GuildMemberBannedEvent ban) + //https://discord.com/developers/docs/topics/gateway-events#guild-ban-add + private void HandleDispatchGuildBanAdd(GuildMemberBannedEvent ban) + { + DiscordGuild guild = _client.GetGuild(ban.GuildId); + + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(ban.GuildId); + return; + } - if (guild == null || !guild.IsAvailable) - { - return; - } + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildBanAdd)} User was banned from the guild. Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}} User Name: {{3}}", ban.GuildId, guild.Name, ban.User.Id, ban.User.FullUserName); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberBanned, ban, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#guild-ban-remove + private void HandleDispatchGuildBanRemove(GuildMemberBannedEvent ban) + { + DiscordGuild guild = _client.GetGuild(ban.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberUnbanned, ban.User, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildBanRemove)} User was unbanned from the guild. Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}} User Name: {{3}}", ban.GuildId, guild.Name, ban.User.Id, ban.User.FullUserName); + if (guild == null || !guild.IsAvailable) + { + return; } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberUnbanned, ban.User, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildBanRemove)} User was unbanned from the guild. Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}} User Name: {{3}}", ban.GuildId, guild.Name, ban.User.Id, ban.User.FullUserName); + } - //https://discord.com/developers/docs/topics/gateway-events#guild-emojis-update - private void HandleDispatchGuildEmojisUpdate(GuildEmojisUpdatedEvent emojis) + //https://discord.com/developers/docs/topics/gateway-events#guild-emojis-update + private void HandleDispatchGuildEmojisUpdate(GuildEmojisUpdatedEvent emojis) + { + DiscordGuild guild = _client.GetGuild(emojis.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(emojis.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + return; + } - Hash previous = guild.Emojis.Clone(); + Hash previous = guild.Emojis.Clone(); - List removedEmojis = DiscordPool.Internal.GetList(); + List removedEmojis = DiscordPool.Internal.GetList(); - foreach (Snowflake id in guild.Emojis.Keys) + foreach (Snowflake id in guild.Emojis.Keys) + { + if (!emojis.Emojis.ContainsKey(id)) { - if (!emojis.Emojis.ContainsKey(id)) - { - removedEmojis.Add(id); - } + removedEmojis.Add(id); } + } - for (int index = 0; index < removedEmojis.Count; index++) - { - Snowflake id = removedEmojis[index]; - guild.Emojis.Remove(id); - } + for (int index = 0; index < removedEmojis.Count; index++) + { + Snowflake id = removedEmojis[index]; + guild.Emojis.Remove(id); + } - DiscordPool.Internal.FreeList(removedEmojis); + DiscordPool.Internal.FreeList(removedEmojis); - guild.Emojis.RemoveAll(e => e.EmojiId.HasValue && !emojis.Emojis.ContainsKey(e.EmojiId.Value)); + guild.Emojis.RemoveAll(e => e.EmojiId.HasValue && !emojis.Emojis.ContainsKey(e.EmojiId.Value)); - foreach (DiscordEmoji emoji in emojis.Emojis.Values) + foreach (DiscordEmoji emoji in emojis.Emojis.Values) + { + DiscordEmoji existing = guild.Emojis[emoji.Id]; + if (existing != null) { - DiscordEmoji existing = guild.Emojis[emoji.Id]; - if (existing != null) - { - existing.Update(emoji); - } - else - { - guild.Emojis[emoji.Id] = emoji; - } + existing.Update(emoji); + } + else + { + guild.Emojis[emoji.Id] = emoji; } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildEmojisUpdated, emojis, previous, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildEmojisUpdate)} Guild ID: {{0}} Guild Name: {{1}}", emojis.GuildId, guild.Name); } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildEmojisUpdated, emojis, previous, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildEmojisUpdate)} Guild ID: {{0}} Guild Name: {{1}}", emojis.GuildId, guild.Name); + } - //https://discord.com/developers/docs/topics/gateway-events#guild-stickers-update - private void HandleDispatchGuildStickersUpdate(GuildStickersUpdatedEvent stickers) - { - DiscordGuild guild = _client.GetGuild(stickers.GuildId); + //https://discord.com/developers/docs/topics/gateway-events#guild-stickers-update + private void HandleDispatchGuildStickersUpdate(GuildStickersUpdatedEvent stickers) + { + DiscordGuild guild = _client.GetGuild(stickers.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + if (guild == null || !guild.IsAvailable) + { + return; + } - Hash previous = guild.Stickers.Clone(); + Hash previous = guild.Stickers.Clone(); - List removedStickers = DiscordPool.Internal.GetList(); + List removedStickers = DiscordPool.Internal.GetList(); - foreach (Snowflake id in guild.Stickers.Keys) + foreach (Snowflake id in guild.Stickers.Keys) + { + if (!stickers.Stickers.ContainsKey(id)) { - if (!stickers.Stickers.ContainsKey(id)) - { - removedStickers.Add(id); - } + removedStickers.Add(id); } + } - for (int index = 0; index < removedStickers.Count; index++) - { - Snowflake id = removedStickers[index]; - guild.Emojis.Remove(id); - } + for (int index = 0; index < removedStickers.Count; index++) + { + Snowflake id = removedStickers[index]; + guild.Emojis.Remove(id); + } - DiscordPool.Internal.FreeList(removedStickers); + DiscordPool.Internal.FreeList(removedStickers); - guild.Emojis.RemoveAll(e => e.EmojiId.HasValue && !stickers.Stickers.ContainsKey(e.EmojiId.Value)); + guild.Emojis.RemoveAll(e => e.EmojiId.HasValue && !stickers.Stickers.ContainsKey(e.EmojiId.Value)); - foreach (DiscordSticker sticker in stickers.Stickers.Values) + foreach (DiscordSticker sticker in stickers.Stickers.Values) + { + DiscordSticker existing = guild.Stickers[sticker.Id]; + if (existing != null) { - DiscordSticker existing = guild.Stickers[sticker.Id]; - if (existing != null) - { - existing.Update(sticker); - } - else - { - guild.Stickers[sticker.Id] = sticker; - } + existing.Update(sticker); } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildStickersUpdated, stickers, previous, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildEmojisUpdate)} Guild ID: {{0}} Guild Name: {{1}}", stickers.GuildId, guild.Name); - } - - //https://discord.com/developers/docs/topics/gateway-events#guild-integrations-update - private void HandleDispatchGuildIntegrationsUpdate(GuildIntegrationsUpdatedEvent integration) - { - DiscordGuild guild = _client.GetGuild(integration.GuildId); - - if (guild == null || !guild.IsAvailable) + else { - return; + guild.Stickers[sticker.Id] = sticker; } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildIntegrationsUpdated, integration, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildIntegrationsUpdate)} Guild ID: {{0}} Guild Name: {{1}}", integration.GuildId, guild.Name); } - //https://discord.com/developers/docs/topics/gateway-events#guild-member-add - private void HandleDispatchGuildMemberAdd(GuildMemberAddedEvent member) + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildStickersUpdated, stickers, previous, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildEmojisUpdate)} Guild ID: {{0}} Guild Name: {{1}}", stickers.GuildId, guild.Name); + } + + //https://discord.com/developers/docs/topics/gateway-events#guild-integrations-update + private void HandleDispatchGuildIntegrationsUpdate(GuildIntegrationsUpdatedEvent integration) + { + DiscordGuild guild = _client.GetGuild(integration.GuildId); + + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(member.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + return; + } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildIntegrationsUpdated, integration, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildIntegrationsUpdate)} Guild ID: {{0}} Guild Name: {{1}}", integration.GuildId, guild.Name); + } - guild.LeftMembers.Remove(member.User.Id); - guild.Members[member.User.Id] = member; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberAdded, member, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildMemberAdd)} Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}} User Name: {{3}}", member.GuildId, guild.Name, member.User.Id, member.User.FullUserName); + //https://discord.com/developers/docs/topics/gateway-events#guild-member-add + private void HandleDispatchGuildMemberAdd(GuildMemberAddedEvent member) + { + DiscordGuild guild = _client.GetGuild(member.GuildId); + if (guild == null || !guild.IsAvailable) + { + return; } - //https://discord.com/developers/docs/topics/gateway-events#guild-member-remove - private void HandleDispatchGuildMemberRemove(GuildMemberRemovedEvent remove) + guild.LeftMembers.Remove(member.User.Id); + guild.Members[member.User.Id] = member; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberAdded, member, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildMemberAdd)} Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}} User Name: {{3}}", member.GuildId, guild.Name, member.User.Id, member.User.FullUserName); + } + + //https://discord.com/developers/docs/topics/gateway-events#guild-member-remove + private void HandleDispatchGuildMemberRemove(GuildMemberRemovedEvent remove) + { + DiscordGuild guild = _client.GetGuild(remove.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(remove.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + return; + } - GuildMember member = guild.Members[remove.User.Id]; - if (member == null) - { - return; - } - - member.HasLeftGuild = true; - guild.LeftMembers[remove.User.Id] = member; - guild.Members.Remove(remove.User.Id); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberRemoved, member, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildMemberRemove)} Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}} User Name: {{3}}", remove.GuildId, guild.Name, member.User.Id, member.User.FullUserName); + GuildMember member = guild.Members[remove.User.Id]; + if (member == null) + { + return; } - //https://discord.com/developers/docs/topics/gateway-events#guild-member-update - private void HandleDispatchGuildMemberUpdate(GuildMemberUpdatedEvent update) + member.HasLeftGuild = true; + guild.LeftMembers[remove.User.Id] = member; + guild.Members.Remove(remove.User.Id); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberRemoved, member, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildMemberRemove)} Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}} User Name: {{3}}", remove.GuildId, guild.Name, member.User.Id, member.User.FullUserName); + } + + //https://discord.com/developers/docs/topics/gateway-events#guild-member-update + private void HandleDispatchGuildMemberUpdate(GuildMemberUpdatedEvent update) + { + DiscordGuild guild = _client.GetGuild(update.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(update.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + return; + } - GuildMember current = guild.Members[update.Id]; - if (current == null) - { - current = update; - guild.Members[update.Id] = current; - } + GuildMember current = guild.Members[update.Id]; + if (current == null) + { + current = update; + guild.Members[update.Id] = current; + } - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberUpdated, update, current, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildMemberUpdate)} GUILD_MEMBER_UPDATE: Guild ID: {{0}} User ID: {{1}}", update.GuildId, update.User.Id); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberUpdated, update, current, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildMemberUpdate)} GUILD_MEMBER_UPDATE: Guild ID: {{0}} User ID: {{1}}", update.GuildId, update.User.Id); - if (current.Nickname != update.Nickname) - { - string oldNickname = current.Nickname; - current.Nickname = update.Nickname; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberNicknameUpdated, current, oldNickname, update.Nickname, current.NickNameLastUpdated, guild); - current.NickNameLastUpdated = DateTime.UtcNow; - } + if (current.Nickname != update.Nickname) + { + string oldNickname = current.Nickname; + current.Nickname = update.Nickname; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberNicknameUpdated, current, oldNickname, update.Nickname, current.NickNameLastUpdated, guild); + current.NickNameLastUpdated = DateTime.UtcNow; + } - if (current.Avatar != update.Avatar) - { - current.Avatar = update.Avatar; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberAvatarUpdated, current, current.Avatar, update.Avatar, guild); - } + if (current.Avatar != update.Avatar) + { + current.Avatar = update.Avatar; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberAvatarUpdated, current, current.Avatar, update.Avatar, guild); + } - if (current.Deaf != update.Deaf) - { - current.Deaf = update.Deaf; - _client.Hooks.CallHook(update.Deaf ? DiscordExtHooks.OnDiscordGuildMemberDeafened : DiscordExtHooks.OnDiscordGuildMemberUndeafened, current, guild); - } + if (current.Deaf != update.Deaf) + { + current.Deaf = update.Deaf; + _client.Hooks.CallHook(update.Deaf ? DiscordExtHooks.OnDiscordGuildMemberDeafened : DiscordExtHooks.OnDiscordGuildMemberUndeafened, current, guild); + } + + if (current.Mute != update.Mute) + { + current.Mute = update.Mute; + _client.Hooks.CallHook(update.Mute ? DiscordExtHooks.OnDiscordGuildMemberMuted : DiscordExtHooks.OnDiscordGuildMemberUnmuted, current, guild); + } - if (current.Mute != update.Mute) + if (current.CommunicationDisabledUntil != update.CommunicationDisabledUntil) + { + DateTime? previous = current.CommunicationDisabledUntil; + current.CommunicationDisabledUntil = update.CommunicationDisabledUntil; + if (previous.HasValue && !update.CommunicationDisabledUntil.HasValue) { - current.Mute = update.Mute; - _client.Hooks.CallHook(update.Mute ? DiscordExtHooks.OnDiscordGuildMemberMuted : DiscordExtHooks.OnDiscordGuildMemberUnmuted, current, guild); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberTimeoutEnded, current, guild); } - - if (current.CommunicationDisabledUntil != update.CommunicationDisabledUntil) + else if(!previous.HasValue && update.CommunicationDisabledUntil.HasValue) { - DateTime? previous = current.CommunicationDisabledUntil; - current.CommunicationDisabledUntil = update.CommunicationDisabledUntil; - if (previous.HasValue && !update.CommunicationDisabledUntil.HasValue) - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberTimeoutEnded, current, guild); - } - else if(!previous.HasValue && update.CommunicationDisabledUntil.HasValue) - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberTimeout, current, guild); - } + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberTimeout, current, guild); } + } - if (current.PremiumSince != update.PremiumSince) + if (current.PremiumSince != update.PremiumSince) + { + DateTime? previous = current.PremiumSince; + current.PremiumSince = update.PremiumSince; + if (!previous.HasValue && update.PremiumSince.HasValue) { - DateTime? previous = current.PremiumSince; - current.PremiumSince = update.PremiumSince; - if (!previous.HasValue && update.PremiumSince.HasValue) - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberBoosted, current, guild); - } - else if (previous.HasValue && current.PremiumSince.HasValue && current.PremiumSince.Value > DateTime.UtcNow) - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberBoostExtended, current, guild); - } - else if (previous.HasValue && !current.PremiumSince.HasValue) - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberBoostEnded, current, guild); - } + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberBoosted, current, guild); } - - for (int index = current.Roles.Count - 1; index >= 0; index--) + else if (previous.HasValue && current.PremiumSince.HasValue && current.PremiumSince.Value > DateTime.UtcNow) { - Snowflake role = current.Roles[index]; - if (!update.Roles.Contains(role)) - { - current.Roles.RemoveAt(index); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberRoleRemoved, current, role, guild); - } + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberBoostExtended, current, guild); } - - for (int index = update.Roles.Count - 1; index >= 0; index--) + else if (previous.HasValue && !current.PremiumSince.HasValue) { - Snowflake role = update.Roles[index]; - if (!current.Roles.Contains(role)) - { - current.Roles.Add(role); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberRoleAdded, current, role, guild); - } + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberBoostEnded, current, guild); } - - current.Flags = update.Flags; } - //https://discord.com/developers/docs/topics/gateway-events#guild-members-chunk - private void HandleDispatchGuildMembersChunk(GuildMembersChunkEvent chunk) + for (int index = current.Roles.Count - 1; index >= 0; index--) { - DiscordGuild guild = _client.GetGuild(chunk.GuildId); - - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildMembersChunk)}: Guild ID: {{0}} Guild Name: {{1}} Nonce: {{2}}", chunk.GuildId, guild?.Name, chunk.Nonce); - //Used to load all members in the discord server - if (chunk.Nonce == "DiscordExtension") + Snowflake role = current.Roles[index]; + if (!update.Roles.Contains(role)) { - if (guild == null || !guild.IsAvailable) - { - return; - } - - for (int index = 0; index < chunk.Members.Count; index++) - { - GuildMember member = chunk.Members[index]; - guild.Members.TryAdd(member.User.Id, member); - } - - //Once we've loaded all guild members call hook - if (chunk.ChunkIndex + 1 < chunk.ChunkCount) - { - return; - } - - guild.HasLoadedAllMembers = true; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMembersLoaded, guild); - if (_client.Servers.Values.All(s => s.HasLoadedAllMembers)) - { - _client.OnBotFullyLoaded(); - } - return; + current.Roles.RemoveAt(index); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberRoleRemoved, current, role, guild); } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMembersChunk, chunk, guild); } - - //https://discord.com/developers/docs/topics/gateway-events#guild-role-create - private void HandleDispatchGuildRoleCreate(GuildRoleCreatedEvent role) + + for (int index = update.Roles.Count - 1; index >= 0; index--) { - DiscordGuild guild = _client.GetGuild(role.GuildId); - - if (guild == null || !guild.IsAvailable) + Snowflake role = update.Roles[index]; + if (!current.Roles.Contains(role)) { - return; + current.Roles.Add(role); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberRoleAdded, current, role, guild); } - - guild.Roles[role.Role.Id] = role.Role; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildRoleCreated, role.Role, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildRoleCreate)} Guild ID: {{0}} Guild Name: {{1}} Role ID: {{2}} Role Name: {{3}}", role.GuildId, guild.Name, role.Role.Id, role.Role); } - //https://discord.com/developers/docs/topics/gateway-events#guild-role-update - private void HandleDispatchGuildRoleUpdate(GuildRoleUpdatedEvent update) + current.Flags = update.Flags; + } + + //https://discord.com/developers/docs/topics/gateway-events#guild-members-chunk + private void HandleDispatchGuildMembersChunk(GuildMembersChunkEvent chunk) + { + DiscordGuild guild = _client.GetGuild(chunk.GuildId); + + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildMembersChunk)}: Guild ID: {{0}} Guild Name: {{1}} Nonce: {{2}}", chunk.GuildId, guild?.Name, chunk.Nonce); + //Used to load all members in the discord server + if (chunk.Nonce == "DiscordExtension") { - DiscordRole updatedRole = update.Role; - DiscordGuild guild = _client.GetGuild(update.GuildId); - if (guild == null || !guild.IsAvailable) { return; } - - DiscordRole existing = guild.Roles[updatedRole.Id]; - if (existing == null) + + for (int index = 0; index < chunk.Members.Count; index++) { - return; + GuildMember member = chunk.Members[index]; + guild.Members.TryAdd(member.User.Id, member); } - - DiscordRole previous = existing.UpdateRole(updatedRole); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildRoleUpdated, updatedRole, previous, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildRoleUpdate)} Existing Guild ID: {{0}} Guild Name: {{1}} Role ID: {{2}} Role Name: {{3}}", update.GuildId, guild.Name, update.Role.Id, update.Role.Name); - } - - //https://discord.com/developers/docs/topics/gateway-events#guild-role-delete - private void HandleDispatchGuildRoleDelete(GuildRoleDeletedEvent delete) - { - DiscordGuild guild = _client.GetGuild(delete.GuildId); - if (guild == null || !guild.IsAvailable) + + //Once we've loaded all guild members call hook + if (chunk.ChunkIndex + 1 < chunk.ChunkCount) { return; } - - DiscordRole role = guild.Roles[delete.RoleId]; - if (role == null) + + guild.HasLoadedAllMembers = true; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMembersLoaded, guild); + if (_client.Servers.Values.All(s => s.HasLoadedAllMembers)) { - return; + _client.OnBotFullyLoaded(); } - - guild.Roles.Remove(delete.RoleId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildRoleDeleted, role, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildRoleDelete)} Guild ID: {{0}} Guild Name: {{1}} Role ID: {{2}}", delete.GuildId, guild.Name, delete.RoleId); + return; } - - //https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-create - private void HandleDispatchGuildScheduledEventCreate(GuildScheduledEvent guildEvent) + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMembersChunk, chunk, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#guild-role-create + private void HandleDispatchGuildRoleCreate(GuildRoleCreatedEvent role) + { + DiscordGuild guild = _client.GetGuild(role.GuildId); + + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(guildEvent.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + return; + } + + guild.Roles[role.Role.Id] = role.Role; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildRoleCreated, role.Role, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildRoleCreate)} Guild ID: {{0}} Guild Name: {{1}} Role ID: {{2}} Role Name: {{3}}", role.GuildId, guild.Name, role.Role.Id, role.Role); + } + + //https://discord.com/developers/docs/topics/gateway-events#guild-role-update + private void HandleDispatchGuildRoleUpdate(GuildRoleUpdatedEvent update) + { + DiscordRole updatedRole = update.Role; + DiscordGuild guild = _client.GetGuild(update.GuildId); - guild.ScheduledEvents[guild.Id] = guildEvent; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildScheduledEventCreated, guildEvent, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildScheduledEventCreate)} Guild ID: {{0}} Guild Name: {{1}} Scheduled Event ID: {{2}}", guildEvent.GuildId, guild.Name, guildEvent.Id); + if (guild == null || !guild.IsAvailable) + { + return; } - - //https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-update - private void HandleDispatchGuildScheduledEventUpdate(GuildScheduledEvent guildEvent) + + DiscordRole existing = guild.Roles[updatedRole.Id]; + if (existing == null) { - DiscordGuild guild = _client.GetGuild(guildEvent.GuildId); + return; + } + + DiscordRole previous = existing.UpdateRole(updatedRole); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildRoleUpdated, updatedRole, previous, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildRoleUpdate)} Existing Guild ID: {{0}} Guild Name: {{1}} Role ID: {{2}} Role Name: {{3}}", update.GuildId, guild.Name, update.Role.Id, update.Role.Name); + } - GuildScheduledEvent existing = guild?.ScheduledEvents[guildEvent.Id]; - if (existing == null) - { - return; - } + //https://discord.com/developers/docs/topics/gateway-events#guild-role-delete + private void HandleDispatchGuildRoleDelete(GuildRoleDeletedEvent delete) + { + DiscordGuild guild = _client.GetGuild(delete.GuildId); + if (guild == null || !guild.IsAvailable) + { + return; + } - existing.Update(guildEvent); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildScheduledEventUpdated, guildEvent, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildScheduledEventUpdate)} Guild ID: {{0}} Guild Name: {{1}} Scheduled Event ID: {{2}}", guildEvent.GuildId, guild.Name, guildEvent.Id); + DiscordRole role = guild.Roles[delete.RoleId]; + if (role == null) + { + return; } + + guild.Roles.Remove(delete.RoleId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildRoleDeleted, role, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildRoleDelete)} Guild ID: {{0}} Guild Name: {{1}} Role ID: {{2}}", delete.GuildId, guild.Name, delete.RoleId); + } - //https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-delete - private void HandleDispatchGuildScheduledEventDelete(GuildScheduledEvent guildEvent) + //https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-create + private void HandleDispatchGuildScheduledEventCreate(GuildScheduledEvent guildEvent) + { + DiscordGuild guild = _client.GetGuild(guildEvent.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(guildEvent.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } - - guild.ScheduledEvents.Remove(guildEvent.Id); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildScheduledEventDeleted, guildEvent, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildScheduledEventDelete)} Guild ID: {{0}} Guild Name: {{1}} Scheduled Event ID: {{2}}", guildEvent.GuildId, guild.Name, guildEvent.Id); + return; } + + guild.ScheduledEvents[guild.Id] = guildEvent; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildScheduledEventCreated, guildEvent, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildScheduledEventCreate)} Guild ID: {{0}} Guild Name: {{1}} Scheduled Event ID: {{2}}", guildEvent.GuildId, guild.Name, guildEvent.Id); + } - //https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-add - private void HandleDispatchGuildScheduledEventUserAdd(GuildScheduleEventUserAddedEvent added) + //https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-update + private void HandleDispatchGuildScheduledEventUpdate(GuildScheduledEvent guildEvent) + { + DiscordGuild guild = _client.GetGuild(guildEvent.GuildId); + + GuildScheduledEvent existing = guild?.ScheduledEvents[guildEvent.Id]; + if (existing == null) { - DiscordGuild guild = _client.GetGuild(added.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + return; + } - GuildScheduledEvent scheduledEvent = guild.ScheduledEvents[added.GuildScheduledEventId]; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildScheduledEventUserAdded, added, scheduledEvent, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildScheduledEventUserAdd)} Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}}", added.GuildId, guild.Name, added.UserId); + existing.Update(guildEvent); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildScheduledEventUpdated, guildEvent, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildScheduledEventUpdate)} Guild ID: {{0}} Guild Name: {{1}} Scheduled Event ID: {{2}}", guildEvent.GuildId, guild.Name, guildEvent.Id); + } + + //https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-delete + private void HandleDispatchGuildScheduledEventDelete(GuildScheduledEvent guildEvent) + { + DiscordGuild guild = _client.GetGuild(guildEvent.GuildId); + if (guild == null || !guild.IsAvailable) + { + return; } + + guild.ScheduledEvents.Remove(guildEvent.Id); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildScheduledEventDeleted, guildEvent, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildScheduledEventDelete)} Guild ID: {{0}} Guild Name: {{1}} Scheduled Event ID: {{2}}", guildEvent.GuildId, guild.Name, guildEvent.Id); + } - //https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-remove - private void HandleDispatchGuildScheduledEventUserRemove(GuildScheduleEventUserRemovedEvent removed) + //https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-add + private void HandleDispatchGuildScheduledEventUserAdd(GuildScheduleEventUserAddedEvent added) + { + DiscordGuild guild = _client.GetGuild(added.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(removed.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + return; + } - GuildScheduledEvent scheduledEvent = guild.ScheduledEvents[removed.GuildScheduledEventId]; - guild.ScheduledEvents.Remove(removed.GuildScheduledEventId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildScheduledEventUserRemoved, removed, scheduledEvent, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildScheduledEventUserRemove)} Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}}", removed.GuildId, guild.Name, removed.UserId); + GuildScheduledEvent scheduledEvent = guild.ScheduledEvents[added.GuildScheduledEventId]; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildScheduledEventUserAdded, added, scheduledEvent, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildScheduledEventUserAdd)} Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}}", added.GuildId, guild.Name, added.UserId); + } + + //https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-remove + private void HandleDispatchGuildScheduledEventUserRemove(GuildScheduleEventUserRemovedEvent removed) + { + DiscordGuild guild = _client.GetGuild(removed.GuildId); + if (guild == null || !guild.IsAvailable) + { + return; } + + GuildScheduledEvent scheduledEvent = guild.ScheduledEvents[removed.GuildScheduledEventId]; + guild.ScheduledEvents.Remove(removed.GuildScheduledEventId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildScheduledEventUserRemoved, removed, scheduledEvent, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchGuildScheduledEventUserRemove)} Guild ID: {{0}} Guild Name: {{1}} User ID: {{2}}", removed.GuildId, guild.Name, removed.UserId); + } - //https://discord.com/developers/docs/topics/gateway-events#integration-create - private void HandleDispatchIntegrationCreate(IntegrationCreatedEvent integration) + //https://discord.com/developers/docs/topics/gateway-events#integration-create + private void HandleDispatchIntegrationCreate(IntegrationCreatedEvent integration) + { + DiscordGuild guild = _client.GetGuild(integration.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(integration.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildIntegrationCreated, integration, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchIntegrationCreate)} Guild ID: {{0}} Guild Name: {{1}} Integration ID: {{2}}", integration.GuildId, guild.Name, integration.Id); + return; } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildIntegrationCreated, integration, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchIntegrationCreate)} Guild ID: {{0}} Guild Name: {{1}} Integration ID: {{2}}", integration.GuildId, guild.Name, integration.Id); + } - //https://discord.com/developers/docs/topics/gateway-events#integration-update - private void HandleDispatchIntegrationUpdate(IntegrationUpdatedEvent integration) + //https://discord.com/developers/docs/topics/gateway-events#integration-update + private void HandleDispatchIntegrationUpdate(IntegrationUpdatedEvent integration) + { + DiscordGuild guild = _client.GetGuild(integration.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(integration.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildIntegrationUpdated, integration, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchIntegrationUpdate)} Guild ID: {{0}} Guild Name: {{1}} Integration ID: {{2}}", integration.GuildId, guild.Name, integration.Id); + return; } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildIntegrationUpdated, integration, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchIntegrationUpdate)} Guild ID: {{0}} Guild Name: {{1}} Integration ID: {{2}}", integration.GuildId, guild.Name, integration.Id); + } - //https://discord.com/developers/docs/topics/gateway-events#integration-delete - private void HandleDispatchIntegrationDelete(IntegrationDeletedEvent integration) + //https://discord.com/developers/docs/topics/gateway-events#integration-delete + private void HandleDispatchIntegrationDelete(IntegrationDeletedEvent integration) + { + DiscordGuild guild = _client.GetGuild(integration.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(integration.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildIntegrationDeleted, integration, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchIntegrationDelete)} Guild ID: {{0}} Guild Name: {{1}} Integration ID: {{2}}", integration.GuildId, guild.Name, integration.Id); + return; } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildIntegrationDeleted, integration, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchIntegrationDelete)} Guild ID: {{0}} Guild Name: {{1}} Integration ID: {{2}}", integration.GuildId, guild.Name, integration.Id); + } - //https://discord.com/developers/docs/topics/gateway-events#message-create - private void HandleDispatchMessageCreate(DiscordMessage message) - { - DiscordGuild guild = _client.GetGuild(message.GuildId); - DiscordChannel channel = _client.GetChannel(message.ChannelId, message.GuildId); + //https://discord.com/developers/docs/topics/gateway-events#message-create + private void HandleDispatchMessageCreate(DiscordMessage message) + { + DiscordGuild guild = _client.GetGuild(message.GuildId); + DiscordChannel channel = _client.GetChannel(message.ChannelId, message.GuildId); - if (channel != null) + if (channel != null) + { + channel.LastMessageId = message.Id; + if (channel.Type == ChannelType.GuildPublicThread || channel.Type == ChannelType.GuildPrivateThread) { - channel.LastMessageId = message.Id; - if (channel.Type == ChannelType.GuildPublicThread || channel.Type == ChannelType.GuildPrivateThread) - { - channel.MessageCount = channel.MessageCount++ ?? 1; - channel.TotalMessageSent = channel.TotalMessageSent++ ?? 1; - } + channel.MessageCount = channel.MessageCount++ ?? 1; + channel.TotalMessageSent = channel.TotalMessageSent++ ?? 1; } + } - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageCreate)} Guild ID: {{0}} Channel ID: {{1}} Message ID: {{2}}", message.GuildId, message.ChannelId, message.Id); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageCreate)} Guild ID: {{0}} Channel ID: {{1}} Message ID: {{2}}", message.GuildId, message.ChannelId, message.Id); - if (!message.Author.Bot.HasValue || !message.Author.Bot.Value) + if (!message.Author.Bot.HasValue || !message.Author.Bot.Value) + { + if(!string.IsNullOrEmpty(message.Content) && DiscordCommand.Instance.HasCommands() && DiscordConfig.Instance.Commands.CommandPrefixes.Contains(message.Content[0])) { - if(!string.IsNullOrEmpty(message.Content) && DiscordCommand.Instance.HasCommands() && DiscordConfig.Instance.Commands.CommandPrefixes.Contains(message.Content[0])) - { - message.Content.TrimStart(DiscordConfig.Instance.Commands.CommandPrefixes).ParseCommand(out string command, out string[] args); - _logger.Debug($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageCreate)} Cmd: {{0}}", message.Content); + message.Content.TrimStart(DiscordConfig.Instance.Commands.CommandPrefixes).ParseCommand(out string command, out string[] args); + _logger.Debug($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageCreate)} Cmd: {{0}}", message.Content); - if (message.GuildId.HasValue && message.GuildId.Value.IsValid() && DiscordCommand.Instance.HandleGuildCommand(_client, message, channel, command, args)) - { - _logger.Debug($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageCreate)} Guild Handled Cmd: {{0}}", command); - return; - } - - if (!message.GuildId.HasValue && DiscordCommand.Instance.HandleDirectMessageCommand(_client, message, channel, command, args)) - { - _logger.Debug($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageCreate)} Direct Handled Cmd: {{0}}", command); - return; - } + if (message.GuildId.HasValue && message.GuildId.Value.IsValid() && DiscordCommand.Instance.HandleGuildCommand(_client, message, channel, command, args)) + { + _logger.Debug($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageCreate)} Guild Handled Cmd: {{0}}", command); + return; } - if (DiscordSubscriptions.Instance.HasSubscriptions() && channel != null && message.GuildId.HasValue) + if (!message.GuildId.HasValue && DiscordCommand.Instance.HandleDirectMessageCommand(_client, message, channel, command, args)) { - DiscordSubscriptions.Instance.HandleMessage(message, channel, _client); + _logger.Debug($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageCreate)} Direct Handled Cmd: {{0}}", command); + return; } } - if (message.GuildId.HasValue) - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageCreated, message, channel, guild); - } - else + if (DiscordSubscriptions.Instance.HasSubscriptions() && channel != null && message.GuildId.HasValue) { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageCreated, message, channel); + DiscordSubscriptions.Instance.HandleMessage(message, channel, _client); } } - //https://discord.com/developers/docs/topics/gateway-events#message-update - private void HandleDispatchMessageUpdate(DiscordMessage message) + if (message.GuildId.HasValue) { - DiscordChannel channel = _client.GetChannel(message.ChannelId, message.GuildId); - - if (message.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(message.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageUpdated, message, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageUpdate)} GuildMessage Guild ID: {{0}} Guild Name: {{1}} Channel ID: {{2}} Channel Name: {{3}} Message ID: {{4}}", message.GuildId, guild.Name, message.ChannelId, channel?.Name, message.Id); - } - else - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageUpdated, message, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageUpdate)} DirectMessage Message ID: {{0}} Channel ID: {{1}}", message.Id, message.ChannelId); - } + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageCreated, message, channel, guild); } + else + { + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageCreated, message, channel); + } + } - //https://discord.com/developers/docs/topics/gateway-events#message-delete - private void HandleDispatchMessageDelete(MessageDeletedEvent message) + //https://discord.com/developers/docs/topics/gateway-events#message-update + private void HandleDispatchMessageUpdate(DiscordMessage message) + { + DiscordChannel channel = _client.GetChannel(message.ChannelId, message.GuildId); + + if (message.GuildId.HasValue) + { + DiscordGuild guild = _client.GetGuild(message.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageUpdated, message, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageUpdate)} GuildMessage Guild ID: {{0}} Guild Name: {{1}} Channel ID: {{2}} Channel Name: {{3}} Message ID: {{4}}", message.GuildId, guild.Name, message.ChannelId, channel?.Name, message.Id); + } + else { - DiscordChannel channel = _client.GetChannel(message.ChannelId, message.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageUpdated, message, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageUpdate)} DirectMessage Message ID: {{0}} Channel ID: {{1}}", message.Id, message.ChannelId); + } + } - if (channel != null && (channel.Type == ChannelType.GuildPublicThread || channel.Type == ChannelType.GuildPrivateThread)) - { - channel.MessageCount = channel.MessageCount-- ?? 0; - } + //https://discord.com/developers/docs/topics/gateway-events#message-delete + private void HandleDispatchMessageDelete(MessageDeletedEvent message) + { + DiscordChannel channel = _client.GetChannel(message.ChannelId, message.GuildId); - if (message.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(message.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageDeleted, message, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageDelete)} GuildMessage Message ID: {{0}} Channel ID: {{1}} Channel Name: {{2}} Guild Id: {{3}} Guild Name: {{4}}", message.Id, message.ChannelId, channel?.Name, message.GuildId, guild.Name); - } - else - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageDeleted, message, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageDelete)} DirectMessage Message ID: {{0}} Channel ID: {{1}}", message.Id, message.ChannelId); - } + if (channel != null && (channel.Type == ChannelType.GuildPublicThread || channel.Type == ChannelType.GuildPrivateThread)) + { + channel.MessageCount = channel.MessageCount-- ?? 0; } - //https://discord.com/developers/docs/topics/gateway-events#message-delete-bulk - private void HandleDispatchMessageDeleteBulk(MessageBulkDeletedEvent bulkDelete) + if (message.GuildId.HasValue) + { + DiscordGuild guild = _client.GetGuild(message.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageDeleted, message, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageDelete)} GuildMessage Message ID: {{0}} Channel ID: {{1}} Channel Name: {{2}} Guild Id: {{3}} Guild Name: {{4}}", message.Id, message.ChannelId, channel?.Name, message.GuildId, guild.Name); + } + else { - DiscordChannel channel = _client.GetChannel(bulkDelete.ChannelId, bulkDelete.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageDeleted, message, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageDelete)} DirectMessage Message ID: {{0}} Channel ID: {{1}}", message.Id, message.ChannelId); + } + } + + //https://discord.com/developers/docs/topics/gateway-events#message-delete-bulk + private void HandleDispatchMessageDeleteBulk(MessageBulkDeletedEvent bulkDelete) + { + DiscordChannel channel = _client.GetChannel(bulkDelete.ChannelId, bulkDelete.GuildId); - if (channel != null && (channel.Type == ChannelType.GuildPublicThread || channel.Type == ChannelType.GuildPrivateThread)) - { - channel.MessageCount = channel.MessageCount - bulkDelete.Ids.Count ?? 0; - } + if (channel != null && (channel.Type == ChannelType.GuildPublicThread || channel.Type == ChannelType.GuildPrivateThread)) + { + channel.MessageCount = channel.MessageCount - bulkDelete.Ids.Count ?? 0; + } - if (bulkDelete.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(bulkDelete.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessagesBulkDeleted, bulkDelete.Ids, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageDeleteBulk)} Channel ID: {{0}} Channel Name: {{1}} Guild ID: {{2}} Guild Name: {{3}}", bulkDelete.ChannelId.Id, channel?.Name, bulkDelete.GuildId, guild.Name); - } - else - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessagesBulkDeleted, bulkDelete.Ids, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageDeleteBulk)} Channel ID: {{0}}", bulkDelete.ChannelId); - } + if (bulkDelete.GuildId.HasValue) + { + DiscordGuild guild = _client.GetGuild(bulkDelete.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessagesBulkDeleted, bulkDelete.Ids, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageDeleteBulk)} Channel ID: {{0}} Channel Name: {{1}} Guild ID: {{2}} Guild Name: {{3}}", bulkDelete.ChannelId.Id, channel?.Name, bulkDelete.GuildId, guild.Name); } - - //https://discord.com/developers/docs/topics/gateway-events#message-reaction-add - private void HandleDispatchMessageReactionAdd(MessageReactionAddedEvent reaction) + else { - DiscordChannel channel = _client.GetChannel(reaction.ChannelId, reaction.GuildId); - - if (reaction.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(reaction.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageReactionAdded, reaction, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionAdd)} GuildMessage Emoji: {{0}} Channel ID: {{1}} Channel Name: {{2}} Message ID: {{3}} User ID: {{4}} Guild ID: {{5}} Guild Name: {{6}}", reaction.Emoji.Name, reaction.ChannelId, channel.Name, reaction.MessageId, reaction.UserId, reaction.GuildId, guild.Name); - } - else - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageReactionAdded, reaction, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionAdd)} DirectMessage Emoji: {{0}} Channel ID: {{1}} Message ID: {{2}} User ID: {{3}}", reaction.Emoji.Name, reaction.ChannelId, reaction.MessageId, reaction.UserId); - } + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessagesBulkDeleted, bulkDelete.Ids, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageDeleteBulk)} Channel ID: {{0}}", bulkDelete.ChannelId); } + } + + //https://discord.com/developers/docs/topics/gateway-events#message-reaction-add + private void HandleDispatchMessageReactionAdd(MessageReactionAddedEvent reaction) + { + DiscordChannel channel = _client.GetChannel(reaction.ChannelId, reaction.GuildId); - //https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove - private void HandleDispatchMessageReactionRemove(MessageReactionRemovedEvent reaction) + if (reaction.GuildId.HasValue) { - DiscordChannel channel = _client.GetChannel(reaction.ChannelId, reaction.GuildId); - - if (reaction.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(reaction.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageReactionRemoved, reaction, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemove)} GuildMessage Emoji: {{0}} Channel ID: {{1}} Channel Name: {{2}} Message ID: {{3}} User ID: {{4}} Guild ID: {{5}} Guild Name: {{6}}", reaction.Emoji.Name, reaction.ChannelId, channel.Name, reaction.MessageId, reaction.UserId, reaction.GuildId, guild?.Name); - } - else - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageReactionRemoved, reaction, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemove)} DirectMessage Emoji: {{0}} Channel ID: {{1}} Message ID: {{2}} User ID: {{3}}", reaction.Emoji.Name, reaction.ChannelId, reaction.MessageId, reaction.UserId); - } + DiscordGuild guild = _client.GetGuild(reaction.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageReactionAdded, reaction, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionAdd)} GuildMessage Emoji: {{0}} Channel ID: {{1}} Channel Name: {{2}} Message ID: {{3}} User ID: {{4}} Guild ID: {{5}} Guild Name: {{6}}", reaction.Emoji.Name, reaction.ChannelId, channel.Name, reaction.MessageId, reaction.UserId, reaction.GuildId, guild.Name); } + else + { + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageReactionAdded, reaction, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionAdd)} DirectMessage Emoji: {{0}} Channel ID: {{1}} Message ID: {{2}} User ID: {{3}}", reaction.Emoji.Name, reaction.ChannelId, reaction.MessageId, reaction.UserId); + } + } + + //https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove + private void HandleDispatchMessageReactionRemove(MessageReactionRemovedEvent reaction) + { + DiscordChannel channel = _client.GetChannel(reaction.ChannelId, reaction.GuildId); - //https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-all - private void HandleDispatchMessageReactionRemoveAll(MessageReactionRemovedAllEvent reaction) + if (reaction.GuildId.HasValue) + { + DiscordGuild guild = _client.GetGuild(reaction.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageReactionRemoved, reaction, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemove)} GuildMessage Emoji: {{0}} Channel ID: {{1}} Channel Name: {{2}} Message ID: {{3}} User ID: {{4}} Guild ID: {{5}} Guild Name: {{6}}", reaction.Emoji.Name, reaction.ChannelId, channel.Name, reaction.MessageId, reaction.UserId, reaction.GuildId, guild?.Name); + } + else { - DiscordChannel channel = _client.GetChannel(reaction.ChannelId, reaction.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageReactionRemoved, reaction, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemove)} DirectMessage Emoji: {{0}} Channel ID: {{1}} Message ID: {{2}} User ID: {{3}}", reaction.Emoji.Name, reaction.ChannelId, reaction.MessageId, reaction.UserId); + } + } - if (reaction.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(reaction.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageReactionRemovedAll, reaction, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemoveAll)} GuildMessage Channel ID: {{0}} Channel Name: {{1}} Message ID: {{2}} Guild ID: {{3}} Guild Name: {{4}}", reaction.ChannelId, channel.Name, reaction.MessageId, reaction.GuildId, guild?.Name); - } - else - { + //https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-all + private void HandleDispatchMessageReactionRemoveAll(MessageReactionRemovedAllEvent reaction) + { + DiscordChannel channel = _client.GetChannel(reaction.ChannelId, reaction.GuildId); + + if (reaction.GuildId.HasValue) + { + DiscordGuild guild = _client.GetGuild(reaction.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageReactionRemovedAll, reaction, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemoveAll)} GuildMessage Channel ID: {{0}} Channel Name: {{1}} Message ID: {{2}} Guild ID: {{3}} Guild Name: {{4}}", reaction.ChannelId, channel.Name, reaction.MessageId, reaction.GuildId, guild?.Name); + } + else + { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageReactionRemovedAll, reaction, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemoveAll)} DirectMessage Channel ID: {{0}} Message ID: {{1}}", reaction.ChannelId, reaction.MessageId); - } - } + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageReactionRemovedAll, reaction, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemoveAll)} DirectMessage Channel ID: {{0}} Message ID: {{1}}", reaction.ChannelId, reaction.MessageId); + } + } - //https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-emoji - private void HandleDispatchMessageReactionRemoveEmoji(MessageReactionRemovedAllEmojiEvent reaction) - { - DiscordChannel channel = _client.GetChannel(reaction.ChannelId, reaction.GuildId); + //https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-emoji + private void HandleDispatchMessageReactionRemoveEmoji(MessageReactionRemovedAllEmojiEvent reaction) + { + DiscordChannel channel = _client.GetChannel(reaction.ChannelId, reaction.GuildId); - if (reaction.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(reaction.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageReactionEmojiRemoved, reaction, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemoveAll)} GuildMessage Emoji: {{0}} Channel ID: {{1}} Channel Name: {{2}} Message ID: {{3}} Guild ID: {{4}} Guild Name: {{5}}", reaction.Emoji.Name, reaction.ChannelId, channel.Name, reaction.MessageId, reaction.GuildId, guild.Name); - } - else - { + if (reaction.GuildId.HasValue) + { + DiscordGuild guild = _client.GetGuild(reaction.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMessageReactionEmojiRemoved, reaction, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemoveAll)} GuildMessage Emoji: {{0}} Channel ID: {{1}} Channel Name: {{2}} Message ID: {{3}} Guild ID: {{4}} Guild Name: {{5}}", reaction.Emoji.Name, reaction.ChannelId, channel.Name, reaction.MessageId, reaction.GuildId, guild.Name); + } + else + { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageReactionEmojiRemoved, reaction, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemoveAll)} DirectMessage Emoji: {{0}} Channel ID: {{1}} Message ID: {{2}}", reaction.Emoji.Name, reaction.ChannelId, reaction.MessageId); - } + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectMessageReactionEmojiRemoved, reaction, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchMessageReactionRemoveAll)} DirectMessage Emoji: {{0}} Channel ID: {{1}} Message ID: {{2}}", reaction.Emoji.Name, reaction.ChannelId, reaction.MessageId); } + } - /// - /// * From Discord API docs: - /// * The user object within this event can be partial, the only field which must be sent is the id field, everything else is optional. - /// * Along with this limitation, no fields are required, and the types of the fields are not validated. - /// * Your client should expect any combination of fields and types within this event - /// - /// - /// https://discord.com/developers/docs/topics/gateway#presence-update - private void HandleDispatchPresenceUpdate(PresenceUpdatedEvent update) - { - DiscordUser updateUser = update.User; + /// + /// * From Discord API docs: + /// * The user object within this event can be partial, the only field which must be sent is the id field, everything else is optional. + /// * Along with this limitation, no fields are required, and the types of the fields are not validated. + /// * Your client should expect any combination of fields and types within this event + /// + /// + /// https://discord.com/developers/docs/topics/gateway#presence-update + private void HandleDispatchPresenceUpdate(PresenceUpdatedEvent update) + { + DiscordUser updateUser = update.User; - DiscordGuild guild = _client.GetGuild(update.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + DiscordGuild guild = _client.GetGuild(update.GuildId); + if (guild == null || !guild.IsAvailable) + { + return; + } - GuildMember member = guild.Members[updateUser.Id]; - if (member == null) - { - return; - } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberPresenceUpdated, update, member, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchPresenceUpdate)} Guild ID: {{0}} User ID: {{1}} Status: {{2}}", update.GuildId, update.User.Id, update.Status); + GuildMember member = guild.Members[updateUser.Id]; + if (member == null) + { + return; } - //https://discord.com/developers/docs/topics/gateway-events#typing-start - private void HandleDispatchTypingStart(TypingStartedEvent typing) - { - DiscordChannel channel = _client.GetChannel(typing.ChannelId, typing.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildMemberPresenceUpdated, update, member, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchPresenceUpdate)} Guild ID: {{0}} User ID: {{1}} Status: {{2}}", update.GuildId, update.User.Id, update.Status); + } - if (typing.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(typing.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildTypingStarted, typing, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchTypingStart)} GuildChannel Channel ID: {{0}} Channel Name: {{1}} User ID: {{2}} Guild ID: {{3}} Guild Name: {{4}}", typing.ChannelId, channel.Name, typing.UserId, typing.GuildId, guild.Name); - } - else - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectTypingStarted, typing, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchTypingStart)} DirectChannel Channel ID: {{0}} User ID: {{1}}", typing.ChannelId, typing.UserId); - } - } + //https://discord.com/developers/docs/topics/gateway-events#typing-start + private void HandleDispatchTypingStart(TypingStartedEvent typing) + { + DiscordChannel channel = _client.GetChannel(typing.ChannelId, typing.GuildId); - //https://discord.com/developers/docs/topics/gateway-events#user-update - private void HandleDispatchUserUpdate(DiscordUser user) + if (typing.GuildId.HasValue) { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordUserUpdated, user); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchUserUpdate)} User ID: {{0}}", user.Id); + DiscordGuild guild = _client.GetGuild(typing.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildTypingStarted, typing, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchTypingStart)} GuildChannel Channel ID: {{0}} Channel Name: {{1}} User ID: {{2}} Guild ID: {{3}} Guild Name: {{4}}", typing.ChannelId, channel.Name, typing.UserId, typing.GuildId, guild.Name); } - - //https://discord.com/developers/docs/topics/gateway-events#voice-state-update - private void HandleDispatchVoiceStateUpdate(VoiceState voice) + else { - DiscordGuild guild = _client.GetGuild(voice.GuildId); - VoiceState existing = guild.VoiceStates[voice.UserId]; - DiscordChannel channel = voice.ChannelId.HasValue ? _client.GetChannel(voice.ChannelId.Value, voice.GuildId) : null; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectTypingStarted, typing, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchTypingStart)} DirectChannel Channel ID: {{0}} User ID: {{1}}", typing.ChannelId, typing.UserId); + } + } - if (existing != null) - { - existing.Update(voice); - voice = existing; - } - else - { - guild.VoiceStates[voice.UserId] = voice; - } + //https://discord.com/developers/docs/topics/gateway-events#user-update + private void HandleDispatchUserUpdate(DiscordUser user) + { + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordUserUpdated, user); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchUserUpdate)} User ID: {{0}}", user.Id); + } + + //https://discord.com/developers/docs/topics/gateway-events#voice-state-update + private void HandleDispatchVoiceStateUpdate(VoiceState voice) + { + DiscordGuild guild = _client.GetGuild(voice.GuildId); + VoiceState existing = guild.VoiceStates[voice.UserId]; + DiscordChannel channel = voice.ChannelId.HasValue ? _client.GetChannel(voice.ChannelId.Value, voice.GuildId) : null; + + if (existing != null) + { + existing.Update(voice); + voice = existing; + } + else + { + guild.VoiceStates[voice.UserId] = voice; + } - if (voice.GuildId.HasValue) - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildVoiceStateUpdated, voice, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchVoiceStateUpdate)} GuildChannel Guild ID: {{0}} Guild Name: {{1}} Channel ID: {{2}} Channel Name: {{3}} User ID: {{4}}", voice.GuildId, guild.Name, voice.ChannelId, channel?.Name, voice.UserId); - } - else - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectVoiceStateUpdated, voice, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchVoiceStateUpdate)} DirectChannel Channel ID: {{0}} User ID: {{1}}", voice.ChannelId, voice.UserId); - } + if (voice.GuildId.HasValue) + { + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildVoiceStateUpdated, voice, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchVoiceStateUpdate)} GuildChannel Guild ID: {{0}} Guild Name: {{1}} Channel ID: {{2}} Channel Name: {{3}} User ID: {{4}}", voice.GuildId, guild.Name, voice.ChannelId, channel?.Name, voice.UserId); } + else + { + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectVoiceStateUpdated, voice, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchVoiceStateUpdate)} DirectChannel Channel ID: {{0}} User ID: {{1}}", voice.ChannelId, voice.UserId); + } + } - //https://discord.com/developers/docs/topics/gateway-events#voice-server-update - private void HandleDispatchVoiceServerUpdate(VoiceServerUpdatedEvent voice) + //https://discord.com/developers/docs/topics/gateway-events#voice-server-update + private void HandleDispatchVoiceServerUpdate(VoiceServerUpdatedEvent voice) + { + DiscordGuild guild = _client.GetGuild(voice.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(voice.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildVoiceServerUpdated, voice, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchVoiceServerUpdate)} Guild ID: {{0}} Guild Name: {{1}}", voice.GuildId, guild.Name); + return; } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildVoiceServerUpdated, voice, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchVoiceServerUpdate)} Guild ID: {{0}} Guild Name: {{1}}", voice.GuildId, guild.Name); + } - //https://discord.com/developers/docs/topics/gateway-events#webhooks-update - private void HandleDispatchWebhooksUpdate(WebhooksUpdatedEvent webhook) + //https://discord.com/developers/docs/topics/gateway-events#webhooks-update + private void HandleDispatchWebhooksUpdate(WebhooksUpdatedEvent webhook) + { + DiscordGuild guild = _client.GetGuild(webhook.GuildId); + DiscordChannel channel = guild?.Channels[webhook.ChannelId]; + + if (channel == null) { - DiscordGuild guild = _client.GetGuild(webhook.GuildId); - DiscordChannel channel = guild?.Channels[webhook.ChannelId]; + return; + } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildWebhookUpdated, webhook, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchWebhooksUpdate)} Guild ID: {{0}} Guild Name {{1}} Channel ID: {{2}} Channel Name: {{3}}", webhook.GuildId, guild.Name, webhook.ChannelId, channel.Name); + } - if (channel == null) - { - return; - } + //https://discord.com/developers/docs/topics/gateway-events#invite-create + private void HandleDispatchInviteCreate(InviteCreatedEvent invite) + { + DiscordChannel channel = _client.GetChannel(invite.ChannelId, invite.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildWebhookUpdated, webhook, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchWebhooksUpdate)} Guild ID: {{0}} Guild Name {{1}} Channel ID: {{2}} Channel Name: {{3}}", webhook.GuildId, guild.Name, webhook.ChannelId, channel.Name); + if (invite.GuildId.HasValue) + { + DiscordGuild guild = _client.GetGuild(invite.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildInviteCreated, invite, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInviteCreate)} Guild Invite Guild ID: {{0}} Guild Name: {{1}} Channel ID: {{2}} Channel Name: {{3}} Code: {{4}}", invite.GuildId, guild?.Name, invite.ChannelId, channel?.Name, invite.Code); } - - //https://discord.com/developers/docs/topics/gateway-events#invite-create - private void HandleDispatchInviteCreate(InviteCreatedEvent invite) + else { - DiscordChannel channel = _client.GetChannel(invite.ChannelId, invite.GuildId); - - if (invite.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(invite.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildInviteCreated, invite, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInviteCreate)} Guild Invite Guild ID: {{0}} Guild Name: {{1}} Channel ID: {{2}} Channel Name: {{3}} Code: {{4}}", invite.GuildId, guild?.Name, invite.ChannelId, channel?.Name, invite.Code); - } - else - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectInviteCreated, invite, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInviteCreate)} Direct Invite Channel ID: {{0}} Code: {{1}}", invite.ChannelId, invite.Code); - } + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectInviteCreated, invite, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInviteCreate)} Direct Invite Channel ID: {{0}} Code: {{1}}", invite.ChannelId, invite.Code); } + } - //https://discord.com/developers/docs/topics/gateway-events#invite-delete - private void HandleDispatchInviteDelete(InviteDeletedEvent invite) - { - DiscordChannel channel = _client.GetChannel(invite.ChannelId, invite.GuildId); + //https://discord.com/developers/docs/topics/gateway-events#invite-delete + private void HandleDispatchInviteDelete(InviteDeletedEvent invite) + { + DiscordChannel channel = _client.GetChannel(invite.ChannelId, invite.GuildId); - if (invite.GuildId.HasValue) - { - DiscordGuild guild = _client.GetGuild(invite.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildInviteDeleted, invite, channel, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInviteDelete)} Guild ID: {{0}} Guild Name: {{1}} Channel ID: {{2}} Channel Name: {{3}} Code: {{4}}", invite.GuildId, guild.Name, invite.ChannelId,channel.Name, invite.Code); - } - else - { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectInviteDeleted, invite, channel); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInviteDelete)} Channel ID: {{0}} Code: {{1}}", invite.ChannelId, invite.Code); - } + if (invite.GuildId.HasValue) + { + DiscordGuild guild = _client.GetGuild(invite.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildInviteDeleted, invite, channel, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInviteDelete)} Guild ID: {{0}} Guild Name: {{1}} Channel ID: {{2}} Channel Name: {{3}} Code: {{4}}", invite.GuildId, guild.Name, invite.ChannelId,channel.Name, invite.Code); } - - //https://discord.com/developers/docs/topics/gateway-events#application-command-permissions-update - private void HandleApplicationCommandsPermissionsUpdate(CommandPermissions permissions) + else { - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordApplicationCommandPermissionsUpdated, permissions); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleApplicationCommandsPermissionsUpdate)} Permission ID: {{0}}", permissions.Id); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordDirectInviteDeleted, invite, channel); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInviteDelete)} Channel ID: {{0}} Code: {{1}}", invite.ChannelId, invite.Code); } + } - //https://discord.com/developers/docs/topics/gateway-events#interaction-create - private void HandleDispatchInteractionCreate(DiscordInteraction interaction) + //https://discord.com/developers/docs/topics/gateway-events#application-command-permissions-update + private void HandleApplicationCommandsPermissionsUpdate(CommandPermissions permissions) + { + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordApplicationCommandPermissionsUpdated, permissions); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleApplicationCommandsPermissionsUpdate)} Permission ID: {{0}}", permissions.Id); + } + + //https://discord.com/developers/docs/topics/gateway-events#interaction-create + private void HandleDispatchInteractionCreate(DiscordInteraction interaction) + { + if (DiscordAppCommand.Instance.HandleInteraction(interaction)) { - if (DiscordAppCommand.Instance.HandleInteraction(interaction)) - { - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInteractionCreate)} Handled. Guild ID: {{0}} Channel ID: {{1}} Interaction ID: {{2}}", interaction.GuildId, interaction.ChannelId, interaction.Id); - return; - } - - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInteractionCreate)} Unhandled. Guild ID: {{0}} Channel ID: {{1}} Interaction ID: {{2}}", interaction.GuildId, interaction.ChannelId, interaction.Id); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordInteractionCreated, interaction); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInteractionCreate)} Handled. Guild ID: {{0}} Channel ID: {{1}} Interaction ID: {{2}}", interaction.GuildId, interaction.ChannelId, interaction.Id); + return; } + + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchInteractionCreate)} Unhandled. Guild ID: {{0}} Channel ID: {{1}} Interaction ID: {{2}}", interaction.GuildId, interaction.ChannelId, interaction.Id); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordInteractionCreated, interaction); + } - //https://discord.com/developers/docs/topics/gateway-events#thread-create - private void HandleDispatchThreadCreated(DiscordChannel thread) + //https://discord.com/developers/docs/topics/gateway-events#thread-create + private void HandleDispatchThreadCreated(DiscordChannel thread) + { + if (!thread.GuildId.HasValue) { - if (!thread.GuildId.HasValue) - { - return; - } - - DiscordGuild guild = _client.GetGuild(thread.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + return; + } - guild.Threads[thread.Id] = thread; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadCreated, thread, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchThreadCreated)} Guild: {{0}}({{1}}) Thread: {{2}}({{3}})", guild.Name, guild.Id, thread.Name, thread.Id); + DiscordGuild guild = _client.GetGuild(thread.GuildId); + if (guild == null || !guild.IsAvailable) + { + return; } + + guild.Threads[thread.Id] = thread; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadCreated, thread, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchThreadCreated)} Guild: {{0}}({{1}}) Thread: {{2}}({{3}})", guild.Name, guild.Id, thread.Name, thread.Id); + } - //https://discord.com/developers/docs/topics/gateway-events#thread-update - private void HandleDispatchThreadUpdated(DiscordChannel thread) + //https://discord.com/developers/docs/topics/gateway-events#thread-update + private void HandleDispatchThreadUpdated(DiscordChannel thread) + { + if (!thread.GuildId.HasValue) { - if (!thread.GuildId.HasValue) - { - return; - } + return; + } - DiscordGuild guild = _client.GetGuild(thread.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + DiscordGuild guild = _client.GetGuild(thread.GuildId); + if (guild == null || !guild.IsAvailable) + { + return; + } - DiscordChannel existing = guild.Threads[thread.Id]; - if (existing != null) - { - DiscordChannel previous = existing.Update(thread); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadUpdated, thread, previous, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchThreadUpdated)} Existing Thread: {{0}}({{1}}) Thread: {{2}}({{3}})", guild.Name, guild.Id, thread.Name, thread.Id); - } - else - { - guild.Threads[thread.Id] = thread; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadUpdated, thread, thread, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchThreadUpdated)} New Thread: {{0}}({{1}}) Thread: {{2}}({{3}})", guild.Name, guild.Id, thread.Name, thread.Id); - } + DiscordChannel existing = guild.Threads[thread.Id]; + if (existing != null) + { + DiscordChannel previous = existing.Update(thread); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadUpdated, thread, previous, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchThreadUpdated)} Existing Thread: {{0}}({{1}}) Thread: {{2}}({{3}})", guild.Name, guild.Id, thread.Name, thread.Id); } - - //https://discord.com/developers/docs/topics/gateway-events#thread-delete - private void HandleDispatchThreadDeleted(DiscordChannel thread ) + else { - if (!thread.GuildId.HasValue) - { - return; - } - - DiscordGuild guild = _client.GetGuild(thread.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } - - thread = guild.Threads[thread.Id] ?? thread; - guild.Threads.Remove(thread.Id); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadDeleted, thread, guild); - _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchThreadDeleted)} Guild: {{0}}({{1}}) Thread: {{2}}({{3}})", guild.Name, guild.Id, thread.Name, thread.Id); + guild.Threads[thread.Id] = thread; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadUpdated, thread, thread, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchThreadUpdated)} New Thread: {{0}}({{1}}) Thread: {{2}}({{3}})", guild.Name, guild.Id, thread.Name, thread.Id); } + } - //https://discord.com/developers/docs/topics/gateway-events#thread-list-sync - private void HandleDispatchThreadListSync(ThreadListSyncEvent sync) + //https://discord.com/developers/docs/topics/gateway-events#thread-delete + private void HandleDispatchThreadDeleted(DiscordChannel thread ) + { + if (!thread.GuildId.HasValue) { - DiscordGuild guild = _client.GetGuild(sync.GuildId); - - //We clear all threads from the guild if ChannelIds is null or the ChannelId exists in ChannelIds - List deleteThreadIds = DiscordPool.Internal.GetList(); - foreach (DiscordChannel thread in guild.Threads.Values) - { - if (thread.ParentId.HasValue - && (sync.ChannelIds == null || sync.ChannelIds.Contains(thread.ParentId.Value)) - && !sync.Threads.ContainsKey(thread.Id)) - { - deleteThreadIds.Add(thread.Id); - } - } - - //Remove all threads who were in synced channels - foreach (Snowflake threadId in deleteThreadIds) - { - guild.Threads.Remove(threadId); - } + return; + } - DiscordPool.Internal.FreeList(deleteThreadIds); + DiscordGuild guild = _client.GetGuild(thread.GuildId); + if (guild == null || !guild.IsAvailable) + { + return; + } - //Add threads to the guild - foreach (DiscordChannel thread in sync.Threads.Values) - { - DiscordChannel existing = guild.Threads[thread.Id]; - if (existing != null) - { - existing.Update(thread); - existing.ThreadMembers.Clear(); - } - else - { - guild.Threads[thread.Id] = thread; - } - } + thread = guild.Threads[thread.Id] ?? thread; + guild.Threads.Remove(thread.Id); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadDeleted, thread, guild); + _logger.Verbose($"{nameof(WebSocketEventHandler)}.{nameof(HandleDispatchThreadDeleted)} Guild: {{0}}({{1}}) Thread: {{2}}({{3}})", guild.Name, guild.Id, thread.Name, thread.Id); + } - foreach (ThreadMember member in sync.Members) - { - if (member.Id.HasValue && member.UserId.HasValue) - { - DiscordChannel thread = guild.Threads[member.Id.Value]; - if (thread != null) - { - thread.ThreadMembers[member.UserId.Value] = member; - } - } - } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadListSynced, sync, guild); - } - - //https://discord.com/developers/docs/topics/gateway-events#thread-member-update - private void HandleDispatchThreadMemberUpdated(ThreadMemberUpdateEvent member) + //https://discord.com/developers/docs/topics/gateway-events#thread-list-sync + private void HandleDispatchThreadListSync(ThreadListSyncEvent sync) + { + DiscordGuild guild = _client.GetGuild(sync.GuildId); + + //We clear all threads from the guild if ChannelIds is null or the ChannelId exists in ChannelIds + List deleteThreadIds = DiscordPool.Internal.GetList(); + foreach (DiscordChannel thread in guild.Threads.Values) { - DiscordGuild guild = _client.GetGuild(member.GuildId); - if (guild == null || !guild.IsAvailable) + if (thread.ParentId.HasValue + && (sync.ChannelIds == null || sync.ChannelIds.Contains(thread.ParentId.Value)) + && !sync.Threads.ContainsKey(thread.Id)) { - return; + deleteThreadIds.Add(thread.Id); } + } - if (!member.Id.HasValue || !member.UserId.HasValue) - { - return; - } + //Remove all threads who were in synced channels + foreach (Snowflake threadId in deleteThreadIds) + { + guild.Threads.Remove(threadId); + } - DiscordChannel thread = guild.Threads[member.Id.Value]; - if (thread == null) - { - return; - } + DiscordPool.Internal.FreeList(deleteThreadIds); - ThreadMember existing = thread.ThreadMembers[member.UserId.Value]; + //Add threads to the guild + foreach (DiscordChannel thread in sync.Threads.Values) + { + DiscordChannel existing = guild.Threads[thread.Id]; if (existing != null) { - existing.Update(member); + existing.Update(thread); + existing.ThreadMembers.Clear(); } else { - thread.ThreadMembers[member.UserId.Value] = member; + guild.Threads[thread.Id] = thread; } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadMemberUpdated, member, thread, guild); } - - //https://discord.com/developers/docs/topics/gateway-events#thread-members-update - private void HandleDispatchThreadMembersUpdated(ThreadMembersUpdatedEvent members) - { - DiscordGuild guild = _client.GetGuild(members.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } - - DiscordChannel thread = guild.Threads[members.Id]; - if (thread == null) - { - return; - } - - if (members.AddedMembers != null) - { - for (int index = 0; index < members.AddedMembers.Count; index++) - { - ThreadMember member = members.AddedMembers[index]; - if (member.UserId.HasValue) - { - thread.ThreadMembers[member.UserId.Value] = member; - } - } - } - if (members.RemovedMemberIds != null) + foreach (ThreadMember member in sync.Members) + { + if (member.Id.HasValue && member.UserId.HasValue) { - for (int index = 0; index < members.RemovedMemberIds.Count; index++) + DiscordChannel thread = guild.Threads[member.Id.Value]; + if (thread != null) { - Snowflake memberId = members.RemovedMemberIds[index]; - thread.ThreadMembers.Remove(memberId); + thread.ThreadMembers[member.UserId.Value] = member; } } - - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadMembersUpdated, members, guild); } + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadListSynced, sync, guild); + } - //https://discord.com/developers/docs/topics/gateway-events#stage-instance-create - private void HandleDispatchStageInstanceCreated(StageInstance stage) + //https://discord.com/developers/docs/topics/gateway-events#thread-member-update + private void HandleDispatchThreadMemberUpdated(ThreadMemberUpdateEvent member) + { + DiscordGuild guild = _client.GetGuild(member.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(stage.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } - - guild.StageInstances[stage.Id] = stage; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordStageInstanceCreated, stage, guild); + return; } - //https://discord.com/developers/docs/topics/gateway-events#stage-instance-update - private void HandleDispatchStageInstanceUpdated(StageInstance stage) + if (!member.Id.HasValue || !member.UserId.HasValue) { - DiscordGuild guild = _client.GetGuild(stage.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } - - StageInstance existing = guild.StageInstances[stage.Id]; - if (existing == null) - { - guild.StageInstances[stage.Id] = stage; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordStageInstanceUpdated, stage, stage, guild); - } - else - { - StageInstance previous = existing.Edit(stage); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordStageInstanceUpdated, stage, previous, guild); - } + return; } - - //https://discord.com/developers/docs/topics/gateway-events#stage-instance-delete - private void HandleDispatchStageInstanceDeleted(StageInstance stage) + + DiscordChannel thread = guild.Threads[member.Id.Value]; + if (thread == null) { - DiscordGuild guild = _client.GetGuild(stage.GuildId); - if (guild == null || !guild.IsAvailable) - { - return; - } + return; + } - StageInstance existing = guild.StageInstances[stage.Id]; - guild.StageInstances.Remove(stage.Id); - guild.StageInstances[stage.Id] = stage; - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordStageInstanceDeleted, existing ?? stage, guild); + ThreadMember existing = thread.ThreadMembers[member.UserId.Value]; + if (existing != null) + { + existing.Update(member); } - - //https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-create - private void HandleDispatchAutoModRuleCreated(AutoModRule rule) + else { - DiscordGuild guild = _client.GetGuild(rule.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordAutoModRuleCreated, rule, guild); + thread.ThreadMembers[member.UserId.Value] = member; } - - //https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-update - private void HandleDispatchAutoModRuleUpdated(AutoModRule rule) + + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadMemberUpdated, member, thread, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#thread-members-update + private void HandleDispatchThreadMembersUpdated(ThreadMembersUpdatedEvent members) + { + DiscordGuild guild = _client.GetGuild(members.GuildId); + if (guild == null || !guild.IsAvailable) { - DiscordGuild guild = _client.GetGuild(rule.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordAutoModRuleUpdated, rule, guild); + return; } - - //https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-delete - private void HandleDispatchAutoModRuleDeleted(AutoModRule rule) + + DiscordChannel thread = guild.Threads[members.Id]; + if (thread == null) { - DiscordGuild guild = _client.GetGuild(rule.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordAutoModRuleDeleted, rule, guild); + return; } - - //https://discord.com/developers/docs/topics/gateway-events#auto-moderation-action-execution - private void HandleDispatchAutoModActionExecuted(AutoModActionExecutionEvent action) + + if (members.AddedMembers != null) { - DiscordGuild guild = _client.GetGuild(action.GuildId); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordAutoModActionExecuted, action, guild); + for (int index = 0; index < members.AddedMembers.Count; index++) + { + ThreadMember member = members.AddedMembers[index]; + if (member.UserId.HasValue) + { + thread.ThreadMembers[member.UserId.Value] = member; + } + } } - private void HandleDispatchUnhandledEvent(EventPayload payload) + if (members.RemovedMemberIds != null) { - _logger.Verbose("Unhandled Dispatch Event: {0}.\n{1}", payload.DispatchCode, payload.Data); - _client.Hooks.CallHook(DiscordExtHooks.OnDiscordUnhandledCommand, payload); + for (int index = 0; index < members.RemovedMemberIds.Count; index++) + { + Snowflake memberId = members.RemovedMemberIds[index]; + thread.ThreadMembers.Remove(memberId); + } } - //https://discord.com/developers/docs/topics/gateway-events#heartbeat - private ValueTask HandleHeartbeat() + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordGuildThreadMembersUpdated, members, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#stage-instance-create + private void HandleDispatchStageInstanceCreated(StageInstance stage) + { + DiscordGuild guild = _client.GetGuild(stage.GuildId); + if (guild == null || !guild.IsAvailable) { - _logger.Debug("Manually sent heartbeat (received opcode 1)"); - return _webSocket.SendHeartbeat(); + return; } + + guild.StageInstances[stage.Id] = stage; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordStageInstanceCreated, stage, guild); + } - //https://discord.com/developers/docs/topics/gateway-events#reconnect - private void HandleReconnect() + //https://discord.com/developers/docs/topics/gateway-events#stage-instance-update + private void HandleDispatchStageInstanceUpdated(StageInstance stage) + { + DiscordGuild guild = _client.GetGuild(stage.GuildId); + if (guild == null || !guild.IsAvailable) { - _webSocket.OnReconnectRequested(); + return; } - - //https://discord.com/developers/docs/topics/gateway-events#invalid-session - private void HandleInvalidSession(bool resume) + + StageInstance existing = guild.StageInstances[stage.Id]; + if (existing == null) { - _webSocket.OnInvalidSession(resume); + guild.StageInstances[stage.Id] = stage; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordStageInstanceUpdated, stage, stage, guild); } - - //https://discord.com/developers/docs/topics/gateway-events#hello - private ValueTask HandleHello(EventPayload payload) + else { - GatewayHelloEvent hello = payload.GetData(_client); - return _webSocket.OnDiscordHello(hello); + StageInstance previous = existing.Edit(stage); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordStageInstanceUpdated, stage, previous, guild); } + } - //https://discord.com/developers/docs/topics/gateway-events#heartbeating - private void HandleHeartbeatAcknowledge() + //https://discord.com/developers/docs/topics/gateway-events#stage-instance-delete + private void HandleDispatchStageInstanceDeleted(StageInstance stage) + { + DiscordGuild guild = _client.GetGuild(stage.GuildId); + if (guild == null || !guild.IsAvailable) { - _webSocket.OnHeartbeatAcknowledge(); + return; } - #endregion + + StageInstance existing = guild.StageInstances[stage.Id]; + guild.StageInstances.Remove(stage.Id); + guild.StageInstances[stage.Id] = stage; + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordStageInstanceDeleted, existing ?? stage, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-create + private void HandleDispatchAutoModRuleCreated(AutoModRule rule) + { + DiscordGuild guild = _client.GetGuild(rule.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordAutoModRuleCreated, rule, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-update + private void HandleDispatchAutoModRuleUpdated(AutoModRule rule) + { + DiscordGuild guild = _client.GetGuild(rule.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordAutoModRuleUpdated, rule, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-delete + private void HandleDispatchAutoModRuleDeleted(AutoModRule rule) + { + DiscordGuild guild = _client.GetGuild(rule.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordAutoModRuleDeleted, rule, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#auto-moderation-action-execution + private void HandleDispatchAutoModActionExecuted(AutoModActionExecutionEvent action) + { + DiscordGuild guild = _client.GetGuild(action.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordAutoModActionExecuted, action, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-add + private void HandleDispatchMessagePollVoteAdded(MessagePollVoteAddedEvent data) + { + DiscordGuild guild = _client.GetGuild(data.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordPollVoteAdded, data, guild); + } + + //https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-remove + private void HandleDispatchMessagePollVoteRemoved(MessagePollVoteRemovedEvent data) + { + DiscordGuild guild = _client.GetGuild(data.GuildId); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordPollVoteRemoved, data, guild); + } + + private void HandleDispatchUnhandledEvent(EventPayload payload) + { + _logger.Verbose("Unhandled Dispatch Event: {0}.\n{1}", payload.DispatchCode, payload.Data); + _client.Hooks.CallHook(DiscordExtHooks.OnDiscordUnhandledCommand, payload); + } + + //https://discord.com/developers/docs/topics/gateway-events#heartbeat + private ValueTask HandleHeartbeat() + { + _logger.Debug("Manually sent heartbeat (received opcode 1)"); + return _webSocket.SendHeartbeat(); + } + + //https://discord.com/developers/docs/topics/gateway-events#reconnect + private void HandleReconnect() + { + _webSocket.OnReconnectRequested(); + } + + //https://discord.com/developers/docs/topics/gateway-events#invalid-session + private void HandleInvalidSession(bool resume) + { + _webSocket.OnInvalidSession(resume); + } + + //https://discord.com/developers/docs/topics/gateway-events#hello + private ValueTask HandleHello(EventPayload payload) + { + GatewayHelloEvent hello = payload.GetData(_client); + return _webSocket.OnDiscordHello(hello); + } + + //https://discord.com/developers/docs/topics/gateway-events#heartbeating + private void HandleHeartbeatAcknowledge() + { + _webSocket.OnHeartbeatAcknowledge(); } -} + #endregion +} \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/Handlers/ZlibDecompressorHandler.cs b/Oxide.Ext.Discord/WebSockets/Handlers/ZlibDecompressorHandler.cs index 2fd723ebd..f68bcf7eb 100644 --- a/Oxide.Ext.Discord/WebSockets/Handlers/ZlibDecompressorHandler.cs +++ b/Oxide.Ext.Discord/WebSockets/Handlers/ZlibDecompressorHandler.cs @@ -7,95 +7,86 @@ using Oxide.Ext.Discord.Interfaces; using Oxide.Ext.Discord.Logging; -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +//Currently not used. Needs some work to get it working without so many allocations. +internal class ZlibDecompressorHandler { - //Currently not used. Needs some work to get it working without so many allocations. - internal class ZlibDecompressorHandler - { - //private readonly MemoryStream _input; - //private readonly DeflateStream _zlib; - //private readonly MemoryStream _output; - //private readonly StreamReader _outputStream; - private readonly Encoding _encoding; - private readonly ILogger _logger; + //private readonly MemoryStream _input; + //private readonly DeflateStream _zlib; + //private readonly MemoryStream _output; + //private readonly StreamReader _outputStream; + private readonly Encoding _encoding; + private readonly ILogger _logger; - private static readonly byte[] ZlibSuffix = {0x00, 0x00, 0xFF, 0xFF}; - private const byte ZlibPrefix = 0x78; + private static readonly byte[] ZlibSuffix = [0x00, 0x00, 0xFF, 0xFF]; + private const byte ZlibPrefix = 0x78; - public ZlibDecompressorHandler(Encoding encoding, ILogger logger) - { - //_input = new MemoryStream(); - //_zlib = new DeflateStream(_input, CompressionMode.Decompress); - //_output = new MemoryStream(); - //_outputStream = new StreamReader(_output, encoding); - _encoding = encoding; - _logger = logger; - } + public ZlibDecompressorHandler(Encoding encoding, ILogger logger) + { + //_input = new MemoryStream(); + //_zlib = new DeflateStream(_input, CompressionMode.Decompress); + //_output = new MemoryStream(); + //_outputStream = new StreamReader(_output, encoding); + _encoding = encoding; + _logger = logger; + } - public async Task DecompressMessage(ArraySegment bytes, CancellationToken token) + public async Task DecompressMessage(ArraySegment bytes, CancellationToken token) + { + try { - try + byte[] array = bytes.Array ?? throw new ArgumentNullException(nameof(bytes)); + if (bytes.Count < 4) { - byte[] array = bytes.Array ?? throw new ArgumentNullException(nameof(bytes)); - if (bytes.Count < 4) - { - _logger.Warning("Tried to decompress a message with less than 4 bytes. Count: {0}", bytes.Count); - return string.Empty; - } + _logger.Warning("Tried to decompress a message with less than 4 bytes. Count: {0}", bytes.Count); + return string.Empty; + } - using (MemoryStream input = new MemoryStream()) - { - if (array[0] == ZlibPrefix) - { - await input.WriteAsync(array, bytes.Offset + 2, bytes.Count - 2, token).ConfigureAwait(false); - } - else - { - await input.WriteAsync(array, bytes.Offset, bytes.Count, token).ConfigureAwait(false); - } + using MemoryStream input = new(); + if (array[0] == ZlibPrefix) + { + await input.WriteAsync(array, bytes.Offset + 2, bytes.Count - 2, token).ConfigureAwait(false); + } + else + { + await input.WriteAsync(array, bytes.Offset, bytes.Count, token).ConfigureAwait(false); + } - await input.FlushAsync(token).ConfigureAwait(false); - input.Position = 0; + await input.FlushAsync(token).ConfigureAwait(false); + input.Position = 0; - using (DeflateStream zlib = new DeflateStream(input, CompressionMode.Decompress, true)) - { - using (MemoryStream output = new MemoryStream()) - { - await zlib.CopyToAsync(output).ConfigureAwait(false); - output.Position = 0; + await using DeflateStream zlib = new(input, CompressionMode.Decompress, true); + using MemoryStream output = new(); + await zlib.CopyToAsync(output, token).ConfigureAwait(false); + output.Position = 0; - using (StreamReader reader = new StreamReader(output, _encoding)) - { - string message = await reader.ReadToEndAsync().ConfigureAwait(false); + using StreamReader reader = new(output, _encoding); + string message = await reader.ReadToEndAsync().ConfigureAwait(false); - _logger.Debug($"Processed Message: String Length: {message.Length} Output Length: {output.Length}"); + _logger.Debug($"Processed Message: String Length: {message.Length} Output Length: {output.Length}"); - return message; - } - } - } - } - } - catch (Exception ex) - { - _logger.Exception("An error occured decompression zlib stream", ex); - return string.Empty; - } + return message; } + catch (Exception ex) + { + _logger.Exception("An error occured decompression zlib stream", ex); + return string.Empty; + } + } - // ReSharper disable once UnusedMember.Local - private bool IsValidZlibStream(ArraySegment bytes) + // ReSharper disable once UnusedMember.Local + private bool IsValidZlibStream(ArraySegment bytes) + { + byte[] array = bytes.Array ?? throw new InvalidOperationException(); + for (int i = 0; i < 4; i++) { - byte[] array = bytes.Array ?? throw new InvalidOperationException(); - for (int i = 0; i < 4; i++) + if (array[array.Length - 1 - i] != ZlibSuffix[ZlibSuffix.Length - 1 - i]) { - if (array[array.Length - 1 - i] != ZlibSuffix[ZlibSuffix.Length - 1 - i]) - { - return false; - } + return false; } - - return true; } + + return true; } } \ No newline at end of file diff --git a/Oxide.Ext.Discord/WebSockets/SocketState.cs b/Oxide.Ext.Discord/WebSockets/SocketState.cs index f6ad4c114..64642ed02 100644 --- a/Oxide.Ext.Discord/WebSockets/SocketState.cs +++ b/Oxide.Ext.Discord/WebSockets/SocketState.cs @@ -1,28 +1,27 @@ -namespace Oxide.Ext.Discord.WebSockets +namespace Oxide.Ext.Discord.WebSockets; + +/// +/// Represents our current state for the websocket +/// +public enum SocketState : byte { /// - /// Represents our current state for the websocket + /// Websocket is in the process of connecting /// - public enum SocketState : byte - { - /// - /// Socket is in the process of connecting - /// - Connecting, + Connecting, - /// - /// Socket is connect and functioning normally - /// - Connected, + /// + /// Websocket is connected and functioning normally + /// + Connected, - /// - /// Websocket is currently disconnecting from a connected web socket - /// - Disconnecting, + /// + /// Websocket is currently disconnecting from a connected web socket + /// + Disconnecting, - /// - /// Websocket is currently disconnect and not waiting to connect - /// - Disconnected - } + /// + /// Websocket is currently disconnect and not waiting to connect + /// + Disconnected } \ No newline at end of file