From cf58afcfa44b0e14e2b76551678fb9b5884e478f Mon Sep 17 00:00:00 2001 From: Stephen Whittle Date: Wed, 1 Sep 2021 16:56:58 +1000 Subject: [PATCH] 2.4.1169 * Internal Native SDK dependency is now private to the Modio module * ReportContentAsync added * SubmitModRatingAsync added --- Doc/documentation.html | 374 ++++++++--- Doc/img/nd_img_DisableModManagement.png | Bin 14840 -> 14828 bytes Doc/img/nd_img_GetLogoFullSize.png | Bin 7205 -> 7206 bytes Doc/img/nd_img_GetLogoThumbnailSize.png | Bin 8342 -> 8345 bytes Doc/img/nd_img_GetProjectEnvironment.png | Bin 8301 -> 8304 bytes Doc/img/nd_img_IsModManagementBusy.png | Bin 15478 -> 15477 bytes Doc/img/nd_img_K2_GetModTagOptionsAsync.png | Bin 15968 -> 15978 bytes Doc/img/nd_img_K2_ReportContentAsync.png | Bin 0 -> 16348 bytes Doc/img/nd_img_K2_SubmitModRatingAsync.png | Bin 0 -> 20908 bytes Doc/img/nd_img_K2_UnsubscribeFromModAsync.png | Bin 18691 -> 18712 bytes Doc/img/nd_img_ListUserSubscriptionAsync.png | Bin 10899 -> 10902 bytes Doc/img/nd_img_MakeApiKey.png | Bin 9253 -> 9244 bytes Doc/img/nd_img_MakeAuthParams.png | Bin 14555 -> 14558 bytes Doc/img/nd_img_QueryUserInstallations.png | Bin 18775 -> 18789 bytes README.adoc | 4 +- .../Classes/Types/ModioAuthenticationParams.h | 61 -- Source/Modio/Classes/Types/ModioCommonTypes.h | 605 ------------------ Source/Modio/Classes/Types/ModioErrorCode.h | 47 -- .../Modio/Classes/Types/ModioFilterParams.h | 260 -------- Source/Modio/Classes/Types/ModioImageState.h | 14 - .../Classes/Types/ModioModCollectionEntry.h | 89 --- .../Classes/Types/ModioModManagementEvent.h | 67 -- Source/Modio/Classes/Types/ModioModTag.h | 27 - Source/Modio/Classes/Types/ModioPagedResult.h | 54 -- .../GeneratedHeader/ModioErrorCondition.h | 27 + .../ModioErrorConditionLibrary.h | 42 -- .../ArchiveFileImplementation.cpp | 10 + .../Modio/GeneratedSource/HttpSharedState.cpp | 10 + Source/Modio/GeneratedSource/ModioBuffer.cpp | 10 + .../GeneratedSource/ModioCacheService.cpp | 10 + .../ModioCompressionService.cpp | 10 + .../GeneratedSource/ModioFileMetadata.cpp | 10 + .../GeneratedSource/ModioFilterParams.cpp | 10 + .../Modio/GeneratedSource/ModioHttpParams.cpp | 10 + .../GeneratedSource/ModioHttpRequest.cpp | 10 + .../GeneratedSource/ModioHttpService.cpp | 10 + .../ModioInitializeOptions.cpp | 12 +- .../GeneratedSource/ModioJsonHelpers.cpp | 10 + .../Modio/GeneratedSource/ModioLogService.cpp | 10 + .../ModioModCollectionEntry.cpp | 9 + .../Modio/GeneratedSource/ModioModDetails.cpp | 10 + Source/Modio/GeneratedSource/ModioModInfo.cpp | 10 + .../Modio/GeneratedSource/ModioModStats.cpp | 10 + .../GeneratedSource/ModioObjectTrack.cpp | 12 +- .../GeneratedSource/ModioPagedResult.cpp | 10 + .../GeneratedSource/ModioReportParams.cpp | 78 +++ .../GeneratedSource/ModioSDKSessionData.cpp | 10 + Source/Modio/GeneratedSource/ModioURLList.cpp | 10 + .../ModioUserDataContainer.cpp | 10 + .../GeneratedSource/ModioUserProfile.cpp | 10 + Source/Modio/GeneratedSource/SDKCore.cpp | 22 + .../GeneratedSource/SDKModManagement.cpp | 10 + .../Modio/GeneratedSource/SDKModMetadata.cpp | 21 + Source/Modio/GeneratedSource/SDKUserData.cpp | 10 + .../Modio/GeneratedSource/deflate_stream.cpp | 10 + .../Modio/GeneratedSource/inflate_stream.cpp | 10 + Source/Modio/Modio.Build.cs | 40 +- .../Private/Internal/Convert/AuthParams.h | 53 ++ .../Private/Internal/Convert/ErrorCode.h | 19 + .../Private/Internal/Convert/FileMetadata.h | 69 ++ .../Private/Internal/Convert/FilterParams.h | 83 +++ .../Convert/InitializeOptions.h} | 38 +- .../Modio/Private/Internal/Convert/Metadata.h | 22 + .../Internal/Convert/ModCollectionEntry.h | 52 ++ .../Modio/Private/Internal/Convert/ModInfo.h | 45 ++ .../Private/Internal/Convert/ModInfoList.h | 19 + .../Internal/Convert/ModManagementEvent.h | 45 ++ .../Internal/Convert/ModProgressInfo.h | 24 + .../Modio/Private/Internal/Convert/ModStats.h | 30 + .../Modio/Private/Internal/Convert/ModTag.h | 21 + .../Private/Internal/Convert/ModTagInfo.h | 23 + .../Private/Internal/Convert/ModTagOptions.h | 20 + .../Modio/Private/Internal/Convert/Rating.h | 34 + .../Private/Internal/Convert/ReportParams.h | 54 ++ Source/Modio/Private/Internal/Convert/Terms.h | 37 ++ .../Modio/Private/Internal/Convert/URLList.h | 24 + Source/Modio/Private/Internal/Convert/User.h | 25 + Source/Modio/Private/Internal/ModioConvert.h | 384 +++++++++++ .../Private/Internal/ModioPrivateDefines.h | 19 + .../Libraries/ModioCommonTypesLibrary.cpp | 18 +- .../Libraries/ModioErrorCodeLibrary.cpp | 12 +- .../Libraries/ModioErrorConditionLibrary.cpp | 21 + .../Libraries/ModioFilterParamsLibrary.cpp | 10 + .../Private/Libraries/ModioImageLibrary.cpp | 12 +- .../Libraries/ModioModCollectionLibrary.cpp | 14 +- .../Libraries/ModioModInfoListLibrary.cpp | 12 +- .../Libraries/ModioModTagOptionsLibrary.cpp | 12 +- .../Libraries/ModioOptionalLibrary.cpp | 12 +- .../Private/Libraries/ModioReportLibrary.cpp | 35 + .../Private/Libraries/ModioSDKLibrary.cpp | 16 +- Source/Modio/Private/Modio.cpp | 10 + Source/Modio/Private/ModioImageCache.cpp | 12 +- Source/Modio/Private/ModioModule.cpp | 11 +- Source/Modio/Private/ModioModule.h | 12 +- Source/Modio/Private/ModioPrivatePCH.h | 10 + Source/Modio/Private/ModioSettings.cpp | 12 +- Source/Modio/Private/ModioSubsystem.cpp | 149 ++++- .../Tests/Commands/AuthoriseUserEmailAsync.h | 10 + .../Tests/Commands/DisableModManagement.h | 10 + .../Tests/Commands/EnableModManagement.h | 10 + .../Commands/FetchExternalUpdatesAsync.h | 10 + .../Private/Tests/Commands/GetModInfoAsync.h | 10 + .../Private/Tests/Commands/GetModMediaAsync.h | 10 + .../Private/Tests/Commands/InitializeAsync.h | 10 + .../Commands/InitializeBadResponseAsync.h | 14 +- .../Tests/Commands/IsModManagementBusy.h | 10 + .../Private/Tests/Commands/ListAllModsAsync.h | 10 + .../Tests/Commands/ModioTestCommandBase.cpp | 80 +++ .../Tests/Commands/ModioTestCommandBase.h | 74 +-- .../Tests/Commands/QueryCurrentModUpdate.h | 10 + .../Private/Tests/Commands/ShutdownAsync.h | 10 + .../Tests/Commands/SubscribeToModAsync.h | 10 + .../Tests/Commands/UnsubFromModAsync.h | 10 + Source/Modio/Private/Tests/GetModInfoTest.cpp | 10 + .../Modio/Private/Tests/InitShutdownTest.cpp | 10 + .../Modio/Private/Tests/ListAllModsTest.cpp | 10 + .../Modio/Private/Tests/ModManagementTest.cpp | 10 + .../Private/Tests/ModioTestValidationData.cpp | 10 + .../Private/Tests/ModioTestValidationData.h | 10 + .../Modio/Private/Tests/SubscriptionTest.cpp | 10 + Source/Modio/Private/Tests/ToModio.cpp | 14 +- Source/Modio/Private/Tests/ToUnreal.cpp | 11 + .../Types/ModioAuthenticationParams.cpp | 13 - .../Modio/Private/Types/ModioCommonTypes.cpp | 46 +- Source/Modio/Private/Types/ModioErrorCode.cpp | 65 +- .../Private/Types/ModioFilterParamsUImpl.cpp | 103 +++ Source/Modio/Private/Types/ModioImage.cpp | 13 +- Source/Modio/Private/Types/ModioMetadata.cpp | 7 - .../Types/ModioModCollectionEntryUImpl.cpp | 39 ++ .../Modio/Private/Types/ModioModInfoList.cpp | 14 +- .../Private/Types/ModioModManagementEvent.cpp | 8 - .../Private/Types/ModioModProgressInfo.cpp | 11 - Source/Modio/Private/Types/ModioModTag.cpp | 3 - .../Modio/Private/Types/ModioModTagInfo.cpp | 9 - .../Private/Types/ModioModTagOptions.cpp | 14 +- ...edResult.cpp => ModioPagedResultUImpl.cpp} | 13 +- .../Private/Types/ModioReportParamsUImpl.cpp | 53 ++ .../Private/Types/ModioSDKFileMetadata.cpp | 15 - .../Types/ModioSDKModCollectionEntry.cpp | 34 - .../Modio/Private/Types/ModioSDKModInfo.cpp | 24 - .../Modio/Private/Types/ModioSDKModStats.cpp | 16 - .../Modio/Private/Types/ModioSDKURLList.cpp | 10 - Source/Modio/Private/Types/ModioTerms.cpp | 27 - .../Modio/Private/Types/ModioURLListUImpl.cpp | 21 + Source/Modio/Private/Types/ModioUser.cpp | 11 - .../Modio/Private/UI/ModioExampleLibrary.cpp | 12 +- .../Modio/Private/UI/ModioPopupContainer.cpp | 12 +- Source/Modio/Public/Internal/ModioConvert.h | 129 ---- .../Public/Internal/ModioPrivateDefines.h | 9 - .../Libraries/ModioCommonTypesLibrary.h | 15 +- .../Public/Libraries/ModioErrorCodeLibrary.h | 12 +- .../Libraries/ModioErrorConditionLibrary.h | 33 + .../Libraries/ModioFilterParamsLibrary.h | 10 + .../Public/Libraries/ModioImageLibrary.h | 12 +- .../Libraries/ModioModCollectionLibrary.h | 14 +- .../Libraries/ModioModInfoListLibrary.h | 12 +- .../Libraries/ModioModTagOptionsLibrary.h | 12 +- .../Public/Libraries/ModioOptionalLibrary.h | 13 +- .../Public/Libraries/ModioReportLibrary.h | 67 ++ .../Modio/Public/Libraries/ModioSDKLibrary.h | 12 +- Source/Modio/Public/Modio.h | 10 + Source/Modio/Public/ModioImageCache.h | 12 +- Source/Modio/Public/ModioSDK.h | 23 +- .../Modio/{Classes => Public}/ModioSettings.h | 12 +- Source/Modio/Public/ModioSubsystem.h | 75 ++- .../Public/Types/ModioAuthenticationParams.h | 40 ++ Source/Modio/Public/Types/ModioCommonTypes.h | 376 +++++++++++ Source/Modio/Public/Types/ModioErrorCode.h | 48 ++ .../Types/ModioFileMetadata.h | 60 +- Source/Modio/Public/Types/ModioFilterParams.h | 172 +++++ .../{Classes => Public}/Types/ModioImage.h | 35 +- Source/Modio/Public/Types/ModioImageState.h | 24 + .../Types/ModioInitializeOptions.h | 20 +- .../{Classes => Public}/Types/ModioList.h | 13 +- .../{Classes => Public}/Types/ModioMetadata.h | 27 +- .../Public/Types/ModioModCollectionEntry.h | 54 ++ .../{Classes => Public}/Types/ModioModInfo.h | 25 +- .../Types/ModioModInfoList.h | 21 +- .../Public/Types/ModioModManagementEvent.h | 47 ++ .../Types/ModioModProgressInfo.h | 24 +- .../{Classes => Public}/Types/ModioModStats.h | 29 +- Source/Modio/Public/Types/ModioModTag.h | 25 + .../Types/ModioModTagInfo.h | 28 +- .../Types/ModioModTagOptions.h | 30 +- Source/Modio/Public/Types/ModioPagedResult.h | 64 ++ Source/Modio/Public/Types/ModioRating.h | 21 + Source/Modio/Public/Types/ModioReportParams.h | 101 +++ .../{Classes => Public}/Types/ModioTerms.h | 37 +- .../{Classes => Public}/Types/ModioURLList.h | 33 +- .../{Classes => Public}/Types/ModioUser.h | 24 +- .../Types/ModioValidationError.h | 10 + Source/Modio/Public/UI/ModioExampleLibrary.h | 12 +- Source/Modio/Public/UI/ModioPopupBase.h | 12 +- Source/Modio/Public/UI/ModioPopupContainer.h | 12 +- Source/ThirdParty/NativeSDK | 2 +- 195 files changed, 4455 insertions(+), 2074 deletions(-) create mode 100644 Doc/img/nd_img_K2_ReportContentAsync.png create mode 100644 Doc/img/nd_img_K2_SubmitModRatingAsync.png delete mode 100644 Source/Modio/Classes/Types/ModioAuthenticationParams.h delete mode 100644 Source/Modio/Classes/Types/ModioCommonTypes.h delete mode 100644 Source/Modio/Classes/Types/ModioErrorCode.h delete mode 100644 Source/Modio/Classes/Types/ModioFilterParams.h delete mode 100644 Source/Modio/Classes/Types/ModioImageState.h delete mode 100644 Source/Modio/Classes/Types/ModioModCollectionEntry.h delete mode 100644 Source/Modio/Classes/Types/ModioModManagementEvent.h delete mode 100644 Source/Modio/Classes/Types/ModioModTag.h delete mode 100644 Source/Modio/Classes/Types/ModioPagedResult.h create mode 100644 Source/Modio/GeneratedHeader/ModioErrorCondition.h delete mode 100644 Source/Modio/GeneratedHeader/ModioErrorConditionLibrary.h create mode 100644 Source/Modio/GeneratedSource/ModioReportParams.cpp create mode 100644 Source/Modio/Private/Internal/Convert/AuthParams.h create mode 100644 Source/Modio/Private/Internal/Convert/ErrorCode.h create mode 100644 Source/Modio/Private/Internal/Convert/FileMetadata.h create mode 100644 Source/Modio/Private/Internal/Convert/FilterParams.h rename Source/Modio/Private/{Types/ModioSDKInitializeOptions.cpp => Internal/Convert/InitializeOptions.h} (55%) create mode 100644 Source/Modio/Private/Internal/Convert/Metadata.h create mode 100644 Source/Modio/Private/Internal/Convert/ModCollectionEntry.h create mode 100644 Source/Modio/Private/Internal/Convert/ModInfo.h create mode 100644 Source/Modio/Private/Internal/Convert/ModInfoList.h create mode 100644 Source/Modio/Private/Internal/Convert/ModManagementEvent.h create mode 100644 Source/Modio/Private/Internal/Convert/ModProgressInfo.h create mode 100644 Source/Modio/Private/Internal/Convert/ModStats.h create mode 100644 Source/Modio/Private/Internal/Convert/ModTag.h create mode 100644 Source/Modio/Private/Internal/Convert/ModTagInfo.h create mode 100644 Source/Modio/Private/Internal/Convert/ModTagOptions.h create mode 100644 Source/Modio/Private/Internal/Convert/Rating.h create mode 100644 Source/Modio/Private/Internal/Convert/ReportParams.h create mode 100644 Source/Modio/Private/Internal/Convert/Terms.h create mode 100644 Source/Modio/Private/Internal/Convert/URLList.h create mode 100644 Source/Modio/Private/Internal/Convert/User.h create mode 100644 Source/Modio/Private/Internal/ModioConvert.h create mode 100644 Source/Modio/Private/Internal/ModioPrivateDefines.h create mode 100644 Source/Modio/Private/Libraries/ModioErrorConditionLibrary.cpp create mode 100644 Source/Modio/Private/Libraries/ModioReportLibrary.cpp create mode 100644 Source/Modio/Private/Tests/Commands/ModioTestCommandBase.cpp delete mode 100644 Source/Modio/Private/Types/ModioAuthenticationParams.cpp create mode 100644 Source/Modio/Private/Types/ModioFilterParamsUImpl.cpp delete mode 100644 Source/Modio/Private/Types/ModioMetadata.cpp create mode 100644 Source/Modio/Private/Types/ModioModCollectionEntryUImpl.cpp delete mode 100644 Source/Modio/Private/Types/ModioModManagementEvent.cpp delete mode 100644 Source/Modio/Private/Types/ModioModProgressInfo.cpp delete mode 100644 Source/Modio/Private/Types/ModioModTag.cpp delete mode 100644 Source/Modio/Private/Types/ModioModTagInfo.cpp rename Source/Modio/Private/Types/{ModioSDKPagedResult.cpp => ModioPagedResultUImpl.cpp} (65%) create mode 100644 Source/Modio/Private/Types/ModioReportParamsUImpl.cpp delete mode 100644 Source/Modio/Private/Types/ModioSDKFileMetadata.cpp delete mode 100644 Source/Modio/Private/Types/ModioSDKModCollectionEntry.cpp delete mode 100644 Source/Modio/Private/Types/ModioSDKModInfo.cpp delete mode 100644 Source/Modio/Private/Types/ModioSDKModStats.cpp delete mode 100644 Source/Modio/Private/Types/ModioSDKURLList.cpp delete mode 100644 Source/Modio/Private/Types/ModioTerms.cpp create mode 100644 Source/Modio/Private/Types/ModioURLListUImpl.cpp delete mode 100644 Source/Modio/Private/Types/ModioUser.cpp delete mode 100644 Source/Modio/Public/Internal/ModioConvert.h delete mode 100644 Source/Modio/Public/Internal/ModioPrivateDefines.h create mode 100644 Source/Modio/Public/Libraries/ModioErrorConditionLibrary.h create mode 100644 Source/Modio/Public/Libraries/ModioReportLibrary.h rename Source/Modio/{Classes => Public}/ModioSettings.h (82%) create mode 100644 Source/Modio/Public/Types/ModioAuthenticationParams.h create mode 100644 Source/Modio/Public/Types/ModioCommonTypes.h create mode 100644 Source/Modio/Public/Types/ModioErrorCode.h rename Source/Modio/{Classes => Public}/Types/ModioFileMetadata.h (57%) create mode 100644 Source/Modio/Public/Types/ModioFilterParams.h rename Source/Modio/{Classes => Public}/Types/ModioImage.h (69%) create mode 100644 Source/Modio/Public/Types/ModioImageState.h rename Source/Modio/{Classes => Public}/Types/ModioInitializeOptions.h (67%) rename Source/Modio/{Classes => Public}/Types/ModioList.h (90%) rename Source/Modio/{Classes => Public}/Types/ModioMetadata.h (56%) create mode 100644 Source/Modio/Public/Types/ModioModCollectionEntry.h rename Source/Modio/{Classes => Public}/Types/ModioModInfo.h (90%) rename Source/Modio/{Classes => Public}/Types/ModioModInfoList.h (74%) create mode 100644 Source/Modio/Public/Types/ModioModManagementEvent.h rename Source/Modio/{Classes => Public}/Types/ModioModProgressInfo.h (73%) rename Source/Modio/{Classes => Public}/Types/ModioModStats.h (87%) create mode 100644 Source/Modio/Public/Types/ModioModTag.h rename Source/Modio/{Classes => Public}/Types/ModioModTagInfo.h (66%) rename Source/Modio/{Classes => Public}/Types/ModioModTagOptions.h (65%) create mode 100644 Source/Modio/Public/Types/ModioPagedResult.h create mode 100644 Source/Modio/Public/Types/ModioRating.h create mode 100644 Source/Modio/Public/Types/ModioReportParams.h rename Source/Modio/{Classes => Public}/Types/ModioTerms.h (73%) rename Source/Modio/{Classes => Public}/Types/ModioURLList.h (68%) rename Source/Modio/{Classes => Public}/Types/ModioUser.h (75%) rename Source/Modio/{Classes => Public}/Types/ModioValidationError.h (68%) diff --git a/Doc/documentation.html b/Doc/documentation.html index 2834255d..6c26f6fc 100644 --- a/Doc/documentation.html +++ b/Doc/documentation.html @@ -822,8 +822,10 @@

mod.io UE4 Plugin Documentation

  • Query System Installations
  • UnsubscribeFromModAsync
  • SubscribeToModAsync
  • +
  • SubmitModRatingAsync
  • ShutdownAsync
  • RequestEmailAuthCodeAsync
  • +
  • ReportContentAsync
  • QueryUserProfile
  • QueryCurrentModUpdate
  • ListAllModsAsync
  • @@ -883,6 +885,7 @@

    mod.io UE4 Plugin Documentation

  • ModioModCollectionEntry
  • ModioOptionalModProgressInfo
  • ModioModProgressInfo
  • +
  • ModioReportParams
  • ModioTerms
  • ModioLink
  • ModioTestFilterParamData
  • @@ -942,6 +945,8 @@

    mod.io UE4 Plugin Documentation

  • EModioSortFieldType
  • EModioImageState
  • EModioModState
  • +
  • EModioRating
  • +
  • EModioReportType
  • EFileSizeUnit
  • @@ -1975,6 +1980,87 @@
    Parameters

    +

    SubmitModRatingAsync

    +
    +
    +nd img K2 SubmitModRatingAsync +
    +
    +
    +
    +
    void K2_SubmitModRatingAsync(FModioModID Mod, EModioRating Rating, FOnErrorOnlyDelegate Callback)
    +
    +
    +
    +

    Submits a rating for a mod on behalf of the current user. Submit a neutral rating to effectively clear a rating already submitted by a user. Submitting other values will overwrite any existing rating submitted by this user.

    +
    +
    Requirements
    +
    +
      +
    • +

      initialized-sdk

      +
    • +
    • +

      authenticated-user

      +
    • +
    • +

      no-rate-limiting

      +
    • +
    +
    +
    Parameters
    + ++++ + + + + + + + + + + + + + + + + + + +

    Target

    Modio Subsystem Object Reference

    Mod

    The mod the user is rating

    Rating

    The rating the user wishes to submit

    Callback

    +
    Error Values
    + ++++ + + + + + + + + + + + + + + + + + + +

    GenericError::SDKNotInitialized

    SDK not initialized

    UserDataError::InvalidUser

    No authenticated user

    NetworkError

    Couldn’t connect to mod.io servers

    EntityNotFoundError

    Specified mod could not be found

    +
    +
    +

    ShutdownAsync

    @@ -1989,7 +2075,7 @@

    ShutdownAsync

    Cancels any running internal operations, frees SDK resources, and invokes any pending callbacks with Modio::GenericError::OperationCanceled . This function will NOT block while the deinitialization occurs.

    -
    Parameters
    +
    Parameters
    @@ -2023,7 +2109,7 @@

    RequestEmailAuthCodeAsync

    Begins email authentication for the current session by requesting a one-time code be sent to the specified email address if it is associated with a Mod.io account

    -
    Requirements
    +
    Requirements
    • @@ -2037,7 +2123,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2058,7 +2144,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2082,6 +2168,69 @@
    Error Values

    +

    ReportContentAsync

    +
    +
    +nd img K2 ReportContentAsync +
    +
    +
    +
    +
    void K2_ReportContentAsync(FModioReportParams Report, FOnErrorOnlyDelegate Callback)
    +
    +
    +
    +

    Sends a content report to mod.io. When using this function, please inform your users that if they provide their contact name or details in the Report parameter, that those may be shared with the person responsible for the content being reported. For more information on what data in a report will be shared with whom, please see our website’s report form for more information.

    +
    +
    Requirements
    +
    +
      +
    • +

      initialized-sdk

      +
    • +
    +
    +
    Parameters
    +
    ++++ + + + + + + + + + + + + + + +

    Target

    Modio Subsystem Object Reference

    Report

    Information about the content being reported and a description of the report.

    Callback

    Callback providing a status code to indicate successful submission of the report.

    +
    Error Values
    + ++++ + + + + + + + + + + +

    NetworkError

    Couldn’t Connect to mod.io servers

    InvalidArgsError

    Required information in the report did not pass validation

    +
    +
    +

    QueryUserProfile

    @@ -2096,7 +2245,7 @@

    QueryUserProfile

    Fetches the currently authenticated Mod.io user profile if there is one associated with the current platform user

    -
    Parameters
    +
    Parameters
    @@ -2134,7 +2283,7 @@

    QueryCurrentModUpdate

    Provides progress information for a mod installation or update operation if one is currently in progress.

    -
    Parameters
    +
    Parameters
    @@ -2172,7 +2321,7 @@

    ListAllModsAsync

    Provides a list of mods for the current game, that match the parameters specified in the filter

    -
    Requirements
    +
    Requirements
    • @@ -2183,7 +2332,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2204,7 +2353,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2238,7 +2387,7 @@

    InitializeAsync

    Initializes the SDK for the given user. Loads the state of mods installed on the system as well as the set of mods the specified user has installed on this device

    -
    Parameters
    +
    Parameters
    @@ -2276,7 +2425,7 @@

    GetUserMediaAsync (Avatar)

    Downloads the avatar of the currently authenticated user. Will only perform a download if there is no local cache of the avatar or if that cached copy is out-of-date.

    -
    Requirements
    +
    Requirements
    • @@ -2290,7 +2439,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2311,7 +2460,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2349,7 +2498,7 @@

    GetTermsOfUseAsync

    This function retrieves the information required for a game to display the mod.io terms of use to a player who wishes to create a mod.io account

    -
    Requirements
    +
    Requirements
    • @@ -2357,7 +2506,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2382,7 +2531,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2416,7 +2565,7 @@

    GetModTagOptionsAsync

    Fetches the available tags used on mods for the current game. These tags can them be used in conjunction with the FilterParams passed to ListAllMods Will be cached when first received

    -
    Requirements
    +
    Requirements
    • @@ -2427,7 +2576,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2444,7 +2593,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2478,7 +2627,7 @@

    GetModMediaAsync (Logo)

    Downloads the logo for the specified mod. Will use existing file if it is already present on disk

    -
    Requirements
    +
    Requirements
    • @@ -2489,7 +2638,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2514,7 +2663,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2556,7 +2705,7 @@

    GetModMediaAsync (Gallery Image)

    Get a gallery image for the specified mod ID. If it already exists on disk the file will be reused unless it is outdated

    -
    Requirements
    +
    Requirements
    • @@ -2567,7 +2716,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2596,7 +2745,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2638,7 +2787,7 @@

    GetModMediaAsync (Avatar)

    Downloads the creator avatar for a specified mod. Will use existing file if it is already present on disk and not outdated

    -
    Requirements
    +
    Requirements
    • @@ -2649,7 +2798,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2674,7 +2823,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2716,7 +2865,7 @@

    GetModInfoAsync

    Fetches detailed information about the specified mod, including description and file metadata for the most recent release

    -
    Requirements
    +
    Requirements
    • @@ -2727,7 +2876,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2748,7 +2897,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2786,7 +2935,7 @@

    FetchExternalUpdatesAsync

    Synchronises the local list of the current user’s subscribed mods with the server. Any mods that have been externally subscribed will be automatically marked for installation, and mods that have been externally removed from the user’s subscriptions may be uninstalled if no other local users have a current subscription.

    -
    Parameters
    +
    Parameters
    @@ -2820,7 +2969,7 @@

    EnableModManagement

    Enables the automatic management of installed mods on the system based on the user’s subscriptions.

    -
    Parameters
    +
    Parameters
    @@ -2854,7 +3003,7 @@

    ClearUserDataAsync

    De-authenticates the current Mod.io user for the current session, and clears all user-specific data stored on the current device. Any subscribed mods that are installed but do not have other local users subscribed will be uninstalled

    -
    Requirements
    +
    Requirements
    • @@ -2868,7 +3017,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2885,7 +3034,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2919,7 +3068,7 @@

    AuthenticateUserExternalAsync

    Uses platform-specific authentication to associate a Mod.io user account with the current platform user

    -
    Requirements
    +
    Requirements
    • @@ -2933,7 +3082,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -2958,7 +3107,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -2996,7 +3145,7 @@

    AuthenticateUserEmailAsync

    Completes email authentication for the current session by submitting the one-time code sent to the user’s email address

    -
    Requirements
    +
    Requirements
    • @@ -3010,7 +3159,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -3031,7 +3180,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -3069,7 +3218,7 @@

    Is Mod Management Busy

    Checks if the automatic management process is currently installing or removing mods

    -
    Parameters
    +
    Parameters
    @@ -3107,7 +3256,7 @@

    Get Last Validation Error

    If the last request to the mod.io servers returned a validation failure, this function returns extended information describing the fields that failed validation.

    -
    Requirements
    +
    Requirements
    • @@ -3115,7 +3264,7 @@
      Requirements
    -
    Parameters
    +
    Parameters
    @@ -3153,7 +3302,7 @@

    ForceUninstallModAsync

    Forcibly uninstalls a mod from the system. This is intended for use when a host application requires more room for a mod that the user wants to install, and as such will return an error if the current user is subscribed to the mod. To remove a mod the current user is subscribed to, use UnsubscribeFromModAsync.

    -
    Parameters
    +
    Parameters
    @@ -3174,7 +3323,7 @@
    Parameters
    -
    Error Values
    +
    Error Values
    @@ -3212,7 +3361,7 @@

    Disable Mod Management

    Disables automatic installation or uninstallation of mods based on the user’s subscriptions. Allows currently processing installation to complete; will cancel any pending operations when called.

    -
    Parameters
    +
    Parameters
    @@ -3669,6 +3818,9 @@

    Variables

    ModioErrorCode

    +
    +

    wrapper around Modio::ErrorCode

    +

    @@ -3824,12 +3976,12 @@

    Variables

    - + - + @@ -3900,6 +4052,10 @@

    Variables


    +

    ModioReportParams

    +
    +
    +

    ModioTerms

    This struct contains strings that should be displayed to a user when displaying the terms of use and offering to create a mod.io account

    @@ -4030,7 +4186,7 @@

    Set Portal

    Changes the portal for the provided set of initialization options

    -

    Parameters

    +

    Parameters

    FModioGameID

    GameID

    GameId

    The Mod.io-provided ID for the game

    FModioApiKey

    APIKey

    ApiKey

    The Mod.io-provided API key for your application or game

    @@ -4072,7 +4228,7 @@

    Make Initialize Options

    Make initialization options, should only be used in conjunction with InitializeAsync

    -

    Parameters

    +

    Parameters

    @@ -4118,7 +4274,7 @@

    Make Game Id

    Create a game id from a integer, should only be used in conjunction with InitializeAsync

    -

    Parameters

    +

    Parameters

    @@ -4152,7 +4308,7 @@

    Make Auth Params

    Creates an AuthenticationParams object

    -

    Parameters

    +

    Parameters

    @@ -4198,7 +4354,7 @@

    Make Api Key

    Create a ApiKey id from a string, should only be used in conjunction with InitializeAsync

    -

    Parameters

    +

    Parameters

    @@ -4229,7 +4385,7 @@

    Get Value

    int32 GetValue(FModioErrorCode Error)
    -

    Parameters

    +

    Parameters

    @@ -4264,7 +4420,7 @@

    Get Message

    FString GetMessage(FModioErrorCode Error)
    -

    Parameters

    +

    Parameters

    @@ -4299,7 +4455,7 @@

    Error Code Matches

    Checks if the passed-in ErrorCode matches the specified error condition

    -

    Parameters

    +

    Parameters

    @@ -4341,7 +4497,7 @@

    List User Subscription Async

    Runs a filter over the user’s subscription list

    -

    Parameters

    +

    Parameters

    @@ -4456,7 +4612,7 @@

    Get Logo Size

    FVector2D GetLogoSize(UTexture* Logo, EModioLogoSize LogoSize)
    -

    Parameters

    +

    Parameters

    @@ -4495,7 +4651,7 @@

    Get Gallery Size

    FVector2D GetGallerySize(UTexture* GalleryImage, EModioGallerySize GallerySize)
    -

    Parameters

    +

    Parameters

    @@ -4534,7 +4690,7 @@

    Get Avatar Size

    FVector2D GetAvatarSize(UTexture* Avatar, EModioAvatarSize AvatarSize)
    -

    Parameters

    +

    Parameters

    @@ -4573,7 +4729,7 @@

    Get Path

    FString GetPath(FModioModCollectionEntry Entry)
    -

    Parameters

    +

    Parameters

    @@ -4608,7 +4764,7 @@

    Get Mod State

    EModioModState GetModState(FModioModCollectionEntry Entry)
    -

    Parameters

    +

    Parameters

    @@ -4643,7 +4799,7 @@

    Get Mod Profile

    FModioModInfo GetModProfile(FModioModCollectionEntry Entry)
    -

    Parameters

    +

    Parameters

    @@ -4678,7 +4834,7 @@

    Get ID

    FModioModID GetID(FModioModCollectionEntry Entry)
    -

    Parameters

    +

    Parameters

    @@ -4716,7 +4872,7 @@

    Get Percent (integer64/integer64)

    Dividend/Divisor and return the floating point result with no checks *

    -

    Parameters

    +

    Parameters

    @@ -4751,7 +4907,7 @@

    Is Valid Security Code Format

    bool IsValidSecurityCodeFormat(FString String)
    -

    Parameters

    +

    Parameters

    @@ -4786,7 +4942,7 @@

    Is Valid Email Address Format

    bool IsValidEmailAddressFormat(FString String)
    -

    Parameters

    +

    Parameters

    @@ -4877,7 +5033,7 @@

    ToString (Filesize)

    FText Filesize_ToString(int64 FileSize, int32 MaxDecimals, TEnumAsByte<EFileSizeUnit> Unit)
    -

    Parameters

    +

    Parameters

    @@ -5355,6 +5511,10 @@

    Values

    + + + +

    UserTermsOfUseError

    When this condition is true, the error code indicates that the user has not yet accepted the mod.io Terms of Use.

    SubmitReportError

    When this condition is true, the error code indicates that a report for the specified content could not be submitted.


    @@ -5493,7 +5653,7 @@

    Values


    -

    EFileSizeUnit

    +

    EModioRating

    Values

    @@ -5502,6 +5662,76 @@

    Values

    + + + + + + + + + + + + +

    Neutral

    Positive

    Negative

    +
    +
    +
    +

    EModioReportType

    +

    Values

    + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Generic

    DMCA

    NotWorking

    RudeContent

    IllegalContent

    StolenContent

    FalseInformation

    Other

    +
    +
    +
    +

    EFileSizeUnit

    +

    Values

    + ++++ + + @@ -5529,7 +5759,7 @@

    Values

    diff --git a/Doc/img/nd_img_DisableModManagement.png b/Doc/img/nd_img_DisableModManagement.png index 871ccb5c638144eeb3956990637eb8d058638ff3..312725bef43322d338d7360f34b68f5b8fd5b5a3 100644 GIT binary patch delta 14521 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 delta 14490 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

    Yc@=JM zC>};qE_7ht{Dt!OiQVPAv&PA}XN;DAk3RWK9(ZK3l<(Rp$#CEc#*daE1CNu9n~SAQ z>sHE_iltSJbE-OyNC?)g#l;xyDnQfHj1Nlc&;iR7rpqrFuZLD}D#*)GK3~_HJg9Ia zd;Z1Qa@weq<=7(*m9eJ`MPR-vm5|NEi`U-CT)TF?%GkKENUE!Aq&=3VZCe+ADBbF{ z>(u6T7}SgpgAE52w@2b&=MeJz%sDb{ciCL~1&t=XVcd`sV?r7OmyiE#Qx<9_u2^gagdpjFnTF}o@gwwq&S9$LYv05jTV=)>*<12*b7aYTSnG2J#fW4yF*y|bn~y*F zM8=)_r1a?4MSl6?o8|6b|3pSlxJ)iO_e?o$^l-W5CwF4jSs*{W>EGni3nrKz)E!Bu zcg#ARNjM{I-@Yzrm%46$+Pqome*35UbQZ zKjS4itXB_X1HP!JNXwnDk6|C%6t>b?dE>^-vTd6=O<~JC;IP!@Af^fSQ2VihJ(q*? z;w^gX9kf>>|9R7O(z<1VOnqUN9M-eDvB8PIbJ1A{zLPLR-X*ht=f5tufA4C!Zwx$TB4<>Ir)V(_Vfp4(M^A(m*isxdt& zhXKrV*8@*t-#k~#{xszHqpS!&(Y{d!CORd{_70xbHy7jCD$?)&`m{{O3I7EN)ILEIJPng0P5S~BI>v3E`1-?o;);xV!F3JjL8~Af4*M@2u zoa}}MiCl206XJrZL41I*6Dkai(pY-8&^pErQo*!>PAar~%{zJ#STQ;l*nmG=-8oIi z_HE_jb5565aF&bC9j{Ne@BPa|5R2gA6wZV;dc$e&{Ml`PGVR4#^4cP|6oTBEDl8+h z^kF*dw9#^OpF`!m38!hDdw?1&8<@@*I}!o4U5+`bkKS;Yzwix+^%uNOUYa#eZn*ji zx&Erlv2n+21=)iJ94G(rgP+Qdouw*+r+^3jsfFxmn7yw4*2VJ0s@3wrhs)*A9^H%< z&iB&ndGhan*Io&kmq`oEfG3_{v->m8&%i+OnS9UT3eoow!-g0i2LnIw5aP?whx^^> zGiS?HS6qbl*2ss;K9a+5(}#%zU|@%_!{w;nJ>}dp$0#lh`^P%(%qpKNgSc(eVJD{X zV@{SM59=Z4oIWz(Te#>Q`QFtRA#lg*UiQQReHF)lYdY(dH{`m@Cdf6HjF%SK*k=JY zu-}n#%m4dtl;gH#9|F74m*{JtWul|be)TQ6_L4K@nu|}D7CG1_12y2--g4`m_mRNb zqtEerxobu*q>q+t-7Y=5b(Zg6b%EUf=rdA*eK45fd~A<0kZaN$ycElFPgp)Q_gw6-Q(iZ3FbGFYc0hB#7o*c-6egS(hIu4x$o~X z;JChW$4_rlXSwP2pGk4?7Mb|OQ}WKz_Yn+#{iHwe4?gmQ>e8)CC-m7a^0QN?%jgj& zNxx%`LO@{u@W|uZ1_^2WqM{A*-5YO_FX6P`zU)E-=;^Wrvr<|rp4)}{fU@VIj#Fp6 zsP(CswX7|>h?Kcy%NDu%hFfIqy7hAP6&LGr^*4XG2Q%DES^4Rw@{3>pUXn5FUV7nw z*)r#qg(`;^N$u+Glt@aT9^COCGRhn0sW4W{(bw%!%t38+Af{i%jaLNmS5g=AJnRo%g;ScHsbEC zCe({IZj|e9|Fx{f-O?-0KTXaaH(a)Vlx)Qf3EVApdXZ0;Nc0Kl#0^ zT33WNPL&B`Pm*E;4F?6zC``1c`D45vT-n@*y(4MQJ^d7Eg~vJGZ+yyu(IG=ZkOwuqOZb&LaVa0f=|>D8$POCx&JB27hMdfk(ExSC4Qj|2n6Gw;>U`VSg*q%ozKEQ=|08iCs^5qL-gBcF#EgnV(F0UaiQyCximX1v&*&7+w+-!Z>( zJ{0&Nm{8_FvKpzuye~2sG}Y%JTp8%wj)#63h8w3B9MHRlKRZ>BS za*U2T$}!?Ox-iOh8EB0WR&eZjl7v^Kw!Zm@Hj>lpByGBM=SNfC0!$5jZsI za5x%kk1(ps6Nr5obU(%(uL?I}O0fSr=k(Del7(-)ZP(h%bh$lfwsw9l8rNPdevS+j0~{P>RF%bQEy zg%I*H1D&c$dN44lY>j9XEjPF#wW$1_-a#79Tt9q&e6IF!K~)cCa;OyWinFpBlrR#g zU$a!7jP6jSUf6?HHVbgoHTYthx!#&&f{sZcjdX~#W#gH`}FrWW-T$T7zbq=18M zaTW^W2qqr|>dA7DTC<>6vBa@}i~tlgBY^SR&CnbQ+3_q?vtidQ+x?`RTymqOyadjys?K^mlgKnGV(fDuoCdx)$hT7j~yg0rI_ zm_@Ck!uemHad`?DNjqgYTOME|%%y-DPP?m8)zTCOQZL>R4#tYMW6~G-Jsi*D;K0g{vlgfmJHZNbUK0}Fq;PjFh%%@ZaOSmB z77o^bzz2@(uAPY_f-I0r8Ng|kMS_h;OGz5U3>;$Obc$4v~VZh^AiGbpbG-g%XWES1EmYNO=d`?pbcVzc1dq3zUNY_nep^)4>qAO zZbSi3!n=T#sI>0Wx5<0+~sWm>P0O`booyvOR`n7aRlyJS1>L3iAP^L_l$nv9h&) zZE_Uo>BF*|s6eJN2S5r!)4uL=1?!1ku1P}xLBy|y?Jf^*#}b`_!^#XYjV!H`4mi*# z9WSQRlLpcp+{^NG zxgoviiH#iz{XnxweR}81ITO07Jyf56i+jYcvDyxDRV^nU6|3sm+EfUoIanxH2=($w zbrk8eSj+q1elKG2@eZhG^EU0jyo9KFIxkGk?1JW)SuL!Wa6^uAq}BV&qx&s;P- zUc6;6#1KR}TQQFzfV2(ZVNg8l2cBhZ9rUgY8WP5IUC4^wuhP0MJyeKNC@w8632z#7 zL)l$=$gHh3zSV2W@pglK#-Rk^6Pk-BZ4}i6prJh~PMlCmL3<-lX)g;FZpKsn_-2$u z>x(Mnu}P~SmO;X_H(>_v+$mds&N`#ByuN6Qy!QcLYob2HCCTx}wUQGC6v~rNufiMs z?!CN*^aZu&VW~xnblJI+ZyM<(Aq~J}4 zDp|Ow7!Tb;I(TuaE(CzDMP3?S2)4IcR5nk*D~SUro1P38*V`-Mbz|LsaVpC2$+Z3O zR!^JfJQ&cJp82Or(=x6{R;i;|=VAD&LA@jd3Li4=s~t86 zd9Eqyw{05&!Rcn;IG)s&9LxojhaK4`PkQ#ulPS|T;7fyA8Q8ynwTvCrULK#kHfY1s zYR(22TnOqNJK^vsTbpLyzzPZNkkeDSvf`;z7*1R~<+n(c?p?BF&V0U`=;^#oeNK9m z^^Y(Xn6t>7d=92y!)aiV#^addh(CuSj}pXlSKT9Xerxc0LAVF;o`Cqwg^Q?5I0RKJ zxdzu1s1zK!L1jRHF}SeLLW8jsD#*aHy3S&RQ)}e9=68zO5`n!TjwT@=715K@7r>E9 zOKY)0M0<{pj(PHlt>qBR3RTs0c%QHYuO{u%9-MtKVfigv?)$;94R`vR4q$NXjvcaP z75K~0Haq(Mhda;*3<97zXM895Xho@fva(e5Jm;)V@-gZwP-lP1b0L<7E%H)j>3iE{ z>H8colBA#jw!k%MQF<8uR z55cdBdHPq2B@Z&kj%C&!E*yN!BDEf#P6}VG{nzD(a|;Muh}HCjw96_oYeqJRyv0ZmpwglJUla5p`3il zDuZpLN`3(xw-kZuVB{GxxUH0y$K>Hj>t)FYr80C#8CqKJER;{g& z;ltWPmsFWJdA+>9yi|_pU4Q^Hd80;jfKBm#8Th1ivh3qsG8A&xtgply=G$alQKinF z)ioHU*>88`b4j)f!H)W=qdVZiX@xvEaW&qYuaXl6wSlj4`D{yQ4oD2H&sUYBFDcTh zH9nsJUyJ;7IqHZ4`SgojI%|=hx}@S;wa1@YizQKsj2_uu(lcqJ6qGw6!112nldI)_ zlh1bHE&EI?&kz_+)(+?ch2#{-NJ~q>oBQkVmIP#AX`6v>-Kd8Rj<|*>Zz-;p!w<`o zZr$?qyRqFBF}zc`S@mY%nr!1?5V61HPjqkTS-X?em)Pu+qzYM24pA6aeWK$KH_dEEvo^2q1oTfv3-~}qX;}DSmqYs{mgW=-)Enf zNxx(BUEsj^)wx~nwk#a{ZDr+yBTh%S#e>5I!4ap?APV3OhSWZRu$oJ{&%%X&iP4aV z@)UdF(G~|bYpFI=JedkO7}+_ip_@qxqtaB^a?Vu7r-TFt2GJP~wfy`HS@}6eX#@@v zC;a)Z+ouj0_ynGxNbx~8otNwNoSZa#nTydH^f?&uxx9M}fmKtRjL-A&qA;AKv^)up zo(<>9mH7)wK+^&XJrUJjItfGW!nynt^?tS2uggKhJgcLI=9Zm%$g&QJh?_{>XKybh6;Q^ zD;U+YbVlufndZ?aR|A)fJrs!KwhVDzVySpcb}H(-lU~?pX*-EVYqxvhgV^ z7$|qKw;kYI7VhAF6839+5@9$(^5S%!W?#9N8K((? zOGiG;C@MU~f+d+s;)O&m34Oq5P^l820bG}T3^uQr3oy!w2bOk!HBj94WlkB;F}QY? zVJ1k0Wg!RggAe}lrT1ak+AjPI8}e!dS2}31Y{ebSvI>Mf^zGO&3rmzb*fI|F8)lJ154AV;+3j^3G16iNE@+u4>)_y=MJ<^=8R_^9M>t<;DfB?_&YD*u z1CKAzJi??DBFgMmdgV|;}!H1eP(y3!EKJcrRp55~>v#ysR7=?>AR$>X8 zi#NurbpX))EqcMPgliGFT;6h7SzT>2C}+YdI4yP0z|5A3W9P1zbnB91GC0$6KMXZg z1_F{ZqmD|hH>@mMQ6|e*mPwb+Su$d1A(qIg+Ghq1-e^*P9xemx5bWjUb=nW|?JC1{ zrO{F5jh`9>GH10}^NL}Imas=F`E1p0dHqe?ya9X*maLq)+O^G;4I8UeN2>8M>1n&; z^5wHH%dv#z%^nLb+McOH`%K*v@-C(G5?Q-`H+~xf`+oSwF3f=RrJSr}tN>^u8?19M zAne}FeQex+k5nLNRSt6U1$ZL0u2hL9Plr6!`c3w#$~?4(mt?+#K?2AYGDhj>*UXQcrMKX;)^rPAG)9S}ThrO)A6(yd#z zJTqgfj*9({&DGJ2!N*ymj31+NxeDq`{N6()ozew=2_2L87@RK^U#o5|sgs#=Z5C9; z!Ae@*g!pJ>h2vwZmRew6!DZs^>J-Vv@{qEoy;OqHK1I$P+Xi>vYO!>&y&pMpbMR}$ zSnBO8!)Gf9uA`2~*WmnUWjSE@niezUiqEiz!i>OK37yo2TDMBq8DPuSS_}}W=mY)K za5~t3xFsRWcxM(fi0E>#7J*=NT#BXX?^YB;hUaA;8BCo!X386HS-;n;tHPJtW$OGT z+iD?;OF+FMy0_!3$fYxvi@waw8}~WfvzBbDk=)!g*+pBt$bD7{_F1sSp*d=cVk|*> z^~lC7l%`8bUh`bg?1J3qU)X528`lQL@oJN}C?bEeuamZ!ND%C~FihKpr<3B~EMfaBtfflhsKiH&f>{f1+OwUOEwcnaKqR{=)1*`9 zTYKNN)1ucKGAv#l+ zhMD-$7WOS0OH01}rTa+VSM<9@ekNu;3&37Ia%IdZZLlxO!0Itg(lGMxD(4It-)9y; zR|a4$2Ba<95bRlL(zb1uyz@ahW=Q;xF}i<)10l%Ux64A`GO@hMkl~m~KKQ6y2Z0@k z)wXT2Bqt9z1pP5bW6y|S)j@v%!Bxtc1bfO&CAHEHGC1pI=cLOp$aw!FyvN38k-+PL z*|rXWas=+ccES>pe7Sk)(j7N+Hg3UB0U%JhN6XGmSKS64-!fPtQdb61Tg*UN=*LMz zTH{x?cI#~0vqzqc!JaD>OKYwWQn57TQj#wmY(j7qVlTv-9BZ*ur9*%A#7s2$ltS1H z_Cf$DJ%WR-oSBL1jmIwZ$IV#owQHLJT`(A;8`Lu$s|Vir*p8(m*FWUZI)VvnDE-H! z@(#>o#OdJ%ZpySea}5`(gO0zTW%S4c`gj>64(~TCKKJnYIpz6(aUA6^1v8i4w9q|| zHBTfnJ9nQTj^ax*L~n@Q~(#gY`%0pp*>0scxhdNU}MmsLy_-ntU zVXL36iOJ}pS@-}iOTNUYTZX`@tieS^;I+U^K<7_Ja4~Jf-P|wN#pL|)ZFG59iDg3> zoe}s=2+$8dsm2$|xEX@BHxyNazD$xZ8m?N0AEg=58b5Nf9ZP>sTY69)X9^!&AAgSD zyJ(*zS6qmj4UoJ1lim1%Qp^&%d?htzCOEnU0`_LmeKTf}HR~$j#P~)I&YA*`;b2gU zW#+rf%H=HF0i#J)d{!g98eFgot_^45 zcbAo+Kac@it@wX*w=Dh8ZlsttJY%o4u@?KoQaNdGYs~ntU1go_X+QiJ!3wg1m%;~<<>ODwF*szx79C)V7-pVb*i+ix zu($;KT%mPb6ji^up+~YMT z%4maXhJ@PG6uqI8K5{LQcjkI0tQaMop?a0Cq{ zwVZE@aL-#$2c`3Tz%gm&%38OwfjykLE7zCdNyzJIg7y`da7rKt#>P)0QCvvAUO?y2 zq|iDGq#+!603&>lb}2EDLdilh!`DJ_ri2wCpSOSC$Bk+&Pd;1Z?rkXnnzCyd47$pJ zlj;u|N9J!j1m6vkE~LM*DGynk4+j14a&T<}xfJY#17>g)YI2p=H|}$y;$>}fpQn1X zVP4#);1|pBnF|KiTe%o5`T9IJv`HX}akIRKg4}m`rE&2n*a=r!;B0LiHv})A(x^^! za;JYB_|$onpK|yY$ML!wuL`j4y0$1UD+@OuFo|v5QHLJ{P0{C33zlFs_cNiVbuz6j zlNC3nIiQiawpr0)sP4Mpl(2qlg|wc|=^v_ldQa->ac3}yGn(Goj!SbmCr@n==mwnH z$Dm%WZiV$^c*4UJN~iLirL~Of4TQGqWU_y(d^iQRBCX%}fI16HykSEMFyrm47g+Hg zSe(N0;MF$#N#%IDpf%G%nZh{e>U56V8h8gw&` {}iY7Jfu)|>vesG2I^j)22c%v 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 diff --git a/Doc/img/nd_img_GetLogoFullSize.png b/Doc/img/nd_img_GetLogoFullSize.png index 58cada6adce8ee55db1ec56fbb9ad6b9e2ab3aa9..4e19f82858a44fef5ab0790b07e23c2d7b3ff156 100644 GIT binary patch delta 5702 zcmV-M7P;xAIHov|BmwQQCG-Vsu| z^JSZmP$NNSI+Z*54v>df^9ptV)a|A(W^%z1LoxCn#$4Z$;y zJdd9|elJd(IgS63<$^= zVEHN&%OBi#`K;X1A zAJr17V&QYIVDq0hW8Wtq;h~>CLd}pgaLgUZKA(-&&2GkjFYXl-#f=BZ4~UNRH! zeYn%e5?qQ*9WFi57cY@7bv+!}f>ZIql~$6+w>*PNpG}Hc{Sf=AEpw*kBEadjM3#94 zs_s2ydDmQMdeh|Nk?sxw^yeEg@Ya1>JoNAU?FZQU_)gs(xP2^b=)pE*LTJ>Wu{OPX z?{2vvla9)Nk#*)A+IMS*aTCU>KdH4+F?+^r)U8t&^A^oRd|W)9pE3>UDe0Io^9AJP z<)NUU08^*^7Uy%$n@zjU_+rlnhyl^fypNtzGX-;Bm@7+hV=R1S0kX2P@Wg~CaC`6D zQ8%qFrcR!!Gu7hPUcvYK^OIi&8c435f;ls+-r|LS$jZ*bFCTsaw~1bq0JfwsfP?=yh>T-La7&k4 z@Uvl~P&>H}Hf-5|2Yz`!cI|#o$I#i>`_W!ZpFa&V=1<4=UE7tsXWt%VpUXk5q!c{= ztLdnJlUfIhSH7&V{q^|<XZ)TpYY8WQ--(eub3DvwS<2?61+W@kO1EP=LVYb^U49#?U;@jnSm*P z?ERCXFC8S`*^*obgSi}W@^LCtQDLFVOrJV`1Mk1PTaPVo|50iEdiO`w#Hx7vowu=J z(>qwdaXqS3se%q|J7AT}wgrU+C@Lz#k~fwhFE`J$#rAmc>X*c`)*W5){(br*DJcoF z=FP&~MRW1!uO_JM(80sdvqw+eHY|8~KISZ#gWo>)8|BebfANQUv**sjyajXd*smUc zHF|@FhPEO7X6oFr3)Zg^zwL3etQxxf3D3lZF)~2ZnZ=eVqvJt2F~uh;ycZ~yo7a5l z=ctE9V$J$B_~F1GVb%QAcGvY#Z7%ZzEu{_aB^uShkZjRF}WM^utO{;E*LYG-J!j(OT4HGJ)mgSaTR?HjL>zuHWeLg;h2A7i%I3> z#E(Xq3UUhJ9w{k7#&V_G8vuF2j;!dHzHI)44-uQx|>O;8-!yKJQ{pk{G+PL{P2~W$mpavd&`VpKsby94^ptj7M zOg|blTo2POP$Q|P>}v@CN0D5N(H?1DKgBOkgmn6A`Fat0Ize5vL$gj%jnXEG%pHRw zrtICt%gwOaM{%xOF2~-Os1*RrsB2NU(>Sxq#a^gYTt5fvwo76 zeT2;8nJV0%egoA_PfJIoN|kW@_;H-eI;Xs}v^2?mN>a-_am?s7sIS5B^aQ9X>bk5_ zz}a(Wv18{BjR#4L>4mR<&MP;us_fT8&08ා$1FPuY-tP`PIP&LM@ah8mUT!3} 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 diff --git a/Doc/img/nd_img_GetLogoThumbnailSize.png b/Doc/img/nd_img_GetLogoThumbnailSize.png index 40d14e989f141a6c6f0640fdd304e0f7ba3822fe..94b400fa253a62bbb17473032d5a9886d4332841 100644 GIT binary patch delta 1152 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 delta 5415 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 R((V8N002ovPDHLkV1hl?J{AA~ diff --git a/Doc/img/nd_img_IsModManagementBusy.png b/Doc/img/nd_img_IsModManagementBusy.png index da7ea0268c569e724eab527557b2f6ecc2563fb2..ee27ef2c29c8691e7974a46a21a3818ccd44e4cb 100644 GIT binary patch delta 6363 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 literal 0 HcmV?d00001 diff --git a/Doc/img/nd_img_K2_SubmitModRatingAsync.png b/Doc/img/nd_img_K2_SubmitModRatingAsync.png new file mode 100644 index 0000000000000000000000000000000000000000..17d242fc9e23d39728eb3f02eacd453d7a334e88 GIT binary patch literal 20908 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 literal 0 HcmV?d00001 diff --git a/Doc/img/nd_img_K2_UnsubscribeFromModAsync.png b/Doc/img/nd_img_K2_UnsubscribeFromModAsync.png index 2c861ae0f0ca0c2cd9d1bb583a4a0639441de443..4e66ab0fcf4c049ab568789524f7909cd8c7d51d 100644 GIT binary patch literal 18712 zcmcFrRa;z5kVb+85AG1$WpIb!?(Po3VQ`1w?hXkySa5f@K?j%M?(T%mcd`Fq_u`z> z7xlDMRljdnclC) zR{0_!k-DLKa?!u|8n~I2<$LLSroW+Ys@mG%yE&1|Z9SF8asG#gM^OUe%+5B|=T1?r z+FFRAOJ3g_-_ol~w-x<0B!kjQ&NgUI5s(+h>aA>5Yy zu)`j~ld{czVvCb)*v<~_+jo&qLUFY)pMplE$$fnDmC0t?D23iFfR8{U5C@=`k4fYD-FWbrF!){yhAmrvnkVJO2O$($i>yAQs3?D=-+_`({)b<1~|acs<#8R z_9d+i?FYQ@5 zTMX*TdAsMT=ux}XJd6CT(XGpBFS=Bj9`#KMc2EW3f;2^O!ZydkIjp@)E9qGA8b92L zqz}zvIQFy%KrvQ%Axb|NX1VD$RqX@p{BtMxcd@Z|brHVt9T?f4t00XamfZO9kGtMz zV2D7$a9LKM^-})!){j5zOVXk3KbSFa1l2& zw~zB#DbdIY(xb*Fp@AmO*$t2$3BPLEbz`DW;a5X}x%;T?s}ONVKiHTgociSUdS!<= z#}|JLCz$IkFG>gytMxdF)hW3QK7pFycebD{Pw4eMH$N$4qFh>H*y|ErQ!2WvV5V?A zP{$DRPgL$H+13tkhkRQ%L>J4HfZn^_r5}evG`15}?QW&-<07fC zxd&>shhOSV7j>?=t2xzmrv>sou6X6Fa2r#(DFZ2u6mi1mCK*(^HgSKtU#Ce1qcEwM zay!jQ`jWAF|3SyBY1V@@xPH+dyTJ>z^E$JJebhM}K<}BrSIS^-VXGq!ZSh=X_rJ}Q zJMO7;6Q^K~E0+=fQNG<=!70r+kM~h3v6x4XM|3^WhEdbiw~h6op?!P3k5OiZV~0#x zH>Mt;(^ki)&TXr>%k}JI#$}Ko~_gsZSsVAa1P#W|uACgQA#K+9uBX-GkJ~up8Wy;3I89GZ&`-nG8tCa;hVAE;Ym6?@Y#(>P#Jv! zpJ}AcL`rhSHu}XKX11VO*rbUXe`CZCz0@lbm0Cf^dhzGFl;T?h*#h^dj7N`iiNnI4 zvxbL)mSYzu5cU@xSEzI+1$rg3`!>?##uf94c-0Qv$)Z)6rKP#z6N&eKDCt_8p%gf4 z9fax}fAe-kN<-;M^;FkV{+m!OYX@GE847tUF11f{aUCsEaQ906Ws49KrMMD~W_yx+ zC;9wKeqYTf4P^tABj|ryqL!FLKPUXRGx(c;`nQHyv@~hD{iPb6atz@WAj6BAx>y6ViRg!l< z$JM}_pUYy+&F{pyxMbjK^FD`@4MvCU@A3M5zJT8e^k4-6b9YbvG9|525yeuJG*nV! zV|`k8(Ue85vbkVqgIvi)%{0@Qia{oKaYPGf74u|FUOL#zFvP-X3@@wzg zCXrNe`1>@s>gN`}CYv_&O{33&gI4bhe`vIH_+M^+-lAhv^!%29k{s{dnPt?fN)Fuk z=wvczmg_O1Ko&@AXJA5YCWwXk!{3wya_aJ6JZT~t-&-ztQ;qQ`O2K@dQ;ZjH##|q) zvxQ|ZsHmYK$s_8JX!o#TR(`)dWVm^tr5W92RlK$Y+OMhQcMWY__`JA#?+ukp@eev% zi|EYhwGFmYolN(JpDz4#5R*qk+;x0y<76F8vvcy+E1k#$Ih$*JkCIQbton_>2A{Lo zY)#JIDEG~}PR!ffk^p6mD=#Sw!wFJXL`X89TH}>|?nS&Fk+eCEJXGNjxtKaau`QW~ z6QW2`S%weNfX7#org+F@%ZxYCF@_gV(D)JE0W)UFkep;lHL2&G(dmd#zO_1eS~oCn z@SXd&Nx2@|7r7chVz_|_(q zUrDCwJRHJe2?bP5#UC$=*iW^zdC4mn>IJpHOC^_M&NbNaOCSYfsE zRu}o94=cKP5sKziVkK>8a=9g2eFxS@f4z2D$+UGuVzVx z@pUHaSgU`A!a$I|A%Q^P(IT6tVW83H=!~|9dHi0y@WFNQ<1aQ^w{$574QzqM^C4&0 zk??b1K5AcX0B<)YO_n+$Z z!LvJvr6Is^Ili6V?wf?uKn8Td`{cXJhKRGdjtDezgGSaYT9+ zhQu~w*7U$X0&-SU&wBBM0YU4Zx?iQ^QUpl7m0liBXcFEJJptRlA1%)$9$qL6`BO*D zTMQV_*HTCAF8%0u{@k}}Xf9Eu%I3d6uBcc49n*z$x%uigyT+|QY&G0GymD9^_4@BU zh!`^O()Q5$-k&iP83%|9|HxO~a4BM*y>)x zrFe$N#aA{nzbAUD^kFHmR#m#{bX){{sV;z!zqa7*G2w%Dchk@Ky6*>a&wx3 zmv8&qeKlytH2Yp8&u`k1gbmJ#1v$NX{w9HR)tHD%TH;*v*RGL}09X?*m&w=ToV;?$ zAr)j4Af2CgRlRYYH1LonKTSx_x1tN!-(|It>Ke&aWRK-7s~La&el5pmVd7+)ej#g# z!>`1d(vU#LVok!M5RH7h4-NzGizIYXHFO)$p?|z19slVn%JrXQ1_X}DwVff1jCs?N zFnk0&N$Q62f1ID(?)_q~k?#@e7~kk>AHCBx9=mk(R~YAUN`HU3OJocL)&ozMwbE;h z7+XXDS{u*Kr6-uYR7jpv-z1l=%!W^D+^Otqp)`^&CE{*&<(Xow)LEA~{>=$^)J+OKrSb#EnjMN471>QuHb3ynz*pnO!GujlP5tMcw)>yWMo?#0m8}%Dfx} z%P!tnYn>4CbAc}Q1Q)qtA*Qzlc0TtKH%QVSRePS@la+Cw~)b>y>97( zbhul*{_Tg1kT=1$(`^v6uT=HxF0)?CT)fcy()I#R>9|mWAR~G_VP$KEk+1ZH_nofy z-my#e;powsww4h~N~uCd5jvmfT5lZ!dTN{{&douG%^RY7t0!gnT}DW!LEGWAOJ-Il zRnOaqP_%&ipqMNE1N_tIfxmJO#iMDn8yL0-2lNQXP0;<3U*_A~d3`~9Gt9YbLm6=& zvGskd>8`-_M=fLT4yyt=}&ekVy3P5*6&TF273s*0l;Q`onJA0@xDte%CJhPkI z+n_a079i!ir$Q9~S?TJ!K4R_e^?{7jdp4hcCY!B;kZ zbmm@1@KAo(2eOVCuo_fkUn}TCT^cdA925xu=HSQZAJU};8_ktT5T;bXumBxd1)3LLg}sI^NmHA?B`=pu+jZhyi^Mk`Z5 zvN+w!b5Obt`dmwUW=--XRR(Qp71zr;9m%+AAxTlDvudj-B=zSQD;Qa1eD)$kEe^Ur z?x0p$%MHR!@1`cFf>Hvg&;{pIl}4D3Q@@Ds-PYiay(=eVxB{_paBu*(G0*jZn?ie6 zeeW8>KRin-yXLb7!Y1?LuBZqL=eW})S#gd3pavMwrt>SF>J}BIJgsOS-@%h=@ z&h9!Snkz?@R4sWcP-S{8I?u5wMRmLZB_+gHMX^mKB^9DAQzY}EsY&4*Wdc%S;gE$& zO}t6xOl|+4WH5{nWV`6;o~Li|LhpinkF?q+bRMV1ft0^pLU|n4e*$ySR2^&kg5rnx ztGKPUmMPsV^b%~H-vNP@0PU)+Y$VhkMftQgyhRthf)AnN`Rc)p^1O^Df^$$XPpF5b z$sxR-SlL8cr563kW81sSnbNRv2hCJgU9SM2p$e|=>L=By|M1LvM+>%L?vJ*0s8O>AWFfJ?Y2+*Pdg;h@Q7K0U=3s81>&RcGk!k z&J&c#qF&7JB=R5biP~04+$Bgj$$OCOWWqhDot2I@I`pO6jwW_Xusl+mglab$VS8A< zDP-PoG~1q3KdPD^a{S=aJHik*KeqMkFGtVIsxwkplW%J1s5$wG@g3XTo_GXhx6>2@ zzroAWN$l4dxiD=XlWoo9sXiX+3_9hWI0?lZE*$t zD!(*EvVYG5Dx0fNr3M3y}M@mtpTN6QMop6zWK_Q8xcXv+%+u%C5BYyt0Qz;s5zHxE_l#iX*eEwNW{ z+S0o)6<)IjLQ{unsvW6`mcGqM#4p#kL7u&v0?|b{Yx&!L!PqUU2Y}BRV=&W({E1G? zYk2P~z6ZX8b2D0_8}m2`k7@neQ|_F_-+pSqZNqd49$|xNb;@Tag(PqQFx0)@;gP) zeW_sYNE}^sF@>o5r7qUjpJB1LLBWMh+#N^CrExmSshjr0bNg{d75n&LQ_n*K#Xf@& zqtb1~r;s{+gzh7yK{-)=T1av!ZG?nRgWuDJ(Y)>qkzaLLe2s-NN$qEp-1lw*_H%D*w z!Q@M$z?&v47q%I`x1+<6u<_g=02#uE>+={+k7%ed6<)4yy5D8$t|iw=Vi*bPsyys{ zI2OTcjxQ!qC8$9>%wOAl{(WqJX?%woyw`s_m5iw{_Td4}yXlv&fw=@Wy85k5Gz@Tf zA$4(^mPwYiZq1`!Iv6_Y}5Dy7Zh2FO0bj9*c|4 z=NpjzMW2y)cCP=8j6Gc!$W>=}HUe$&uDE5h<-APqpg#(aRi8fe@jNE3GGQ-1LK+PH z?gJ+KdkHf$KkgpbW+=B*JY&A;G6k zs8w*T&ob8harqg}@oT>JKI|vIlQ3h|BN}ub3$|}r(S`k5nPj`AVinjA!r%Dw+(Fe? z2X7^0vGAnuTUTEO+1ZBh1#JzkQUdxhv;7cHc)K}VY;x^H4>2_9jybM;MNwHE*k8h; zo*^@R#HeP9tDPyq%c471NbYQCX2tb*l%@BZ565UVyfNAg0Zz8OaYpG-=$ULdf={9p zF%9)&`{dA5W8A;D(uu139p9h`Tpp(DL(ZRzVs=088mu;% z9vs7N3%VhpkHMpYT`0uipoj}8(@u$#s@Lkjg!(#MT?L`lJ;U}%$ ztR-vXltW1nk{(6naI_qZxQ)2*N)jG6cZUYg9WXjWonVf_(@*Vx=6vC2kiYn3v8w^xY`Reo-iG57-1#%*;K)!hfit5b>Dd^2BdL zA|-5&f3jykm>K_NJOW~hu)v@yGQ=S*Z7xy78&Hfh8tGgZ$x%d#8IW&FSs*bpc9XRX z`4YATHp>QJ03S8gnMRGQp5UNCb?tQ2?8rRPO$08?`AFZxFKLa_W3AxSIyVVkMhSaz zifwQ&v{w&4--ebN=2!f{Zi%LM$Q-fWz`<$^bBHS4DNX+LjJoj$5UM6%m#nzB3IS2W zu;EmGV@hEh;Egsfa-$1>i>I${M6rWQj>IGt+n31$ol;JPE}fy8{N-G zzreRon$g3cJCrvO3cWm5Nw3e0OeSnx!E>XlS?MR^(jTk#O9!VGRS~CI z1jPaf2 zWxL{tXV_V2H^@b|2kta)p2i{5pFd}26#C1^9y2oWh;_Uy)^{&R6(xP1GS*g}u#}(B z4O2o*IqLv~P%4uBIcO^V7u*QQR@7iBUTy%z5@X6^Sa2>{BeTH8tLI#o;^4Qri+5D|en*`DG1`|#PBts}piLYArw z*4xaQ1?JN{eZCq&Vwxpk%DyM+SR@zBR^myD62c^JIk|>rtbw?-lro8;COd?;(}gF# zIY5(6?)s+-KRurfw&UqZbZk`ITAf4@sjZ8{&^MhRb(Rdzo41!Q@-MB;)wQ+6l+!D$ zbQ#Wg#6q`UTNxQYp_SHf!aQrhGn*28wo1+jA(`TT z0SOmtgLl$TriV4r7EEFP>W83N#>y97bxm+IP~pJ%WU0R+A=vE`V5Xl;)GI(hH$hF( zblJK1Mdl}`Qcq$?ZJQc>WIZp|w=?3tF^gDVOWtSM;La9!vm0FEcGgrS?|^G1oUThP zLf}^D-Rk#c_*@xh!ZutJ_x-!2RD1KZa%vmhJqiSx1QSnZqKI3GSI#I~RMe8>VLocf zIjv9X&ASNh1_W~Aoyex0pYpaC2H4_st=#Su73e_aY37 zQDkTeYO9ZXouErqKswJVy3B|rYV^e+2Ho7D%RcM~mF)6Sss_h_)>qpXq!Bw8Djv8& zf4$E1UAlQ8zi|9Auns*95e&bysC`Lha@yc*m{|$sXVcbibvKN*Ou4{d^DowEE}zrH zG80rn@JUC^%s+hP2n(iYZ3$|H`hdKShPR$Zk-=`xkSAdAEO>^VSz2~ny*287`$VO7tDeXAS^om^HQmBt%1`?v<9+~b3d9W=2-As$J#i%doNY#tn(Ii`>e+C zOVL5%^#&_?T0i4S7*SIoTcLF&O9W|(2+pJXCVNNt9g|YSez-)q495?jfE5PEU(g7c!4n?Gy_r_LNiQ8Ltn$ZAFcR;X?caQTECAAX~DIJK? z8z>qd4^%^E!`BBfVT`hdl&1=pi_^|!LzRkCT2M@j6eVUIdG!+Tr`tLc&^`CxcG%?$ z_}WXmH;w;;?hNqL=VeY9g=2ytgrTtDDxm?bNFPaypQO^Hvq~F2zBr^zh`4L1wZLaw z@4GQL3`yw<*4BEIYV{F8zULoG0L#_y&wJ{x7EzW&t;X_vN4=QdJLPaslE|b27ABVT z6jBSBvDjSG!*epr7O>}#eViHV?rlo-Ozo8`v8;d~p(Iky+LF7K$~KE#T?hms=k0s) zT`<$6z|Or?XW;U`kK^dG*UdbtS`#Jfs&IiDXrEE zT>N(~pg`?h&XV~8h)U4oeG)=vrV2j$15)uhR}GS0OeX}4Uj;_}j{Qn7UcV6WtMKZ# z%0a+La1I_%3h5tYiybP#x$K$eolH(J%yLl33^Cf^%rEhLKS0W6*4H2=gsIw1C_xmo z9EWw85l_) z>_g3W(y6z5f-{yjz9Ag!qB_0v%xw3w%cCHqJpMZ28vP>L#i{Ir+<;2GcukzI0!bq1 z8w0e3i;yIwObebK4G>w;a^utUoz%JX6Lj4XHmd*R%`L}+t{&jF4LOEdO6HgR$}*tQ zuPL?N46w@XNBV~5K99s9n;Egehk*J^i$wJt!A8lWofyzq0vx8(&@_xV)R(vX3v(+U zuC9Fcvq&l8fe&!s)#Rn&&_L|tY zjj>aws(#oVk3seK>lifNnG?u&+f5d90AHN6s3aP`PN9e)1MA`C83Z^;h-BFAJ~>ju zb7FDQVYhb*=Z6Uwarq5IiDrjP(56>V*sq}5T1I>W**hv)waX&&(};et7@g^(hIHve zTg;EAdctaME$dEZrwyKpxwQtkAxdH6`Fkc<( zIx;z(nQgYuVz$m*HOlw$p^tx&NfD1|f)OHp8YvSwp5#(P%o-tHkmB8LKkA&ixx$h! zXFt)1C8ON?1=}YC^XG(1({=pX;Tpp`4QNvkXFMs2ccf~h${32U6YM$<+##~NiX@f} znAiJgdf+CLtNc8(>Nmo6H~#56YV&W1w*e8i^BT*yP8!?&h^?t>zktJ7;W%bS;)T%A zjLe@(qq9-!I>f#i@DcO)Ap6g^S-cL6Db9nq1@XK>e|Dg>`THXeWhz~8Et01VgBV$` zfUSuvEK}*ImSuuR%k<8v#6Bu^D?d^=Nc~*P6+VC|C}gXvK+G+ArtjfW`CpaejaZOz zwa0%&G=^27cw5Y?WnJrL-JPp5<;>vgPN_z;L?q4aZ_{RsR!xH~o)WpA=vC7cd;{~C zbdAc3+}%;LIZhpF4ibCnCV-g0NXeL%(f0(V)U?WqJ#yY3MRPtupjKY#?tJ54Xv_7M zXoLanC#};PLpS?N`}L++QnE87-d+M@gXrmGf#2CnlS=?QqYus+%W(06JELf7QRV9c z39N(YHQ-`PMxaKHO$rKc^a27ovO{VZTvnMKVZNdf^_;K{EyCFn zu?PYAiMIE$$r5smDGX z;4-yUAk^aOW1WLejtNal=D|W06%2y>vVbR}k{@F0C})FDpo3u1Z`pBtkP&CzRPyGwVJ~I+ zYK~>^){UbWft!|;q)FoY_c@nbc+zUAs3%)eLXUjlsTN(zCJP+uq85H!bacJyv_fiD zXcN|*nKT9-l2|BNXXRTb3=nGhOm0LuqEvA+h-|EotSFDu236yOwYwq_=WL-)w$V|X znUINaZ)XyJUnmxnYt=@;b37v=Ux$jz-PY@hFd|0N8&axBD&_okQ0Gr76&I!!)6Obx zE!N@mgJaGVdBOIi7>>Bx4J4QrEQX1mFAh(fMM=KYM`$0D89a>YNWfkEDPuG?i|8u! z3gAB@#L7B1IxI9jp)g<*A;>RTeSd>ozt@$aeUc!PUR{1b*qAM)63KZ16Hfpm2q{w0l$ahn0{+(YAbdRW{J z7s^bzUY}TMIBUD=m;p4sdk#`A3a^EzNu~=x;;y8vK)rr=3T96DO95(M&v+|6{>69= zs=V==FEmQZ^@b|w?%3_gCas)fe$1E#oGBY1np_DY)R*!L~n-}-nC}bV; zf-Fa&CF`|W|E7NSULWPMbHQR)a}x^Tm?`!{zITA99UaoBP~z5RPcR~T0`g9lMsx1h z3@S8eE8imHA{loQ=iryoO1Dtkj2Wl4fkoh6;#v`m^||b9 zL3?Z7ul#FoG1D_KV5360PHz}CYmQ!}EgfeRZmWy@mS2adq#Z=>80SIU9)RFP!=J5J zwXoJQy>#s4jw&$BN$;2x_k{{oDTjuSPd7Pqmu)53c@=Eyit4NagQs9-X%lgx{lhDN zTqWN2dmHdLH^$bQk;GK@kdPP1hvxkg#Um2fh!k6F<&aCmYXGHWnGGLUr4ln0pEvMB z*3Kjb*Jl=2-3Galhy_Q_RBo-=fjhuhm)>sC#VRpg9a~OJKX$e`Y+_(k%7r{DyTv-eZ}Qgs8p4d<R?(82EpGkti-;z!EO=wcvgrO33cq8Je(bkUq z7gc>0I*pE)g`&P>rG(yRlvu9=F-#)jxHx8Glt3o&BG+#98~9_N(fIUsqv8}b4&hH* z*r57W-WS`FCO|Gja{pE)L=}to(O13@+tD_YS~0+pkWj1Cel?cI-vudl#(J9AA!xe0 zQOoyE3>K-lHt5OTcB7Dh7*j&96IT^2KBcUR8%=J*j1$1kiyp^-RkT(C(evKFH@TH` z7wyV69~XR;&mAmv|5S7mF;G0~roB`;hC9k6x@)RyK2j4}R0@t7Nj2e_8^C6KlKdtn ztdtR9K0}{TQfb!{7CAVr#i-$)<*yA-{%&A=v zbZA3l*eejo7N*%<&Pe|kq z0#X+^cHi0ZlrrpNJH2`JBd4ZSW7V}c0uPS;98};1(nBK}`|Ar~DD4P6T#>KzXE4Y5 zrLdMRvocj@f>*3~Iq1X?>PSh(lK-6_ijqxXr;-AR-(@cs>)MzVUOou0UfRKRXlhiosGO^j*;Sjw;;$x7sv`i;|`Y)G8Lj4GHPb_isZFs5N{RJIE zrgS4P`aqswzmA%ar4yEwSKg-uZR#xaz+#16tJsGf=+El>nnOS}P<=c1Cv2|IQgTTB zGUZLkIH7z=N_NZ!9sg2TVf602@UwX3AgVe->kP!SM`MwpZu@T>ZZ0Q;Qwe<)1L-LVH*?`jr2j5U$FZv` ziYk8yv20pyrAxvy`V&OfRlmgD?n3KD3376t=QG}}%JQ&v{rk9figsn~#tkmqFSD~5 z*I$QG688a$rivcw$KGpeqArH4b8gc`|C!KJ=n&3t(p3`f&fB=-yJgs;+&lJ)nMuqr zO@04+Oi~NhqbxbCbl=+(`c*VT&zEL|3VQR>3QK~1oqBfVu=wdL@Zu^ZMV(%lKPSwj z4q~7i?aiJTK#z2(M!mD<;&c7G75jky>na{EwbCQP&1F7UxX1vF1frG!ZGffxYLXIP z(V(i;!TnEAmt+CAfsNUy5nCRK*NwikveS*js*Y!%OTzIX13zoq9@?LP+rO1XVF10o zWpq|Lee{;~_dM!Pf`;+Ez1>w9gg>SomdlDDb;osyKMHgVH7OSWk$eIk*6QLwXEi+Khj#b`Xi1U_AU%!zKRSV zLk~S!B7#0089&(ph5If(N-+hMyg9#961If+@LN-3bLPIh=mCB^zc<>tGE$n+U#C`|T{*b1VF|>}&88ii$#6#F&;Dvu zd-6UYMmNgc40P)O zTgDDcmr`O+3wdudlucsEFG^6B1o|(M{M*8)$72#|H@X{a!te(c*~Cj7ZBa9|EOBneX}Ge9}&IKJl;iJ~T6 zpx%RH@aVK&1rN;1kgM@UcZsK01++>4-)(zIR2#A}sGDeq;#{WjK5>zpm9e{+^3JXD127 zTbc4@I<5@JXRm|&e5L+&7KxsT@e5_oI{PDCwkQz;7q33)+C>G+iezI%fWHz;SCiM0 z@i%iQT)WZ+e@9KDX+N!v_zlYPwLogoXEU|32e}He?!mz*i({D2-RdVk$?E7GD?dZY zmKc_2fns@zjG-a;yMQ?zwOVIng!vCbiERnKf0oV`pZICEHVQT9#_F{%S4KL z#N0fNm}yI0@8*S$>J4QsJv|A&U}lTF_el-$LWUs1GHiRBQ}?R`Wf+mJQlX0|1)Gnp zcQ2ckp5N2wiy*7f6;SGEu6K^hP40@KyG6G;J(L2rd8+nTpB{fRs+QNcBhkYF-TahaF0n8Ig5p@a0*63bt~1Pk`((rK-j%ySRuPlpeVoC<^=9H zzjX_1Em28zYYP3-bi5A3nvHlUv{4?;6()dk+BrL%P}EGVB4NLXT(QuvH|_*lAqlqz zprH&01^4NYV16d6}sI;LZe<2=?#d+&Q9*7&49Ru@CnVT$YUO%krvw> zN-|s*ZhsLD^JgYKMGjY$(bE|a=kc|E8T+B5>Z@GS7uGT62vS&@W4-h!r|7?oQWw~EDoNo>v+Nlfe#yZo{kkzz zE+vD|4CIaenuH0@Zt{b!OZ=Hrl#L|ZZWRgz^!4*NhhQI+e#sIOkyTXu8Mpmh(Ip2>d&EP9CAZ@m3K2>{Lsij<4>qmDq}W(OUEj!DM<=Us)@cef-_s)z^U;&_6a89x zXgd*!!N#y$e`A+Uyej9Qoh>v-IM@&Q5$p`0o1aah-SWg2H`(&b++4>P)Z^Y&$%CP! zGbmrUrVHcyv^k4Sl=`{z#I6jb?UXoe38}?>4k=`j2imp~QQeJ}h8sS(aM#8FcfZ_c zf~Y^}4~|6MTYH0Ox}7`vfP)@oQRaejnnqixIN+_6JO@oC)-P0Hha-IUBa~jK8v*lh_{)m;PtN;XK1)KNMyZ?;#Wj5R5jG{>0StE z!ffGx_fnJ}5Uq2oawA#1bEKPJJXXF-zd-SG-4X%U?}`O@yG0VD;fEtk2g1kJoVu7n zxvtT%{x0@{{NvKN%a%;Fl>R}Nge$8ZgtqPU>ZN7k!XIz9u8=5NE;YG9T-~h>yWsPE z*cZm6b9Oa;bt%fy1_|uT3S1dZwf2_)EVAWl$`W-O-+NpoBW!8hr)u4;oR?k?GWtAd zzOa3b=I(n?QPj>T%%&u=ySz;1|9(yPWjslr;3TDlrh}NL<^lK{?QP?O< zM-g0i6uP}92!#>LpQ~Pgd!%e?a~`3&QawQ3vT%*yUw0gX&$nUMCh1!u0Gszjn8!W7 z`X;{5qT@>c;xo1FN4D+WHxkeFFG7=8+;XWKmdrEQ!ikXEiV;%ZsusUzSKCBKq$(Z7O&h)EXx2dF>p1*n<{*Ql#qa&XvknOdRGu@2mk^?gkQ?76jhoPES@=&xC)|E@9=CzB#M8AjxL!~pU-uuX*E_?|I6S$XLLK5kd5L&eVI!l z!ZPx^mh^tVU)o>PcXB}S9mLW#>Cg*0=iNW9j86oP;*douJg1GGAtVM&4^CjAbwch1 z6{%__dDMIcBfkLb7MWIBU5XTPc~$v=L35O6O-n}g9_M;(=gn(=w8DFd;(IZy-H8y0 zTH9GYxVXL^!ulEni2bi)R`0+06kQ&KU%fXyj zuYQu6M!6UJ5v@^$SzgKY!eN!~yu;U|IF0GFH$aia7gu5KN=kfav&X^PGjTa$*M(C$B|3j{=UbMl9+xO1q5ONkE*wQ)<9Lz)Yw>( zU3Ht()rqk8ewy}P`)PFwGHd5d1`+kY`K*9ke35D(Ufug*CvW@igQX;R%&-*GxS`xh zd4VenE-UDUrUNwy`P|KX0f>kgFZly|o$-Zy8m-U;uSCa2M-xBZF9X|I{IB{D{Oc(b z1l3$7v$^I5y1cGtO(RGSc8eq|f}K*})HaW{OO=i%On$`Hph{10^`^utjm_NKBpGdD zWxb}3(LRqg?M(7)GG!R~l+Vx4AB{fFN|P;sCvDGnhGI?)^*v7JWdR%<`w=2wi0b?41Xjw@mpd!19z=Zc^r9H!=&52OfS10^ZEBztP7aEy}fUW z$lgb3vp8*&cLJ_L$&MoVOnRXRg#B7~cpO%#{jpy{{ugbBU%w! zp?W~}sp@Lz37eW8d?!RAvkgM0oHjG$x{WqT&i-SUtO6cqbhNoaQOM*!E=jZ=84hx@;f#UyA+z>*K&VNL%+u~@*;PIq2d-J3~O4v*Z6KLG-eQRaA z*8H1vuB~W%4yRb;H!`09u)=*7OQx@u`=L0n77wpLgFx z04_gL38YAUcebK_zjaNueYKxq9B>#=(`GsVFXV2zKc2Q-!O1`QIxu&3e00IT8_Pk+ z%xX3mRTak`k|Ba=eSOBN7BgG6qnLCOMxkpcnSGBrM)uW6icyxaATim7GkER}l5|Va`0tu3L+JDynR3dnB=s+L zNpZ^k^t3S=lj3jiH_G_DSK(+Qp~ZOAmLO%3cMaa?w%&oXo_~`b+#lxbMFfvVOn2Gy z(XFKD9SKmzb>42>jZg8uJs3--md7NmGT4kdLLCFvx8S(7xBVl&=auPzQfnxePeM;y zq5j zJz9Uf$NfM4zVH8sC@I&^-#?RG% z(AloS+5LCpcux4~-`ZiQYss!@3wfwGCNdPViv+>@$7cyb51D}&+NX=Z_k$5gXT*PY zcwSadrJY3~3KBNB9ZvZKEf1iJRDGvP9+|`SLJ~CY6D7f49wq3f9b+WFDC%~_%wr%M zSvBD{xM;Rle615NxhM$y+eVr>>^mNxv6K+_whIqlT}Tw6=bJ?{_dt-HrdH3bo{ zpfp+|(hcDQQ{Zj8$N33$vgfKTXlNOMveNS)%i6Jo$ddi%^-_%6ey-~{J!v{7Y3Zxa zpMckM(v3u1^}v&W`660X7}bknTtQ3oBjbCeV#*^!f7uu zS;20GcDTVjvlrxBgDF#tJR~{~P)Y0IJlf7qVMWl=^4&Z?SWmrQjzOp*!YleWpMZE? zMvUmAJKnW|BzXu{C4_{@1nH80FvDJ)bHi_%0#F1$Wf%P&!ZT+2w~9&W`FmgEv+7IX zecz|6d_kkWDRE;18}G$3kuRj5?|nd!p~!%ifhDY&e|YZNz&KlelUw2TW7qv(b4&VK z_02RKp!;<}*WlwnwlCQ)Qp)Fq_UP_?{5Ooed3o*pr|e3h1z5`MoO5g?uJ9W|Aw_g8 zUwFgv_}weGs}BnTjo4P7i0z#_>sYR6Tzn*WiBt+_5l&)&!@H34mXDDOhBhaWps!ao>HzD}R{~FkXH4CT(VO48|DnnKAb)(K z-|Zr)@7XU(Oyf`UGt~}H5_jPi;hN@$S2ti*u*k==vU`9+-u~vt-xia0W`i|u?57Y4 z(*Ftk2Lt#b&CLv!&5MDfKEIwg=9puI&cOGj#0N~<_2hQGA&l!SZXhL+hiSgh5jj$E zl>XPh{?*`#^5L@TE2p7T<-@$mrjxaGvhsFiy40O=%cq!{w!rSnv50XBxqF)yW9AhO zJn5f(zu%JMYxZA-M`y=6P)A{o%p8SpxZ#Gd$a>R> z%4z6S`FaIy1DJ}fw;^hmN2j5NTtKH((U|Wk`E^JQ)_R$p%?L?{-SSb&-&3ZfKtvo_ zU>CIjmr0FsO4`GG4~efmGP{{g9j+lcWyJ`Ywq-g=q7YdivOtO!_(o2dVp$P+WP!*6 zNmzhRnfjVC3BeIbWP!*6jkiGLl#RDt#2Hy&hgcwT${k|XNN8k%##<1G+5W#erZaYh!{Ar^?7a)+2T5*k^c@fL`jvhlWyI3o+}5DP?3 zxkJnv35_h!cnd^M*?8MUoRI}~hy^02+#zO-ghm!~ zlP*!7I+XA&llqPsXW5*+Y}me zQvJ6{{~f7I%1-$h&Xehf!=4%n#FH*jz;S_k=vD9Dy`@{XZo*?ScxEXNk=orts;53A zW1qY4zFSWO#L<{S8}k?uI_9@2@TB@wUmx*p(tk(mlG1saUS6KZ>-@}24{qn-I6VJi zo^VG~-?^MP;7ZRs#i?w5xjavG!GZ<;8LH^ry~{4U%){wzdj2PloAha&%w*1DZAcCd z*Ya>smzIH3^z=;DWX@v!$3Onzp%d|N61j&{&3(P`-n>#tXOp0mqycyYM2hckfmOjnjiI-F?l z;UF;&C*G+(JhzwSh3mq6efpvU)-!vlC(dM2zWV5#{<~8QXK%#0ueOUARa3Lo$*(*p zk?@8BkKcy_>eSWI;Sge(K7G3I=zfMor;R)MWaC6~czC3J;(^eOFkQUc^ zJi&c?om7s)qh;pInL5+qA!q2=TycJ!=#=&Nlj;-E`GR({M5E`6iB2j_1b24j5s>wr z5y}I2iDN*|sB2C(B2H`3GduQ_;zV+IwJxPXz)hSWco-#uLe_ z4<0^EJdwPeacX%Y`?@;ph?C0Ku3f8}O5ww@SzfZItS3w7>aeTFSQ0jE;9<+$+~JAl zyqOF!sDpBvlx*OL z5S>~+K!y(=9%C||ygp{k7=0}Q-^s%7KsnXs>maxs*q$eqa|e~P9=_d+`vg1$I~*E1 zWu4PucFsIBx*@u-yxl3SyI;xfaJik;a}(^o67Fac$wWi(Fe>T}A9wY*D;eGa#0co? z6n-03ygW2ImBY6~aTkzsaHEws{!LEta<0DmY7egh&^Jcmy_NbVEXwDbs_-Hnk2|+N z{pn9*-h{*)8XCmd*vN{H@PI+)@*Yt9nQrYmgsN|g&Dw~lfv7c8j=;^ zA`9$p7D#!cXC^#38Uc5=W)ju6DJ_ul^tCCKi^_^Du)A5HQPbDm%}7ywBMUUO1yWv9 zHnoCLd65NnHw&m!dXo6*nBC1FQGFu|>?{j7KcrKh8u{eTx(!jekp)5)Fk|DX+~}cW z*7EhSY5ES?5K)wjED%|sNi3kFq;bj&IwX@P@zV{TO`=6qNMwP?0&0PfL!JbHKGEY$ zb0QLBH4}}R&L&YDSzw1*AmofJgAVy36P&)fz%(x+pL4({jw}#aV24`ZR7mGw$Qi3n aVE-SNg{DZleo(pq000013 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 WI|5mN4h=cnTTzzRkgJoi4EsN*KC6NN diff --git a/Doc/img/nd_img_MakeApiKey.png b/Doc/img/nd_img_MakeApiKey.png index 5e6ad782d1bf537d2fe7685a1c701cd92b2cb0ac..1f1526a5271dc9ce7cca4bcf5807c1771e1af0a0 100644 GIT binary patch delta 8976 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 z zMd^=t``@R1Us0vgVpQY07*)G0MislpD5J5-Q3sv*KE5<%#7v1tyjeVvtV7jl6!oRr zykp5fx-4%@!brzKN7phPeBeIhDe0i3dnuc@Ul1nZrj9o0fF0Y-i{=jy5 zlnyQr@MMgaYNbdBs_$bP>2x}YhEQkONWq%!9bVbpO*3g)($Z3B{pCfliGa-o?0RDR zJxY-Wel8D`D)3;;)TAXem6rTmcKsrHd-v`w8w&WQ1U7hzO4tVfsR`fLjDOO>>46fj z@eZ_`@cGSwdf_hCn)u>1KFcdEVOJGjttxH8M=1C_GD-)h2THZZJ2+hxzG`g2w{6>2 z{jWq;bKl##ES!j)PL>`DdP_zf|1xt=O zY_1^q^03XKKQahTlp+sA9w=K6xF6T#uUsSO5QBZ>mo}rJuWUUXX^T8yJ>UghA128! zOsjKxbHRMUG8+BVCs7`G;3s*&3pnUO(8+&RW2&hMWgK9>sKh9bJR}f#;3s>aA8Wv% drvE}m{}02usreWUNRt2n002ovPDHLkV1l%BmXrVh diff --git a/Doc/img/nd_img_MakeAuthParams.png b/Doc/img/nd_img_MakeAuthParams.png index 20cec3b9e773ca1cad5c7077e00c7865c1d0d779..5487d46da3ade19ac6e8904a1022637c0001755a 100644 GIT binary patch literal 14558 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 HlhFSGnLglx delta 14420 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 diff --git a/Doc/img/nd_img_QueryUserInstallations.png b/Doc/img/nd_img_QueryUserInstallations.png index 5e64b74a18b7f7c09e7927e9af5126379d901983..aa05f6d1ca33724331167c34b258bd814f5eb3b3 100644 GIT binary patch delta 18400 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 U|20EQ(45cggZ+!_c=^_U0Ir;sp#T5? diff --git a/README.adoc b/README.adoc index a9fed87e..c38a6660 100644 --- a/README.adoc +++ b/README.adoc @@ -7,7 +7,7 @@ image:https://img.shields.io/badge/license-MIT-brightgreen.svg[alt="License", li image:https://img.shields.io/discord/389039439487434752.svg?label=Discord&logo=discord&color=7289DA&labelColor=2C2F33[alt="Discord", link="https://discord.mod.io"] image:https://img.shields.io/badge/Unreal-4.25%2B-dea309[alt="Unreal", link="https://www.unrealengine.com"] -Welcome to the mod.io UE4 plugin public repository. It allows game developers to host and automatically install user-created mods in their games. It provides a C++ and Blueprint interface around the mod.io SDK, which connects to the https://docs.mod.io[mod.io REST API]. We have a https://test.mod.io[test environment] available, and developers can create a game profile there to evaluate the plugin with. +Welcome to the mod.io UE4 plugin public repository. It allows game developers to host and automatically install user-created mods in their games which use UE 4.25 or newer. It provides a C++ and Blueprint interface around the mod.io SDK, which connects to the https://docs.mod.io[mod.io REST API]. We have a https://test.mod.io[test environment] available, and developers can create a game profile there to evaluate the plugin with. ++++ @@ -56,7 +56,7 @@ The settings have the following parameters: [.stretch,stripes=odd,frame=none, cols="25%,~"] |=== |[.paramname]#Game Id#|Your mod.io-provided Game Id for the target environment (Live, or Test) -|[.paramname]#API Key#|Your mod.io-provided Game Id for the target environment (Live, or Test) +|[.paramname]#API Key#|Your mod.io-provided API key for the target environment (Live, or Test) |[.paramname]#Environment#|Are you targeting the production/live environment or the private/test environment? |[.paramname]#Log Level#|The default logging level to use. Messages with a lower log level will be silently discarded. |[.paramname]#Portal#|The default portal to use. This usually corresponds to the store your game will be being distributed through. diff --git a/Source/Modio/Classes/Types/ModioAuthenticationParams.h b/Source/Modio/Classes/Types/ModioAuthenticationParams.h deleted file mode 100644 index a5b571a7..00000000 --- a/Source/Modio/Classes/Types/ModioAuthenticationParams.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "ModioSDK.h" - -#include "Internal/ModioPrivateDefines.h" -#include "Containers/UnrealString.h" -#include "Misc/Optional.h" - -#include "ModioAuthenticationParams.generated.h" - -/** @brief Simple struct to encapsulate data passed to external authentication systems */ -UENUM(BlueprintType) -enum class EModioAuthenticationProvider : uint8 -{ - XboxLive, - Steam, - GoG, - Itch, - Switch, - Discord -}; - -/** @brief Simple struct to encapsulate data passed to external authentication systems */ -USTRUCT(BlueprintType) -struct FModioAuthenticationParams -{ - GENERATED_BODY(); - - operator Modio::AuthenticationParams() const; - UPROPERTY(BlueprintReadWrite, EditInstanceOnly) - FString AuthToken; - UPROPERTY(BlueprintReadWrite, EditInstanceOnly) - FString UserEmail; - UPROPERTY(BlueprintReadWrite, EditInstanceOnly) - bool bUserHasAcceptedTerms = false; -}; - -#pragma region ToModio implementation -MODIO_BEGIN_CONVERT_SWITCHES -FORCEINLINE Modio::AuthenticationProvider ToModio(EModioAuthenticationProvider Provider) -{ - switch (Provider) - { - case EModioAuthenticationProvider::XboxLive: - return Modio::AuthenticationProvider::XboxLive; - case EModioAuthenticationProvider::Steam: - return Modio::AuthenticationProvider::Steam; - case EModioAuthenticationProvider::GoG: - return Modio::AuthenticationProvider::GoG; - case EModioAuthenticationProvider::Itch: - return Modio::AuthenticationProvider::Itch; - case EModioAuthenticationProvider::Switch: - return Modio::AuthenticationProvider::Switch; - case EModioAuthenticationProvider::Discord: - return Modio::AuthenticationProvider::Discord; - } - - return Modio::AuthenticationProvider::Steam; -} -MODIO_END_CONVERT_SWITCHES -#pragma endregion diff --git a/Source/Modio/Classes/Types/ModioCommonTypes.h b/Source/Modio/Classes/Types/ModioCommonTypes.h deleted file mode 100644 index aecab3cd..00000000 --- a/Source/Modio/Classes/Types/ModioCommonTypes.h +++ /dev/null @@ -1,605 +0,0 @@ -#pragma once - -#include "Misc/Crc.h" -#include "Internal/ModioPrivateDefines.h" -#include "ModioSDK.h" -#include "Types/ModioAuthenticationParams.h" - -// clang-format off -#include "ModioCommonTypes.generated.h" -// clang-format on - -/** @brief Enum representing what environment your game is deployed in */ -UENUM(BlueprintType) -enum class EModioEnvironment : uint8 -{ - // Test/Private environment - Test, - // Live/Public environment - Live -}; - -/** @brief Enum representing the store or service your game is being distributed through */ -UENUM(BlueprintType) -enum class EModioPortal : uint8 -{ - None, - Apple, - EpicGamesStore, - GOG, - Google, - Itchio, - Nintendo, - PSN, - Steam, - XboxLive -}; - -/** @brief Enum representing mod logo sizes */ -UENUM(BlueprintType) -enum class EModioLogoSize : uint8 -{ - // Original Size - Original, - // 320x180px - Thumb320, - // 640x360px - Thumb640, - // 1280x720px - Thumb1280 -}; - -/** @brief Enum representing avatar image sizes */ -UENUM(BlueprintType) -enum class EModioAvatarSize : uint8 -{ - // Original Size - Original, - // 50x50px Thumbnail - Thumb50, - // 100x100px Thumbnail - Thumb100 -}; - -/** */ -UENUM(BlueprintType) -enum class EModioGallerySize : uint8 -{ - // Original Size - Original, - // 320x180px Thumbnail - Thumb320 -}; - -/** @brief Degree of severity for the log output */ -UENUM() -enum class EModioLogLevel : uint8 -{ - // Detailed low-level debugging output. Not intended for general use - Trace = 0, - // Informational output containing status messages - Info = 1, - // Warnings about incorrect plugin usage, timeouts - Warning = 2, - // Only errors - Error = 3 -}; - -/** @brief Enum representing the languages mod.io support responses in */ -UENUM(BlueprintType) -enum class EModioLanguage : uint8 -{ - English, - Bulgarian, - French, - German, - Italian, - Polish, - Portuguese, - Hungarian, - Japanese, - Korean, - Russian, - Spanish, - Thai, - ChineseSimplified, - ChineseTraditional -}; - -/** @brief Strong type for Mod IDs */ -USTRUCT(BlueprintType) -struct MODIO_API FModioModID -{ - GENERATED_BODY() - - FModioModID(); - constexpr explicit FModioModID(Modio::ModID InModId) : ModID(InModId) {} - - FORCEINLINE friend uint32 GetTypeHash(FModioModID ModioModId) - { - return FCrc::MemCrc32(&ModioModId.ModID, sizeof(Modio::ModID)); - } - - FORCEINLINE friend bool operator==(FModioModID A, FModioModID B) - { - return A.ModID == B.ModID; - } - - FORCEINLINE friend bool operator!=(FModioModID A, FModioModID B) - { - return A.ModID != B.ModID; - } - - FORCEINLINE friend bool operator<(FModioModID A, FModioModID B) - { - return A.ModID < B.ModID; - } - - FORCEINLINE friend bool operator>(FModioModID A, FModioModID B) - { - return A.ModID > B.ModID; - } - - /** Implicitly convert it to the underlying type */ - constexpr FORCEINLINE operator Modio::ModID() const - { - return ModID; - } - - FORCEINLINE FString ToString() const - { - if (ModID < 0) - { - return TEXT("InvalidModID"); - } - return FString::Printf(TEXT("%lld"), *ModID); - } - -private: - Modio::ModID ModID; -}; - -template<> -struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 -{ - enum - { - WithIdenticalViaEquality = true - }; -}; - -/** @brief Strong type for Game IDs */ -USTRUCT(BlueprintType, meta = (HasNativeMake = "Modio.ModioCommonTypesLibrary.MakeGameId")) -struct MODIO_API FModioGameID -{ - GENERATED_BODY() - - FModioGameID(); - constexpr explicit FModioGameID(Modio::GameID InGameId) : GameID(InGameId) {} - constexpr explicit FModioGameID(int64 InGameId) : GameID(Modio::GameID(InGameId)) {} - - FORCEINLINE friend uint32 GetTypeHash(FModioGameID ModioGameId) - { - return FCrc::MemCrc32(&ModioGameId.GameID, sizeof(Modio::GameID)); - } - - FORCEINLINE friend bool operator==(FModioGameID A, FModioGameID B) - { - return A.GameID == B.GameID; - } - - /** Implicitly convert it to the underlying type */ - constexpr FORCEINLINE operator Modio::GameID() const - { - return GameID; - } - - FORCEINLINE FString ToString() const - { - if (GameID < 0) - { - return TEXT("InvalidGameID"); - } - return FString::Printf(TEXT("%lld"), *GameID); - } - - static FORCEINLINE FModioGameID InvalidGameID() - { - return FModioGameID(Modio::GameID::InvalidGameID()); - } - -private: - Modio::GameID GameID; -}; - -template<> -struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 -{ - enum - { - WithIdenticalViaEquality = true - }; -}; - -/** @brief Strong type for File Metadata IDs */ -USTRUCT(BlueprintType) -struct MODIO_API FModioFileMetadataID -{ - GENERATED_BODY() - - FModioFileMetadataID(); - constexpr explicit FModioFileMetadataID(Modio::FileMetadataID InFileMetadataId) : FileMetadataID(InFileMetadataId) {} - - FORCEINLINE friend uint32 GetTypeHash(FModioFileMetadataID FileMetadataID) - { - return FCrc::MemCrc32(&FileMetadataID.FileMetadataID, sizeof(Modio::FileMetadataID)); - } - - FORCEINLINE friend bool operator==(FModioFileMetadataID A, FModioFileMetadataID B) - { - return A.FileMetadataID == B.FileMetadataID; - } - - /** Implicitly convert it to the underlying type */ - constexpr FORCEINLINE operator Modio::FileMetadataID() const - { - return FileMetadataID; - } - - FORCEINLINE FString ToString() const - { - if (FileMetadataID < 0) - { - return TEXT("InvalidFileMetadataID"); - } - return FString::Printf(TEXT("%lld"), *FileMetadataID); - } - -private: - Modio::FileMetadataID FileMetadataID; -}; - -template<> -struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 -{ - enum - { - WithIdenticalViaEquality = true - }; -}; - -/** @brief Strong type for User IDs */ -USTRUCT(BlueprintType) -struct MODIO_API FModioUserID -{ - GENERATED_BODY() - - FModioUserID(); - constexpr explicit FModioUserID(Modio::UserID InUserID) : UserID(InUserID) {} - constexpr explicit FModioUserID(int64 InUserID) : UserID(Modio::UserID(InUserID)) {} - - FORCEINLINE friend uint32 GetTypeHash(FModioUserID UserID) - { - return FCrc::MemCrc32(&UserID.UserID, sizeof(Modio::UserID)); - } - - FORCEINLINE friend bool operator==(FModioUserID A, FModioUserID B) - { - return A.UserID == B.UserID; - } - - /** Implicitly convert it to the underlying type */ - constexpr FORCEINLINE operator Modio::UserID() const - { - return UserID; - } - - FORCEINLINE FString ToString() const - { - if (UserID < 0) - { - return TEXT("InvalidUserID"); - } - return FString::Printf(TEXT("%lld"), *UserID); - } - -private: - Modio::UserID UserID; -}; - -template<> -struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 -{ - enum - { - WithIdenticalViaEquality = true - }; -}; - -/** @brief Strong type for Api Keys */ -USTRUCT(BlueprintType, meta = (HasNativeMake = "Modio.ModioCommonTypesLibrary.MakeApiKey")) -struct MODIO_API FModioApiKey -{ - GENERATED_BODY() - - FModioApiKey() = default; - explicit FModioApiKey(const FString& InApiKey); - explicit FModioApiKey(const Modio::ApiKey& InApiKey); - - /** Implicitly convert it to the underlying type */ - FORCEINLINE operator Modio::ApiKey() const - { - return Modio::ApiKey(TCHAR_TO_UTF8(*ToString())); - } - - FORCEINLINE const FString& ToString() const - { - // Put in the function instead of default constructor to avoid having to allocate memory for - // each empty instance - if (ApiKey.Len() == 0) - { - static FString Invalid(TEXT("InvalidApiKey")); - return Invalid; - } - return ApiKey; - } - - static FModioApiKey InvalidAPIKey() - { - return FModioApiKey(Modio::ApiKey::InvalidAPIKey()); - } - -private: - FString ApiKey; -}; - -/** @brief Strong type for email address */ -USTRUCT(BlueprintType) -struct MODIO_API FModioEmailAddress -{ - GENERATED_BODY() - - FModioEmailAddress() = default; - FModioEmailAddress(const FString& InEmailAddress); - - /** Implicitly convert it to the underlying type */ - FORCEINLINE operator Modio::EmailAddress() const - { - return Modio::EmailAddress(TCHAR_TO_UTF8(*ToString())); - } - - FORCEINLINE const FString& ToString() const - { - // Put in the function instead of default constructor to avoid having to allocate memory for - // each empty instance - if (EmailAddress.Len() == 0) - { - static FString Invalid(TEXT("InvalidEmailAddress")); - return Invalid; - } - return EmailAddress; - } - -private: - FString EmailAddress; -}; - -/** @brief Strong type for email auth code */ -USTRUCT(BlueprintType) -struct MODIO_API FModioEmailAuthCode -{ - GENERATED_BODY() - - FModioEmailAuthCode() = default; - FModioEmailAuthCode(const FString& InEmailAuthCode); - - /** Implicitly convert it to the underlying type */ - FORCEINLINE operator Modio::EmailAuthCode() const - { - return Modio::EmailAuthCode(TCHAR_TO_UTF8(*ToString())); - } - - FORCEINLINE const FString& ToString() const - { - // Put in the function instead of default constructor to avoid having to allocate memory for - // each empty instance - if (EmailAuthCode.Len() == 0) - { - static FString Invalid(TEXT("InvalidEmailAuthCode")); - return Invalid; - } - return EmailAuthCode; - } - -private: - FString EmailAuthCode; -}; - -FORCEINLINE FModioModID ToUnreal(Modio::ModID Value); -FORCEINLINE FModioFileMetadataID ToUnreal(Modio::FileMetadataID Value); - -FORCEINLINE Modio::LogLevel ToModio(EModioLogLevel UnrealLogLevel); -FORCEINLINE Modio::AvatarSize ToModio(EModioAvatarSize AvatarSize); -FORCEINLINE Modio::GallerySize ToModio(EModioGallerySize GallerySize); -FORCEINLINE Modio::LogoSize ToModio(EModioLogoSize LogoSize); -FORCEINLINE Modio::Environment ToModio(EModioEnvironment Environment); -FORCEINLINE Modio::Portal ToModio(EModioPortal Portal); - - -#pragma region ToModio implementation - -MODIO_BEGIN_CONVERT_SWITCHES - -Modio::LogLevel ToModio(EModioLogLevel UnrealLogLevel) -{ - switch (UnrealLogLevel) - { - case EModioLogLevel::Error: - return Modio::LogLevel::Error; - case EModioLogLevel::Info: - return Modio::LogLevel::Info; - case EModioLogLevel::Trace: - return Modio::LogLevel::Trace; - case EModioLogLevel::Warning: - return Modio::LogLevel::Warning; - } - - checkf(false, TEXT("Missed a case in ToModio(EModioLogLevel UnrealLogLevel)")); - return Modio::LogLevel::Info; -} - -Modio::AvatarSize ToModio(EModioAvatarSize AvatarSize) -{ - switch (AvatarSize) - { - case EModioAvatarSize::Original: - return Modio::AvatarSize::Original; - case EModioAvatarSize::Thumb50: - return Modio::AvatarSize::Thumb50; - case EModioAvatarSize::Thumb100: - return Modio::AvatarSize::Thumb100; - } - - checkf(false, TEXT("Missed a case in ToModio(EModioAvatarSize AvatarSize)")); - return Modio::AvatarSize::Thumb50; -} - -Modio::GallerySize ToModio(EModioGallerySize GallerySize) -{ - switch (GallerySize) - { - case EModioGallerySize::Original: - return Modio::GallerySize::Original; - case EModioGallerySize::Thumb320: - return Modio::GallerySize::Thumb320; - } - - checkf(false, TEXT("Missed a case in ToModio(EModioGallerySize GallerySize)")); - return Modio::GallerySize::Thumb320; -} - -Modio::LogoSize ToModio(EModioLogoSize LogoSize) -{ - switch (LogoSize) - { - case EModioLogoSize::Original: - return Modio::LogoSize::Original; - case EModioLogoSize::Thumb320: - return Modio::LogoSize::Thumb320; - case EModioLogoSize::Thumb640: - return Modio::LogoSize::Thumb640; - case EModioLogoSize::Thumb1280: - return Modio::LogoSize::Thumb1280; - } - - checkf(false, TEXT("Missed a case in ToModio(EModioLogoSize LogoSize)")); - return Modio::LogoSize::Thumb320; -} - -Modio::Environment ToModio(EModioEnvironment Environment) -{ - switch (Environment) - { - case EModioEnvironment::Test: - return Modio::Environment::Test; - case EModioEnvironment::Live: - return Modio::Environment::Live; - } - - checkf(false, TEXT("Missed a case in ToModio(EModioEnvironment Environment)")); - return Modio::Environment::Test; -} - -Modio::Portal ToModio(EModioPortal Portal) { - switch (Portal) - { - case EModioPortal::None: - return Modio::Portal::None; - break; - case EModioPortal::Apple: - return Modio::Portal::Apple; - break; - case EModioPortal::EpicGamesStore: - return Modio::Portal::EpicGamesStore; - break; - case EModioPortal::GOG: - return Modio::Portal::GOG; - break; - case EModioPortal::Google: - return Modio::Portal::Google; - break; - case EModioPortal::Itchio: - return Modio::Portal::Itchio; - break; - case EModioPortal::Nintendo: - return Modio::Portal::Nintendo; - break; - case EModioPortal::PSN: - return Modio::Portal::PSN; - break; - case EModioPortal::Steam: - return Modio::Portal::Steam; - break; - case EModioPortal::XboxLive: - return Modio::Portal::XboxLive; - break; - } - checkf(false, TEXT("Missed a case in ToModio(EModioPortal)")); - return Modio::Portal::None; -} - - -FORCEINLINE Modio::Language ToModio(EModioLanguage Language) -{ - switch (Language) - { - case EModioLanguage::English: - return Modio::Language::English; - case EModioLanguage::Bulgarian: - return Modio::Language::Bulgarian; - case EModioLanguage::French: - return Modio::Language::French; - case EModioLanguage::German: - return Modio::Language::German; - case EModioLanguage::Italian: - return Modio::Language::Italian; - case EModioLanguage::Polish: - return Modio::Language::Polish; - case EModioLanguage::Portuguese: - return Modio::Language::Portuguese; - case EModioLanguage::Hungarian: - return Modio::Language::Hungarian; - case EModioLanguage::Japanese: - return Modio::Language::Japanese; - case EModioLanguage::Korean: - return Modio::Language::Korean; - case EModioLanguage::Russian: - return Modio::Language::Russian; - case EModioLanguage::Spanish: - return Modio::Language::Spanish; - case EModioLanguage::Thai: - return Modio::Language::Thai; - case EModioLanguage::ChineseSimplified: - return Modio::Language::ChineseSimplified; - case EModioLanguage::ChineseTraditional: - return Modio::Language::ChineseTraditional; - } - - checkf(false, TEXT("Missed a case in ToModio(EModioLanguage Language)")); - return Modio::Language::English; -} - - -MODIO_END_CONVERT_SWITCHES - -FModioModID ToUnreal(Modio::ModID Value) -{ - return FModioModID(Value); -} - -FModioFileMetadataID ToUnreal(Modio::FileMetadataID Value) -{ - return FModioFileMetadataID(Value); -} - -#pragma endregion diff --git a/Source/Modio/Classes/Types/ModioErrorCode.h b/Source/Modio/Classes/Types/ModioErrorCode.h deleted file mode 100644 index 0106bc5f..00000000 --- a/Source/Modio/Classes/Types/ModioErrorCode.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "ModioSDK.h" - -// clang-format off -#include "ModioErrorCode.generated.h" -// clang-format on - -/** @bried wrapper around the Modio::ErrorCode. This is a wrapper around the std::error_code */ -USTRUCT(BlueprintType) -struct MODIO_API FModioErrorCode -{ - GENERATED_BODY() - - // This is to allow delegates to pass FModioErrorCode code, but I would have preferred it to be deleted - FModioErrorCode() = default; - FModioErrorCode(Modio::ErrorCode ec); - - /** return true if this error code is a error */ - FORCEINLINE operator bool() const - { - return Error.value() != 0; - } - - /** Get the error code */ - FORCEINLINE int GetValue() const - { - return Error.value(); - } - FORCEINLINE Modio::ErrorCode GetRawErrorCode() const - { - return Error; - } - - /** Get a human readable message from the error code */ - FString GetMessage() const; - -private: - Modio::ErrorCode Error; -}; - -#pragma region ToUnreal implementation -FORCEINLINE FModioErrorCode ToUnreal(Modio::ErrorCode ec) -{ - return FModioErrorCode(ec); -} -#pragma endregion diff --git a/Source/Modio/Classes/Types/ModioFilterParams.h b/Source/Modio/Classes/Types/ModioFilterParams.h deleted file mode 100644 index 36567883..00000000 --- a/Source/Modio/Classes/Types/ModioFilterParams.h +++ /dev/null @@ -1,260 +0,0 @@ -#pragma once - -#include "Internal/ModioConvert.h" -#include "Internal/ModioPrivateDefines.h" - -#include "ModioSDK.h" - -#include "Types/ModioCommonTypes.h" - -// clang-format off -#include "ModioFilterParams.generated.h" -// clang-format on - -/// @brief Enum indicating which field should be used to sort the results -UENUM(BlueprintType) -enum class EModioSortFieldType : uint8 -{ - ID, /** use mod ID (default) */ - DownloadsToday, /** use number of downloads in last 24 (exposed in REST API as 'popular' */ - SubscriberCount, /** use number of subscribers */ - Rating, /** use mod rating */ - DateMarkedLive, /** use date mod was marked live */ - DateUpdated /** use date mod was last updated */ -}; - -/// @brief Enum indicating which direction sorting should be applied -UENUM(BlueprintType) -enum class EModioSortDirection : uint8 -{ - Ascending, /** (default) */ - Descending -}; - -FORCEINLINE Modio::FilterParams::SortFieldType ToModio(EModioSortFieldType Field); -FORCEINLINE Modio::FilterParams::SortDirection ToModio(EModioSortDirection Direction); - -/** @brief Class storing a set of filter parameters for use in xref:ListAllModsAsync[] */ -USTRUCT(BlueprintType) -struct MODIO_API FModioFilterParams -{ - GENERATED_BODY() - - /** Convert to the underlying type for the modio functions */ - FORCEINLINE const Modio::FilterParams& operator*() const - { - return FilterParams; - } - - /** - * @brief Indicates the filter should only include the specified mods - * @param IDs the set of mods to match - * @return *this - */ - FModioFilterParams& MatchingIDs(const TArray& IDs) - { - std::vector Out; - for (FModioModID ID : IDs) - { - Out.push_back(ID); - } - - FilterParams.MatchingIDs(Out); - return *this; - } - - /** - * @brief Indicates the filter should exclude the specified mods. - * @param IDs the set of mods to exclude - * @return *this - */ - FModioFilterParams& ExcludingIDs(const TArray& IDs) - { - std::vector Out; - for (FModioModID ID : IDs) - { - Out.push_back(ID); - } - - FilterParams.ExcludingIDs(Out); - return *this; - } - - /** - * @brief Indicates results should be sorted using the specified field and direction - * @param ByField Field to sort with - * @param ByDirection Direction to sort - * @return *this - **/ - FORCEINLINE FModioFilterParams& SortBy(EModioSortFieldType ByField, EModioSortDirection ByDirection) - { - FilterParams.SortBy(ToModio(ByField), ToModio(ByDirection)); - return *this; - } - - /** - * @brief Only include mods where the name contains the provided string - * @param SearchString Search string - * @return *this - **/ - FORCEINLINE FModioFilterParams& NameContains(const FString& SearchString) - { - FilterParams.NameContains(ToSTD(SearchString)); - return *this; - } - - /** - * @brief Only include mods where the name contains at least one of the provided strings (string1 OR string2 OR - *stringN...) - * @tparam ...Args std::string - * @param SearchString First search string - * @param ...args Additional search strings - * @return *this - **/ - FORCEINLINE FModioFilterParams& NameContains(const TArray& SearchString) - { - FilterParams.NameContains(ToSTD(SearchString)); - return *this; - } - - /** - * @brief Only include mods that were marked live (i.e released) after the specified date - * @param LiveAfter Minimum date - * @return *this - **/ - FORCEINLINE FModioFilterParams& MarkedLiveAfter(FDateTime LiveAfter) - { - FilterParams.MarkedLiveAfter(ToSTD(LiveAfter)); - return *this; - } - - /** - * @brief Only include mods that were marked live (i.e released) before the specified date - * @param LiveBefore Maximum date - * @return *this - **/ - FORCEINLINE FModioFilterParams& MarkedLiveBefore(FDateTime LiveBefore) - { - FilterParams.MarkedLiveBefore(ToSTD(LiveBefore)); - return *this; - } - - /** - * @brief Only include mods that have the specified tag - * @param Tag Tag to include - * @return *this - **/ - FORCEINLINE FModioFilterParams& WithTags(const FString& Tag) - { - FilterParams.WithTags(ToSTD(Tag)); - return *this; - } - - /** - * @brief Only include mods that have all the specified tags (tag1 AND tag2 AND tagN...) - * @param NewTags The set of tags to filter on - * @return *this - **/ - FORCEINLINE FModioFilterParams& WithTags(const TArray& NewTags) - { - FilterParams.WithTags(ToSTD(NewTags)); - return *this; - } - - /** - * @brief Only include mods that do not have the specified tag - * @param Tag Tag to exclude - * @return *this - **/ - FORCEINLINE FModioFilterParams& WithoutTags(const FString& Tag) - { - FilterParams.WithoutTags(ToSTD(Tag)); - return *this; - } - - /** - * @brief Only include mods that do not have any of the specified tags ( NOT (tag1 OR tag2 OR tagN...)) - * @param NewTags Tags to exclude - * @return *this - **/ - FORCEINLINE FModioFilterParams& WithoutTags(const TArray& NewTags) - { - FilterParams.WithoutTags(ToSTD(NewTags)); - return *this; - } - - /** - * @brief Returns a sub-range of query results from StartIndex to StartIndex + ResultCount - * @param StartIndex Zero-based index of first result to return - * @param ResultCount Number of results to return - * @return *this - **/ - FORCEINLINE FModioFilterParams& IndexedResults(uint64 StartIndex, uint64 ResultCount) - { - FilterParams.IndexedResults(StartIndex, ResultCount); - return *this; - } - - /** - * @brief Returns a sub-range of query results based on a specified page size and index - * @param PageNumber Zero-based index of page to return - * @param PageSize Number of results in a page - * @return - **/ - FORCEINLINE FModioFilterParams& PagedResults(uint64 PageNumber, uint64 PageSize) - { - FilterParams.PagedResults(PageNumber, PageSize); - return *this; - } - - /** - * @brief Converts the filter params to a string suitable for use in the REST API. - * @note Performs a allocation to acquire the string - * @return FString containing the filter parameters - */ - FORCEINLINE FString ToString() const - { - return FString(UTF8_TO_TCHAR(FilterParams.ToString().c_str())); - } - -private: - Modio::FilterParams FilterParams; -}; - -#pragma region ToModio implementation -MODIO_BEGIN_CONVERT_SWITCHES -Modio::FilterParams::SortDirection ToModio(EModioSortDirection SortDirection) -{ - switch (SortDirection) - { - case EModioSortDirection::Ascending: - return Modio::FilterParams::SortDirection::Ascending; - case EModioSortDirection::Descending: - return Modio::FilterParams::SortDirection::Descending; - } - - return Modio::FilterParams::SortDirection::Ascending; -} - -Modio::FilterParams::SortFieldType ToModio(EModioSortFieldType Environment) -{ - switch (Environment) - { - case EModioSortFieldType::ID: - return Modio::FilterParams::SortFieldType::ID; - case EModioSortFieldType::DownloadsToday: - return Modio::FilterParams::SortFieldType::DownloadsToday; - case EModioSortFieldType::SubscriberCount: - return Modio::FilterParams::SortFieldType::SubscriberCount; - case EModioSortFieldType::Rating: - return Modio::FilterParams::SortFieldType::Rating; - case EModioSortFieldType::DateMarkedLive: - return Modio::FilterParams::SortFieldType::DateMarkedLive; - case EModioSortFieldType::DateUpdated: - return Modio::FilterParams::SortFieldType::DateUpdated; - } - - return Modio::FilterParams::SortFieldType::ID; -} -MODIO_END_CONVERT_SWITCHES -#pragma endregion \ No newline at end of file diff --git a/Source/Modio/Classes/Types/ModioImageState.h b/Source/Modio/Classes/Types/ModioImageState.h deleted file mode 100644 index 18a7d763..00000000 --- a/Source/Modio/Classes/Types/ModioImageState.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -// clang-format off -#include "ModioImageState.generated.h" -// clang-format on - -UENUM(BlueprintType) -enum class EModioImageState : uint8 -{ - OnDisc, - LoadingIntoMemory, - InMemory, - Corrupted -}; \ No newline at end of file diff --git a/Source/Modio/Classes/Types/ModioModCollectionEntry.h b/Source/Modio/Classes/Types/ModioModCollectionEntry.h deleted file mode 100644 index 45cba265..00000000 --- a/Source/Modio/Classes/Types/ModioModCollectionEntry.h +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include "ModioSDK.h" -#include "Internal/ModioPrivateDefines.h" -#include "Types/ModioCommonTypes.h" -#include "Types/ModioModInfo.h" - -// clang-format off -#include "ModioModCollectionEntry.generated.h" -// clang-format on - -/// @brief Enum representing the current state of a mod -UENUM(BlueprintType) -enum class EModioModState : uint8 -{ - InstallationPending, // dont save - Installed, - UpdatePending, // saved as installed - Downloading, // installing - dont save - Extracting, // installing- don't save - UninstallPending, // saved as installed -}; - -// @todo: This could just copy the four members that you can access -/** @brief Class representing a mod which is installed locally */ -USTRUCT(BlueprintType) -struct MODIO_API FModioModCollectionEntry -{ - GENERATED_BODY() - - FModioModCollectionEntry() = default; - FModioModCollectionEntry(Modio::ModCollectionEntry&& ModCollectionEntry); - - /** @return Modio::ModState enum representing current state of the mod */ - EModioModState GetModState() const; - - /** @return Mod ID */ - FModioModID GetID() const; - - /** @return Modio::ModInfo containing mod profile data */ - const FModioModInfo& GetModProfile() const; - - /** - * @return Path to the mod's installation folder on disk - * NOTE: If the mod is not yet installed this path may not yet exist. Check - * @doc_xref{ModCollectionEntry::GetModState} before trying to load files in this location - **/ - const FString& GetPath() const; - -private: - Modio::ModCollectionEntry ModCollectionEntry; - - /** Lazy init path, that we will initialize when we request the path */ - mutable TOptional CachedPath; - - /** Lazy init mod info, that we will initialize when we request the path */ - mutable TOptional CachedModInfo; -}; - -#pragma region ToUnreal implementation -FORCEINLINE FModioModCollectionEntry ToUnreal(const FModioModCollectionEntry& ModCollectionEntry) -{ - return FModioModCollectionEntry(ModCollectionEntry); -} - -MODIO_BEGIN_CONVERT_SWITCHES -FORCEINLINE EModioModState ToUnreal(Modio::ModState ModState) -{ - switch (ModState) - { - case Modio::ModState::InstallationPending: - return EModioModState::InstallationPending; - case Modio::ModState::Installed: - return EModioModState::Installed; - case Modio::ModState::UpdatePending: - return EModioModState::UpdatePending; - case Modio::ModState::Downloading: - return EModioModState::Downloading; - case Modio::ModState::Extracting: - return EModioModState::Extracting; - case Modio::ModState::UninstallPending: - return EModioModState::UninstallPending; - } - - checkf(false, TEXT("Missed a case in ToUnreal(Modio::ModState ModState)")); - return EModioModState::InstallationPending; -} -MODIO_END_CONVERT_SWITCHES -#pragma endregion \ No newline at end of file diff --git a/Source/Modio/Classes/Types/ModioModManagementEvent.h b/Source/Modio/Classes/Types/ModioModManagementEvent.h deleted file mode 100644 index 2f3e70ea..00000000 --- a/Source/Modio/Classes/Types/ModioModManagementEvent.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include "Internal/ModioPrivateDefines.h" -#include "Types/ModioCommonTypes.h" -#include "Types/ModioErrorCode.h" - -// clang-format off -#include "ModioModManagementEvent.generated.h" -// clang-format on - -/** @brief What type of event occurred */ -UENUM(BlueprintType) -enum class EModioModManagementEventType : uint8 -{ - Installed, /** Mod installation to local storage */ - Uninstalled, /** Mod uninstallation from local storage*/ - Updated /** Mod local installation updated to latest version*/ -}; - -/** @brief Simple struct representing the outcome of a mod management operation */ -USTRUCT(BlueprintType) -struct MODIO_API FModioModManagementEvent -{ - GENERATED_BODY() - - // This is to allow delegates to pass FModioModManagementEvent code, but I would have preferred it to be deleted - FModioModManagementEvent() = default; - FModioModManagementEvent(const Modio::ModManagementEvent& Event); - - /** @brief ID for the mod that the event occurred on */ - UPROPERTY(BlueprintReadOnly,Category="ModManagementEvent") - FModioModID ID; - - /** @brief What type of event occurred */ - UPROPERTY(BlueprintReadOnly,Category="ModManagementEvent") - EModioModManagementEventType Event; - - /** @brief Empty if operation completed successfully, truthy/contains error code if operation failed */ - UPROPERTY(BlueprintReadOnly,Category="ModManagementEvent") - FModioErrorCode Status; -}; - -#pragma region ToUnreal implementation -FORCEINLINE FModioModManagementEvent ToUnreal(const Modio::ModManagementEvent& Event) -{ - return FModioModManagementEvent(Event); -} - -MODIO_BEGIN_CONVERT_SWITCHES -FORCEINLINE EModioModManagementEventType ToUnreal(Modio::ModManagementEvent::EventType Event) -{ - switch (Event) - { - case Modio::ModManagementEvent::EventType::Installed: - return EModioModManagementEventType::Installed; - case Modio::ModManagementEvent::EventType::Uninstalled: - return EModioModManagementEventType::Uninstalled; - case Modio::ModManagementEvent::EventType::Updated: - return EModioModManagementEventType::Updated; - } - - checkf(false, TEXT("Missed a case in ToModio(EModioEnvironment Environment)")); - return EModioModManagementEventType::Installed; -} -MODIO_END_CONVERT_SWITCHES - -#pragma endregion diff --git a/Source/Modio/Classes/Types/ModioModTag.h b/Source/Modio/Classes/Types/ModioModTag.h deleted file mode 100644 index 68085c4d..00000000 --- a/Source/Modio/Classes/Types/ModioModTag.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "Containers/UnrealString.h" -#include "ModioSDK.h" - -// clang-format off -#include "ModioModTag.generated.h" -// clang-format on - -USTRUCT(BlueprintType) -struct MODIO_API FModioModTag -{ - GENERATED_BODY() - - FModioModTag() = default; - FModioModTag(const Modio::ModTag& ModTag); - - UPROPERTY(BlueprintReadOnly, Category = "ModTag") - FString Tag; -}; - -#pragma region ToUnreal implementation -FORCEINLINE FModioModTag ToUnreal(const Modio::ModTag& ModTag) -{ - return FModioModTag(ModTag); -} -#pragma endregion diff --git a/Source/Modio/Classes/Types/ModioPagedResult.h b/Source/Modio/Classes/Types/ModioPagedResult.h deleted file mode 100644 index c74950ad..00000000 --- a/Source/Modio/Classes/Types/ModioPagedResult.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "ModioSDK.h" - -// clang-format off -#include "ModioPagedResult.generated.h" -// clang-format on - -/** Base class for all api endpoints that can return paged results */ -USTRUCT(BlueprintType) -struct MODIO_API FModioPagedResult -{ - GENERATED_BODY() - - FModioPagedResult() = default; - FModioPagedResult(const Modio::PagedResult& Other); - FModioPagedResult(int32 ResultOffset, int32 PageSize, int32 TotalResultCount, int32 ResultCount); - - inline int32 GetPageIndex() const - { - return PageIndex; - } - inline int32 GetPageSize() const - { - return PageSize; - } - - inline int32 GetTotalResultCount() const - { - return TotalResultCount; - } - - inline int32 GetResultCount() const - { - return ResultCount; - } -protected: - UPROPERTY(BlueprintReadOnly,Category="mod.io|PagedResult|Page") - int32 PageIndex; - - UPROPERTY(BlueprintReadOnly,Category="mod.io|PagedResult|Page") - int32 PageSize; - - UPROPERTY(BlueprintReadOnly,Category="mod.io|PagedResult|Page") - int32 PageCount; - - UPROPERTY(BlueprintReadOnly,Category="mod.io|PagedResult") - int32 TotalResultCount; - - UPROPERTY(BlueprintReadOnly,Category="mod.io|PagedResult") - int32 ResultCount; -}; - -static_assert(sizeof(FModioPagedResult) == sizeof(Modio::PagedResult), "Modio::PagedResult wrapper size mismatch"); diff --git a/Source/Modio/GeneratedHeader/ModioErrorCondition.h b/Source/Modio/GeneratedHeader/ModioErrorCondition.h new file mode 100644 index 00000000..ec3b83a6 --- /dev/null +++ b/Source/Modio/GeneratedHeader/ModioErrorCondition.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "ModioErrorCondition.generated.h" + +UENUM(BlueprintType) +enum class EModioErrorCondition: uint8 +{ + NoError = 0, + NetworkError = 2 UMETA(ToolTip="When this condition is true, the error code represents a connection or HTTP error between the client and the mod.io server.") , + ConfigurationError = 3 UMETA(ToolTip="When this condition is true, the error code indicates the SDK's configuration is not valid - the game ID or API key are incorrect or the game has been deleted.") , + InvalidArgsError = 4 UMETA(ToolTip="When this condition is true, the error code indicates the arguments passed to the function have failed validation or were otherwise invalid.") , + FilesystemError = 5 UMETA(ToolTip="When this condition is true, the error code indicates a permission or IO error when accessing local filesystem data.") , + InternalError = 6 UMETA(ToolTip="When this condition is true, the error code represents an internal SDK error - please inform mod.io of the error code value.") , + EntityNotFoundError = 12 UMETA(ToolTip="When this condition is true, the error code indicates that a specified game, mod, media file or mod file was not found.") , + UserTermsOfUseError = 13 UMETA(ToolTip="When this condition is true, the error code indicates that the user has not yet accepted the mod.io Terms of Use.") , + SubmitReportError = 14 UMETA(ToolTip="When this condition is true, the error code indicates that a report for the specified content could not be submitted.") , +}; diff --git a/Source/Modio/GeneratedHeader/ModioErrorConditionLibrary.h b/Source/Modio/GeneratedHeader/ModioErrorConditionLibrary.h deleted file mode 100644 index 70b0c47e..00000000 --- a/Source/Modio/GeneratedHeader/ModioErrorConditionLibrary.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include "Kismet/BlueprintFunctionLibrary.h" -#include "Types/ModioErrorCode.h" - -#include "ModioErrorConditionLibrary.generated.h" - -UENUM(BlueprintType) -enum class EModioErrorCondition: uint8 -{ - NoError = 0, - NetworkError = (uint8) Modio::ErrorConditionTypes::NetworkError UMETA(ToolTip="When this condition is true, the error code represents a connection or HTTP error between the client and the mod.io server.") , - ConfigurationError = (uint8) Modio::ErrorConditionTypes::ConfigurationError UMETA(ToolTip="When this condition is true, the error code indicates the SDK's configuration is not valid - the game ID or API key are incorrect or the game has been deleted.") , - InvalidArgsError = (uint8) Modio::ErrorConditionTypes::InvalidArgsError UMETA(ToolTip="When this condition is true, the error code indicates the arguments passed to the function have failed validation or were otherwise invalid.") , - FilesystemError = (uint8) Modio::ErrorConditionTypes::FilesystemError UMETA(ToolTip="When this condition is true, the error code indicates a permission or IO error when accessing local filesystem data.") , - InternalError = (uint8) Modio::ErrorConditionTypes::InternalError UMETA(ToolTip="When this condition is true, the error code represents an internal SDK error - please inform mod.io of the error code value.") , - EntityNotFoundError = (uint8) Modio::ErrorConditionTypes::EntityNotFoundError UMETA(ToolTip="When this condition is true, the error code indicates that a specified game, mod, media file or mod file was not found.") , - UserTermsOfUseError = (uint8) Modio::ErrorConditionTypes::UserTermsOfUseError UMETA(ToolTip="When this condition is true, the error code indicates that the user has not yet accepted the mod.io Terms of Use.") , -}; - -UCLASS() -class UModioErrorConditionLibrary : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() - -public: - /** - * @brief Checks if the passed-in ErrorCode matches the specified error condition - * @param ErrorCode The code to check - * @param Condition The error condition to check against - * @return true if the code matches the condition - */ - UFUNCTION(BlueprintCallable, Category = "mod.io|Error Handling") - static bool ErrorCodeMatches(FModioErrorCode ErrorCode, EModioErrorCondition Condition) - { - if (Condition == EModioErrorCondition::NoError) - { - return (bool)ErrorCode.GetRawErrorCode(); - } - return Modio::ErrorCodeMatches(ErrorCode.GetRawErrorCode(), static_cast(Condition)); - } - -}; \ No newline at end of file diff --git a/Source/Modio/GeneratedSource/ArchiveFileImplementation.cpp b/Source/Modio/GeneratedSource/ArchiveFileImplementation.cpp index 7577b9d9..9e35edba 100644 --- a/Source/Modio/GeneratedSource/ArchiveFileImplementation.cpp +++ b/Source/Modio/GeneratedSource/ArchiveFileImplementation.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/detail/compression/zip/ArchiveFileImplementation.h" #endif diff --git a/Source/Modio/GeneratedSource/HttpSharedState.cpp b/Source/Modio/GeneratedSource/HttpSharedState.cpp index 0adbaf9e..d92f3cf8 100644 --- a/Source/Modio/GeneratedSource/HttpSharedState.cpp +++ b/Source/Modio/GeneratedSource/HttpSharedState.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "common/HttpSharedState.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioBuffer.cpp b/Source/Modio/GeneratedSource/ModioBuffer.cpp index 483500a7..87c298fb 100644 --- a/Source/Modio/GeneratedSource/ModioBuffer.cpp +++ b/Source/Modio/GeneratedSource/ModioBuffer.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/ModioBuffer.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioCacheService.cpp b/Source/Modio/GeneratedSource/ModioCacheService.cpp index 848b6444..aa506a61 100644 --- a/Source/Modio/GeneratedSource/ModioCacheService.cpp +++ b/Source/Modio/GeneratedSource/ModioCacheService.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/cache/ModioCacheService.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioCompressionService.cpp b/Source/Modio/GeneratedSource/ModioCompressionService.cpp index 613d5f6a..5096c944 100644 --- a/Source/Modio/GeneratedSource/ModioCompressionService.cpp +++ b/Source/Modio/GeneratedSource/ModioCompressionService.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/compression/ModioCompressionService.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioFileMetadata.cpp b/Source/Modio/GeneratedSource/ModioFileMetadata.cpp index 39d193c5..768c41a2 100644 --- a/Source/Modio/GeneratedSource/ModioFileMetadata.cpp +++ b/Source/Modio/GeneratedSource/ModioFileMetadata.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/entities/ModioFileMetadata.h" #else diff --git a/Source/Modio/GeneratedSource/ModioFilterParams.cpp b/Source/Modio/GeneratedSource/ModioFilterParams.cpp index 79e6e1c6..c22103ae 100644 --- a/Source/Modio/GeneratedSource/ModioFilterParams.cpp +++ b/Source/Modio/GeneratedSource/ModioFilterParams.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/ModioFilterParams.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioHttpParams.cpp b/Source/Modio/GeneratedSource/ModioHttpParams.cpp index 7037da03..6676286e 100644 --- a/Source/Modio/GeneratedSource/ModioHttpParams.cpp +++ b/Source/Modio/GeneratedSource/ModioHttpParams.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/http/ModioHttpParams.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioHttpRequest.cpp b/Source/Modio/GeneratedSource/ModioHttpRequest.cpp index 66ddf7b9..d94413b7 100644 --- a/Source/Modio/GeneratedSource/ModioHttpRequest.cpp +++ b/Source/Modio/GeneratedSource/ModioHttpRequest.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/http/ModioHttpRequest.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioHttpService.cpp b/Source/Modio/GeneratedSource/ModioHttpService.cpp index a81c5f42..59b74bc0 100644 --- a/Source/Modio/GeneratedSource/ModioHttpService.cpp +++ b/Source/Modio/GeneratedSource/ModioHttpService.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/http/ModioHttpService.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioInitializeOptions.cpp b/Source/Modio/GeneratedSource/ModioInitializeOptions.cpp index 6031f62f..ea623f0d 100644 --- a/Source/Modio/GeneratedSource/ModioInitializeOptions.cpp +++ b/Source/Modio/GeneratedSource/ModioInitializeOptions.cpp @@ -1,4 +1,14 @@ -#ifdef MODIO_SEPARATE_COMPILATION +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/ModioInitializeOptions.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioJsonHelpers.cpp b/Source/Modio/GeneratedSource/ModioJsonHelpers.cpp index 88a70161..03a22a2e 100644 --- a/Source/Modio/GeneratedSource/ModioJsonHelpers.cpp +++ b/Source/Modio/GeneratedSource/ModioJsonHelpers.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/detail/ModioJsonHelpers.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioLogService.cpp b/Source/Modio/GeneratedSource/ModioLogService.cpp index 483aa3ab..396a6423 100644 --- a/Source/Modio/GeneratedSource/ModioLogService.cpp +++ b/Source/Modio/GeneratedSource/ModioLogService.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/ModioLogService.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioModCollectionEntry.cpp b/Source/Modio/GeneratedSource/ModioModCollectionEntry.cpp index bf91028c..3b4d2c64 100644 --- a/Source/Modio/GeneratedSource/ModioModCollectionEntry.cpp +++ b/Source/Modio/GeneratedSource/ModioModCollectionEntry.cpp @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ #ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/ModioModCollectionEntry.h" diff --git a/Source/Modio/GeneratedSource/ModioModDetails.cpp b/Source/Modio/GeneratedSource/ModioModDetails.cpp index 44e6d8ef..02e46d87 100644 --- a/Source/Modio/GeneratedSource/ModioModDetails.cpp +++ b/Source/Modio/GeneratedSource/ModioModDetails.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/entities/ModioModDetails.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioModInfo.cpp b/Source/Modio/GeneratedSource/ModioModInfo.cpp index 7e7eed03..a78121cc 100644 --- a/Source/Modio/GeneratedSource/ModioModInfo.cpp +++ b/Source/Modio/GeneratedSource/ModioModInfo.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/entities/ModioModInfo.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioModStats.cpp b/Source/Modio/GeneratedSource/ModioModStats.cpp index 11c9bab0..a094f0a4 100644 --- a/Source/Modio/GeneratedSource/ModioModStats.cpp +++ b/Source/Modio/GeneratedSource/ModioModStats.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/entities/ModioModStats.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioObjectTrack.cpp b/Source/Modio/GeneratedSource/ModioObjectTrack.cpp index 146a42f9..dd9c321e 100644 --- a/Source/Modio/GeneratedSource/ModioObjectTrack.cpp +++ b/Source/Modio/GeneratedSource/ModioObjectTrack.cpp @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #ifdef MODIO_SEPARATE_COMPILATION #include "modio/detail/ModioObjectTrack.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioPagedResult.cpp b/Source/Modio/GeneratedSource/ModioPagedResult.cpp index 96cce70c..8614f381 100644 --- a/Source/Modio/GeneratedSource/ModioPagedResult.cpp +++ b/Source/Modio/GeneratedSource/ModioPagedResult.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/entities/ModioPagedResult.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioReportParams.cpp b/Source/Modio/GeneratedSource/ModioReportParams.cpp new file mode 100644 index 00000000..5424ba0d --- /dev/null +++ b/Source/Modio/GeneratedSource/ModioReportParams.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#ifdef MODIO_SEPARATE_COMPILATION + #include "modio/core/ModioReportParams.h" +#endif + +#include "modio/detail/ModioConstants.h" +#include "modio/http/ModioHttpParams.h" + +namespace Modio +{ + ReportParams::ReportParams(std::int64_t ResourceID, ResourceType ReportedResourceType, Modio::ReportType Type, + std::string ReportDescription, Modio::Optional ReporterName, + Modio::Optional ReporterContact) + : ReporterName(ReporterName), + ReporterContact(ReporterContact), + ReportDescription(ReportDescription), + ReportedResourceType(ReportedResourceType), + ResourceID(ResourceID), + Type(Type) + {} + + ReportParams::ReportParams(Modio::GameID Game, Modio::ReportType Type, std::string ReportDescription, + Modio::Optional ReporterName, Modio::Optional ReporterContact) + : ReportParams(Game, ResourceType::Game, Type, ReportDescription, ReporterName, ReporterContact) + {} + + ReportParams::ReportParams(Modio::ModID Mod, Modio::ReportType Type, std::string ReportDescription, + Modio::Optional ReporterName, Modio::Optional ReporterContact) + : ReportParams(Mod, ResourceType::Mod, Type, ReportDescription, ReporterName, ReporterContact) + {} + + ReportParams::ReportParams(Modio::UserID User, Modio::ReportType Type, std::string ReportDescription, + Modio::Optional ReporterName, Modio::Optional ReporterContact) + : ReportParams(User, ResourceType::User, Type, ReportDescription, ReporterName, ReporterContact) + {} + Modio::Detail::HttpRequestParams ToRequest(const Modio::ReportParams& Params) + { + std::string ResourceString; + switch (Params.ReportedResourceType) + { + case ReportParams::ResourceType::Game: + ResourceString = "games"; + break; + case ReportParams::ResourceType::Mod: + ResourceString = "mods"; + break; + case ReportParams::ResourceType::User: + ResourceString = "users"; + break; + } + + Modio::Detail::HttpRequestParams Request = Modio::Detail::SubmitReportRequest; + if (Params.ReporterName) + { + Request.AppendPayloadValue(Modio::Detail::Constants::APIStrings::ReportSubmitterName, Params.ReporterName.value()); + } + if (Params.ReporterContact) + { + Request.AppendPayloadValue(Modio::Detail::Constants::APIStrings::ReportSubmitterContact, Params.ReporterContact.value()); + } + + return Request.AppendPayloadValue(Modio::Detail::Constants::APIStrings::ReportResourceType, ResourceString) + .AppendPayloadValue(Modio::Detail::Constants::APIStrings::ReportResourceID, + fmt::format("{}", Params.ResourceID)) + .AppendPayloadValue(Modio::Detail::Constants::APIStrings::ReportType, + fmt::format("{}", static_cast(Params.Type))) + .AppendPayloadValue(Modio::Detail::Constants::APIStrings::ReportSummary, Params.ReportDescription); + } +} // namespace Modio diff --git a/Source/Modio/GeneratedSource/ModioSDKSessionData.cpp b/Source/Modio/GeneratedSource/ModioSDKSessionData.cpp index cbe16b7f..e319d087 100644 --- a/Source/Modio/GeneratedSource/ModioSDKSessionData.cpp +++ b/Source/Modio/GeneratedSource/ModioSDKSessionData.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/detail/ModioSDKSessionData.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioURLList.cpp b/Source/Modio/GeneratedSource/ModioURLList.cpp index 130b19be..c26a61bf 100644 --- a/Source/Modio/GeneratedSource/ModioURLList.cpp +++ b/Source/Modio/GeneratedSource/ModioURLList.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/core/entities/ModioURLList.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioUserDataContainer.cpp b/Source/Modio/GeneratedSource/ModioUserDataContainer.cpp index 93d8b65d..31ed8a1e 100644 --- a/Source/Modio/GeneratedSource/ModioUserDataContainer.cpp +++ b/Source/Modio/GeneratedSource/ModioUserDataContainer.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/detail/userdata/ModioUserDataContainer.h" #endif diff --git a/Source/Modio/GeneratedSource/ModioUserProfile.cpp b/Source/Modio/GeneratedSource/ModioUserProfile.cpp index 734521b9..80ed2d76 100644 --- a/Source/Modio/GeneratedSource/ModioUserProfile.cpp +++ b/Source/Modio/GeneratedSource/ModioUserProfile.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #ifdef MODIO_SEPARATE_COMPILATION #include "modio/detail/userdata/ModioUserProfile.h" #endif diff --git a/Source/Modio/GeneratedSource/SDKCore.cpp b/Source/Modio/GeneratedSource/SDKCore.cpp index 05b3775c..e2877243 100644 --- a/Source/Modio/GeneratedSource/SDKCore.cpp +++ b/Source/Modio/GeneratedSource/SDKCore.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #ifdef MODIO_SEPARATE_COMPILATION @@ -7,6 +17,7 @@ #include "modio/cache/ModioCacheService.h" #include "modio/detail/ModioSDKSessionData.h" #include "modio/detail/ops/ServiceInitializationOp.h" +#include "modio/detail/ops/ReportContentOp.h" #include "modio/detail/ops/Shutdown.h" #include "modio/file/ModioFileService.h" #include "modio/http/ModioHttpService.h" @@ -116,4 +127,15 @@ namespace Modio { return Modio::Detail::SDKSessionData::GetLastValidationError(); } + + void ReportContentAsync(Modio::ReportParams Report, std::function Callback) + { + if (Modio::Detail::RequireSDKIsInitialized(Callback)) + { + + asio::async_compose, void(Modio::ErrorCode)>( + Modio::Detail::ReportContentOp(Report), Callback, + Modio::Detail::Services::GetGlobalContext().get_executor()); + } + } } // namespace Modio diff --git a/Source/Modio/GeneratedSource/SDKModManagement.cpp b/Source/Modio/GeneratedSource/SDKModManagement.cpp index 7bb38c40..801cbd0a 100644 --- a/Source/Modio/GeneratedSource/SDKModManagement.cpp +++ b/Source/Modio/GeneratedSource/SDKModManagement.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #ifdef MODIO_SEPARATE_COMPILATION diff --git a/Source/Modio/GeneratedSource/SDKModMetadata.cpp b/Source/Modio/GeneratedSource/SDKModMetadata.cpp index 3758b6ef..357bd6f9 100644 --- a/Source/Modio/GeneratedSource/SDKModMetadata.cpp +++ b/Source/Modio/GeneratedSource/SDKModMetadata.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #ifdef MODIO_SEPARATE_COMPILATION @@ -16,6 +26,7 @@ #include "modio/detail/ops/mod/GetModMediaLogoOp.h" #include "modio/detail/ops/mod/GetModTagsOp.h" #include "modio/detail/ops/mod/ListAllModsOp.h" +#include "modio/detail/ops/mod/SubmitModRatingOp.h" #include "modio/impl/SDKPreconditionChecks.h" // Implementation header - do not include directly @@ -108,4 +119,14 @@ namespace Modio } } + void SubmitModRatingAsync(Modio::ModID ModID, Modio::Rating Rating, std::function Callback) + { + if (Modio::Detail::RequireSDKIsInitialized(Callback) && Modio::Detail::RequireNotRateLimited(Callback) && + Modio::Detail::RequireUserIsAuthenticated(Callback)) + { + return asio::async_compose, void(Modio::ErrorCode)>( + Modio::Detail::SubmitModRatingOp(ModID, Rating), Callback, + Modio::Detail::Services::GetGlobalContext().get_executor()); + } + } } // namespace Modio diff --git a/Source/Modio/GeneratedSource/SDKUserData.cpp b/Source/Modio/GeneratedSource/SDKUserData.cpp index c04a25d7..50fc9cad 100644 --- a/Source/Modio/GeneratedSource/SDKUserData.cpp +++ b/Source/Modio/GeneratedSource/SDKUserData.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once // Implementation header - do not include directly diff --git a/Source/Modio/GeneratedSource/deflate_stream.cpp b/Source/Modio/GeneratedSource/deflate_stream.cpp index a5bd03e0..ebdf0491 100644 --- a/Source/Modio/GeneratedSource/deflate_stream.cpp +++ b/Source/Modio/GeneratedSource/deflate_stream.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #if(0) //We don't currently create archives, this will be re-enabled later // // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) diff --git a/Source/Modio/GeneratedSource/inflate_stream.cpp b/Source/Modio/GeneratedSource/inflate_stream.cpp index 00fd2c5d..cbe77b46 100644 --- a/Source/Modio/GeneratedSource/inflate_stream.cpp +++ b/Source/Modio/GeneratedSource/inflate_stream.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io SDK. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + // // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) // diff --git a/Source/Modio/Modio.Build.cs b/Source/Modio/Modio.Build.cs index 8d8dce09..91bd2ee6 100644 --- a/Source/Modio/Modio.Build.cs +++ b/Source/Modio/Modio.Build.cs @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. using System.IO; using System.Collections.Generic; @@ -12,7 +22,7 @@ public Modio(ReadOnlyTargetRules Target) : base(Target) bEnableUndefinedIdentifierWarnings = false; bEnforceIWYU = true; - + //bUseUnity = false; //Add stub generated header { string GeneratedHeaderPath = Path.Combine(ModuleDirectory, "GeneratedHeader"); @@ -25,32 +35,32 @@ public Modio(ReadOnlyTargetRules Target) : base(Target) { }; // Silly hack/workaround until 4.26 adds ConditionalAddModuleDirectory - we may change where this lives in the native SDK later - string ErrorConditionLibraryPath = Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/modio/modio/core/ModioErrorConditionLibrary.h"); + string ErrorConditionLibraryPath = Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/modio/modio/core/ModioErrorCondition.h"); // Add dependency on the upstream file so if it is modified we re-run and copy it again ExternalDependencies.Add(ErrorConditionLibraryPath); - File.Copy(ErrorConditionLibraryPath, Path.Combine(GeneratedHeaderPath, "ModioErrorConditionLibrary.h"), true); + File.Copy(ErrorConditionLibraryPath, Path.Combine(GeneratedHeaderPath, "ModioErrorCondition.h"), true); PublicIncludePaths.AddRange(new string[] { - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/modio"), - GeneratedHeaderPath }); PublicSystemIncludePaths.AddRange(new string[] { - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/json/single_include"), - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/filesystem/include"), - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/fmt/include"), - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/optional/include"), - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/platform/interface"), }); PrivateIncludePaths.AddRange(new string[] { - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/asio/asio/include"), - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/utfcpp/source"), - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/httpparser/src"), - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/platform/ms-common/include"), - Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/platform/win32/win32"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/json/single_include"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/filesystem/include"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/fmt/include"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/optional/include"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/asio/asio/include"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/utfcpp/source"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/ext/httpparser/src"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/platform/interface"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/platform/ms-common/include"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/platform/win32/win32"), + Path.Combine(ModuleDirectory, "../ThirdParty/NativeSDK/modio"), + GeneratedHeaderPath }); } // Add native SDK implementation to this module so we don't have to create an extraneous module diff --git a/Source/Modio/Private/Internal/Convert/AuthParams.h b/Source/Modio/Private/Internal/Convert/AuthParams.h new file mode 100644 index 00000000..76d433d1 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/AuthParams.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "ModioSDK.h" +#include "GenericPlatform/GenericPlatformHttp.h" +#include "Internal/ModioConvert.h" +#include "Internal/ModioPrivateDefines.h" +#include "Misc/Optional.h" +#include "Types/ModioAuthenticationParams.h" + + +MODIO_BEGIN_CONVERT_SWITCHES +FORCEINLINE Modio::AuthenticationProvider ToModio(EModioAuthenticationProvider Provider) +{ + switch (Provider) + { + case EModioAuthenticationProvider::XboxLive: + return Modio::AuthenticationProvider::XboxLive; + case EModioAuthenticationProvider::Steam: + return Modio::AuthenticationProvider::Steam; + case EModioAuthenticationProvider::GoG: + return Modio::AuthenticationProvider::GoG; + case EModioAuthenticationProvider::Itch: + return Modio::AuthenticationProvider::Itch; + case EModioAuthenticationProvider::Switch: + return Modio::AuthenticationProvider::Switch; + case EModioAuthenticationProvider::Discord: + return Modio::AuthenticationProvider::Discord; + } + + return Modio::AuthenticationProvider::Steam; +} +MODIO_END_CONVERT_SWITCHES + + +FORCEINLINE Modio::AuthenticationParams ToModio(const FModioAuthenticationParams& UnrealParams) +{ + Modio::AuthenticationParams Params; + Params.AuthToken = ToSTD(FGenericPlatformHttp::UrlEncode(UnrealParams.AuthToken)); + Params.UserEmail = UnrealParams.UserEmail.TrimStartAndEnd().IsEmpty() ? Modio::Optional(ToSTD(UnrealParams.UserEmail)) : Modio::Optional(); + Params.bUserHasAcceptedTerms = UnrealParams.bUserHasAcceptedTerms; + + return Params; +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/ErrorCode.h b/Source/Modio/Private/Internal/Convert/ErrorCode.h new file mode 100644 index 00000000..95e5d34c --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ErrorCode.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "Types/ModioErrorCode.h" +#include "ModioSDK.h" + +FModioErrorCode ToUnreal(Modio::ErrorCode ec) +{ + return FModioErrorCode(ec); +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/FileMetadata.h b/Source/Modio/Private/Internal/Convert/FileMetadata.h new file mode 100644 index 00000000..c3bdc76b --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/FileMetadata.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Internal/ModioPrivateDefines.h" +#include "ModioSDK.h" +#include "Types/ModioFileMetadata.h" + + + + +MODIO_BEGIN_CONVERT_SWITCHES +FORCEINLINE EModioVirusScanStatus ToUnreal(Modio::FileMetadata::VirusScanStatus VirusScanStatus) +{ + switch (VirusScanStatus) + { + case Modio::FileMetadata::VirusScanStatus::NotScanned: + return EModioVirusScanStatus::NotScanned; + case Modio::FileMetadata::VirusScanStatus::ScanComplete: + return EModioVirusScanStatus::ScanComplete; + case Modio::FileMetadata::VirusScanStatus::InProgress: + return EModioVirusScanStatus::InProgress; + case Modio::FileMetadata::VirusScanStatus::TooLargeToScan: + return EModioVirusScanStatus::TooLargeToScan; + case Modio::FileMetadata::VirusScanStatus::FileNotFound: + return EModioVirusScanStatus::FileNotFound; + case Modio::FileMetadata::VirusScanStatus::ErrorScanning: + return EModioVirusScanStatus::ErrorScanning; + } + + return EModioVirusScanStatus::NotScanned; +} + +FORCEINLINE EModioVirusStatus ToUnreal(Modio::FileMetadata::VirusStatus VirusStatus) +{ + switch (VirusStatus) + { + case Modio::FileMetadata::VirusStatus::NoThreat: + return EModioVirusStatus::NoThreat; + case Modio::FileMetadata::VirusStatus::Malicious: + return EModioVirusStatus::Malicious; + } + + return EModioVirusStatus::NoThreat; +} +MODIO_END_CONVERT_SWITCHES + +FORCEINLINE FModioFileMetadata ToUnreal(const Modio::FileMetadata& FileMetadata) +{ + FModioFileMetadata Out; + Out.MetadataId = ToUnreal(FileMetadata.MetadataId); + Out.ModId = ToUnreal(FileMetadata.ModId); + Out.DateAdded = ToUnrealDateTime(FileMetadata.DateAdded); + Out.CurrentVirusScanStatus = ToUnreal(FileMetadata.CurrentVirusScanStatus); + Out.CurrentVirusStatus = ToUnreal(FileMetadata.CurrentVirusStatus); + Out.Filesize = ToUnreal(FileMetadata.Filesize); + Out.Filename = ToUnreal(FileMetadata.Filename); + Out.Version = ToUnreal(FileMetadata.Version); + Out.Changelog = ToUnreal(FileMetadata.Changelog); + Out.MetadataBlob = FString(FileMetadata.MetadataBlob.c_str()); + return Out; +} diff --git a/Source/Modio/Private/Internal/Convert/FilterParams.h b/Source/Modio/Private/Internal/Convert/FilterParams.h new file mode 100644 index 00000000..73b6d5a2 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/FilterParams.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Internal/ModioConvert.h" +#include "Internal/ModioPrivateDefines.h" + +#include "ModioSDK.h" + +MODIO_BEGIN_CONVERT_SWITCHES +FORCEINLINE Modio::FilterParams::SortDirection ToModio(EModioSortDirection SortDirection) +{ + switch (SortDirection) + { + case EModioSortDirection::Ascending: + return Modio::FilterParams::SortDirection::Ascending; + case EModioSortDirection::Descending: + return Modio::FilterParams::SortDirection::Descending; + } + + return Modio::FilterParams::SortDirection::Ascending; +} + +FORCEINLINE Modio::FilterParams::SortFieldType ToModio(EModioSortFieldType Environment) +{ + switch (Environment) + { + case EModioSortFieldType::ID: + return Modio::FilterParams::SortFieldType::ID; + case EModioSortFieldType::DownloadsToday: + return Modio::FilterParams::SortFieldType::DownloadsToday; + case EModioSortFieldType::SubscriberCount: + return Modio::FilterParams::SortFieldType::SubscriberCount; + case EModioSortFieldType::Rating: + return Modio::FilterParams::SortFieldType::Rating; + case EModioSortFieldType::DateMarkedLive: + return Modio::FilterParams::SortFieldType::DateMarkedLive; + case EModioSortFieldType::DateUpdated: + return Modio::FilterParams::SortFieldType::DateUpdated; + } + + return Modio::FilterParams::SortFieldType::ID; +} +MODIO_END_CONVERT_SWITCHES + +FORCEINLINE Modio::FilterParams ToModio(const FModioFilterParams& In ) +{ + + Modio::FilterParams Out; + + if (In.isPaged) + { + Out.PagedResults(In.Index,In.Count); + } + else + { + Out.IndexedResults(In.Index,In.Count); + } + + if (In.DateRangeBegin) + { + Out.MarkedLiveAfter(ToSTD(In.DateRangeBegin.GetValue())); + } + + if (In.DateRangeEnd) + { + Out.MarkedLiveBefore(ToSTD(In.DateRangeEnd.GetValue())); + } + + return Out.SortBy(ToModio(In.SortField), ToModio(In.Direction)) + .NameContains(ToSTD(In.SearchKeywords)) + .MatchingIDs(ToModio(In.IncludedIDs)) + .ExcludingIDs(ToModio(In.ExcludedIDs)) + .WithTags(ToSTD(In.Tags)) + .WithoutTags(ToSTD(In.ExcludedTags)); +} \ No newline at end of file diff --git a/Source/Modio/Private/Types/ModioSDKInitializeOptions.cpp b/Source/Modio/Private/Internal/Convert/InitializeOptions.h similarity index 55% rename from Source/Modio/Private/Types/ModioSDKInitializeOptions.cpp rename to Source/Modio/Private/Internal/Convert/InitializeOptions.h index 38c8134b..b1cdfc0f 100644 --- a/Source/Modio/Private/Types/ModioSDKInitializeOptions.cpp +++ b/Source/Modio/Private/Internal/Convert/InitializeOptions.h @@ -1,10 +1,25 @@ -#include "Types/ModioInitializeOptions.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Internal/ModioConvert.h" +#include "Internal/ModioPrivateDefines.h" +#include "ModioSDK.h" +#include "Types/ModioInitializeOptions.h" #include "Modio.h" + // For GetUserSidString #include #include -static std::string GetUserSidString() +static FORCEINLINE std::string GetUserSidString() { LPSTR SidString = nullptr; @@ -44,14 +59,13 @@ static std::string GetUserSidString() return SIDStringCopy; } - -FModioInitializeOptions::operator Modio::InitializeOptions() const +FORCEINLINE Modio::InitializeOptions ToModio(const FModioInitializeOptions& In ) { - Modio::InitializeOptions Options; - Options.GameID = GameID; - Options.APIKey = APIKey; - Options.GameEnvironment = ToModio(GameEnvironment); - Options.User = GetUserSidString(); - Options.PortalInUse = ToModio(PortalInUse); - return Options; -} + Modio::InitializeOptions Options; + Options.GameID = ToModio(In.GameId); + Options.APIKey = ToModio(In.ApiKey); + Options.GameEnvironment = ToModio(In.GameEnvironment); + Options.User = GetUserSidString(); + Options.PortalInUse = ToModio(In.PortalInUse); + return Options; +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/Metadata.h b/Source/Modio/Private/Internal/Convert/Metadata.h new file mode 100644 index 00000000..c23afbfc --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/Metadata.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "Internal/ModioConvert.h" +#include "ModioSDK.h" + +FORCEINLINE FModioMetadata ToUnreal(const Modio::Metadata& In) +{ + FModioMetadata Out; + Out.Key = ToUnreal(In.Key); + Out.Value = ToUnreal(In.Value); + return Out; +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/ModCollectionEntry.h b/Source/Modio/Private/Internal/Convert/ModCollectionEntry.h new file mode 100644 index 00000000..1347f6ef --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ModCollectionEntry.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Types/ModioModCollectionEntry.h" +#include "Internal/ModioPrivateDefines.h" +#include "Internal/ModioConvert.h" +#include "Internal/Convert/ModInfo.h" +#include "ModioSDK.h" + + +MODIO_BEGIN_CONVERT_SWITCHES +FORCEINLINE EModioModState ToUnreal(Modio::ModState ModState) +{ + switch (ModState) + { + case Modio::ModState::InstallationPending: + return EModioModState::InstallationPending; + case Modio::ModState::Installed: + return EModioModState::Installed; + case Modio::ModState::UpdatePending: + return EModioModState::UpdatePending; + case Modio::ModState::Downloading: + return EModioModState::Downloading; + case Modio::ModState::Extracting: + return EModioModState::Extracting; + case Modio::ModState::UninstallPending: + return EModioModState::UninstallPending; + } + + checkf(false, TEXT("Missed a case in ToUnreal(Modio::ModState ModState)")); + return EModioModState::InstallationPending; +} +MODIO_END_CONVERT_SWITCHES + +FModioModCollectionEntry ToUnreal(const Modio::ModCollectionEntry& In) +{ + FModioModCollectionEntry Out; + Out.ModState = ToUnreal(In.GetModState()); + Out.ModID = ToUnreal(In.GetID()); + Out.ModPath = ToUnreal(In.GetPath()); + Out.ModProfile = ToUnreal(In.GetModProfile()); + return Out; +} + diff --git a/Source/Modio/Private/Internal/Convert/ModInfo.h b/Source/Modio/Private/Internal/Convert/ModInfo.h new file mode 100644 index 00000000..b7490bd7 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ModInfo.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Internal/Convert/FileMetadata.h" +#include "Internal/Convert/Metadata.h" +#include "Internal/Convert/ModStats.h" +#include "Internal/Convert/ModTag.h" +#include "Internal/Convert/URLList.h" +#include "Internal/Convert/User.h" +#include "Internal/ModioConvert.h" +#include "ModioSDK.h" +#include "Types/ModioModInfo.h" + +FORCEINLINE FModioModInfo ToUnreal(const Modio::ModInfo& In) +{ + FModioModInfo Out; + Out.ModId = ToUnreal(In.ModId); + Out.ProfileName = ToUnreal(In.ProfileName); + Out.ProfileSummary = ToUnreal(In.ProfileSummary); + Out.ProfileDescription = ToUnreal(In.ProfileDescription); + Out.ProfileDescriptionPlaintext = ToUnreal(In.ProfileDescriptionPlaintext); + Out.ProfileURL = ToUnreal(In.ProfileURL); + Out.ProfileSubmittedBy = ToUnreal(In.ProfileSubmittedBy); + Out.ProfileDateAdded = ToUnrealDateTime(In.ProfileDateAdded); + Out.ProfileDateUpdated = ToUnrealDateTime(In.ProfileDateUpdated); + Out.ProfileDateLive = ToUnrealDateTime(In.ProfileDateLive); + Out.ProfileMaturityOption = ToUnreal(In.ProfileMaturityOption); + Out.MetadataBlob = FString(In.MetadataBlob.c_str()); // Converting verbatim rather than via TCHAR as ToUnreal does + Out.FileInfo = ToUnreal(In.FileInfo); + Out.MetadataKvp = ToUnreal(In.MetadataKvp); + Out.Tags = ToUnreal(In.Tags); + Out.NumGalleryImages = ToUnreal(In.NumGalleryImages); + Out.YoutubeURLs = ToUnreal(In.YoutubeURLs); + Out.SketchfabURLs = ToUnreal(In.SketchfabURLs); + Out.Stats = ToUnreal(In.Stats); + return Out; +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/ModInfoList.h b/Source/Modio/Private/Internal/Convert/ModInfoList.h new file mode 100644 index 00000000..a3c22b3e --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ModInfoList.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "ModioSDK.h" +#include "Types/ModioModInfoList.h" + +FModioModInfoList ToUnreal(const Modio::ModInfoList& In) +{ + return FModioModInfoList(In); +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/ModManagementEvent.h b/Source/Modio/Private/Internal/Convert/ModManagementEvent.h new file mode 100644 index 00000000..18613971 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ModManagementEvent.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Internal/ModioConvert.h" +#include "Internal/ModioPrivateDefines.h" +#include "ModioSDK.h" +#include "Types/ModioModManagementEvent.h" + + +MODIO_BEGIN_CONVERT_SWITCHES +FORCEINLINE EModioModManagementEventType ToUnreal(Modio::ModManagementEvent::EventType Event) +{ + switch (Event) + { + case Modio::ModManagementEvent::EventType::Installed: + return EModioModManagementEventType::Installed; + case Modio::ModManagementEvent::EventType::Uninstalled: + return EModioModManagementEventType::Uninstalled; + case Modio::ModManagementEvent::EventType::Updated: + return EModioModManagementEventType::Updated; + } + + checkf(false, TEXT("Missed a case in ToModio(EModioEnvironment Environment)")); + return EModioModManagementEventType::Installed; +} +MODIO_END_CONVERT_SWITCHES + + + +FORCEINLINE FModioModManagementEvent ToUnreal(const Modio::ModManagementEvent& In) +{ + FModioModManagementEvent Out; + Out.ID = ToUnreal(In.ID); + Out.Event = ToUnreal(In.Event); + Out.Status = ToUnreal(In.Status); + return Out; +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/ModProgressInfo.h b/Source/Modio/Private/Internal/Convert/ModProgressInfo.h new file mode 100644 index 00000000..3edcbfaa --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ModProgressInfo.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Internal/ModioConvert.h" +#include "ModioSDK.h" +#include "Types/ModioModProgressInfo.h" + +FORCEINLINE FModioModProgressInfo ToUnreal(const Modio::ModProgressInfo& In) +{ + FModioModProgressInfo Out; + Out.TotalDownloadSize = ToUnreal(In.TotalDownloadSize); + Out.CurrentlyDownloadedBytes = ToUnreal(In.CurrentlyDownloadedBytes); + Out.TotalExtractedSizeOnDisk = ToUnreal(In.TotalExtractedSizeOnDisk); + Out.ID = ToUnreal(In.ID); + return Out; +} diff --git a/Source/Modio/Private/Internal/Convert/ModStats.h b/Source/Modio/Private/Internal/Convert/ModStats.h new file mode 100644 index 00000000..2574e329 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ModStats.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Internal/ModioConvert.h" +#include "ModioSDK.h" +#include "Types/ModioModStats.h" + +FORCEINLINE FModioModStats ToUnreal(const Modio::ModStats& In) +{ + FModioModStats Out; + Out.PopularityRankPosition = ToUnreal(In.PopularityRankPosition); + Out.PopularityRankTotalMods = ToUnreal(In.PopularityRankTotalMods); + Out.DownloadsTotal = ToUnreal(In.DownloadsTotal); + Out.SubscribersTotal = ToUnreal(In.SubscribersTotal); + Out.RatingTotal = ToUnreal(In.RatingTotal); + Out.RatingPositive = ToUnreal(In.RatingPositive); + Out.RatingNegative = ToUnreal(In.RatingNegative); + Out.RatingPercentagePositive = ToUnreal(In.RatingPercentagePositive); + Out.RatingWeightedAggregate = ToUnreal(In.RatingWeightedAggregate); + Out.RatingDisplayText = ToUnreal(In.RatingDisplayText); + return Out; +} diff --git a/Source/Modio/Private/Internal/Convert/ModTag.h b/Source/Modio/Private/Internal/Convert/ModTag.h new file mode 100644 index 00000000..0f576491 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ModTag.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Internal/ModioConvert.h" +#include "ModioSDK.h" +#include "Types/ModioModTag.h" + +FORCEINLINE FModioModTag ToUnreal(const Modio::ModTag& In) +{ + FModioModTag Out; + Out.Tag = ToUnreal(In.Tag); + return Out; +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/ModTagInfo.h b/Source/Modio/Private/Internal/Convert/ModTagInfo.h new file mode 100644 index 00000000..99de13d9 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ModTagInfo.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Internal/ModioConvert.h" +#include "ModioSDK.h" +#include "Types/ModioModTagInfo.h" + +FORCEINLINE FModioModTagInfo ToUnreal(const Modio::ModTagInfo& In) +{ + FModioModTagInfo Out; + Out.TagGroupName = ToUnreal(In.TagGroupName); + Out.TagGroupValues = ToUnreal(In.TagGroupValues); + Out.bAllowMultipleSelection = ToUnreal(In.bAllowMultipleSelection); + return Out; +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/ModTagOptions.h b/Source/Modio/Private/Internal/Convert/ModTagOptions.h new file mode 100644 index 00000000..e26110b4 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ModTagOptions.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#pragma once + +#include "ModioSDK.h" +#include "Types/ModioModTagOptions.h" + +FORCEINLINE FModioModTagOptions ToUnreal(const Modio::ModTagOptions& In) +{ + return FModioModTagOptions(In); +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/Rating.h b/Source/Modio/Private/Internal/Convert/Rating.h new file mode 100644 index 00000000..a5a1f8fa --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/Rating.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "ModioSDK.h" +#include "Types/ModioRating.h" + +/// I'd love to just use a static_cast after checking that the value is within the range of the target enum +/// but UE4 doesn't allow signed UENUMS at the present time +/// So a manual switch it is +FORCEINLINE Modio::Rating ToModio(const EModioRating In) +{ + switch (In) + { + case EModioRating::Negative: + return Modio::Rating::Negative; + break; + case EModioRating::Neutral: + return Modio::Rating::Neutral; + break; + case EModioRating::Positive: + return Modio::Rating::Positive; + break; + } + checkf(false, TEXT("EModioRating value was outside the range of expected values")); + return Modio::Rating::Neutral; +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/ReportParams.h b/Source/Modio/Private/Internal/Convert/ReportParams.h new file mode 100644 index 00000000..99ce9288 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/ReportParams.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Internal/ModioConvert.h" +#include "ModioSDK.h" +#include "Types/ModioReportParams.h" + +FORCEINLINE Modio::ReportType ToModio(const EModioReportType& In) +{ + return static_cast(In); +} + +FORCEINLINE Modio::ReportParams ToModio(const FModioReportParams& In) +{ + Modio::Optional ReporterName; + Modio::Optional ReporterContact; + + if (In.ReporterName && !In.ReporterName->TrimStartAndEnd().IsEmpty()) + { + ReporterName = ToSTD(In.ReporterName.GetValue()); + } + + if (In.ReporterContact && !In.ReporterContact->TrimStartAndEnd().IsEmpty()) + { + ReporterContact = ToSTD(In.ReporterContact.GetValue()); + } + + switch (In.ReportedResourceType) + { + case FModioReportParams::ResourceType::Game: + return Modio::ReportParams(Modio::GameID(In.ResourceID), ToModio(In.Type), ToSTD(In.ReportDescription), + ReporterName, ReporterContact); + break; + case FModioReportParams::ResourceType::Mod: + return Modio::ReportParams(Modio::ModID(In.ResourceID), ToModio(In.Type), ToSTD(In.ReportDescription), + ReporterName, ReporterContact); + break; + case FModioReportParams::ResourceType::User: + return Modio::ReportParams(Modio::UserID(In.ResourceID), ToModio(In.Type), ToSTD(In.ReportDescription), + ReporterName, ReporterContact); + break; + } + // There's no sensible default for reported resource type, so returning params with empty description should trip + // the data validation checks on the server and give them the response we want + return Modio::ReportParams(Modio::GameID(-1), ToModio(In.Type), "", {}, {}); +} diff --git a/Source/Modio/Private/Internal/Convert/Terms.h b/Source/Modio/Private/Internal/Convert/Terms.h new file mode 100644 index 00000000..f8b8cdc6 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/Terms.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "ModioSDK.h" +#include "Types/ModioTerms.h" +#include "Internal/ModioConvert.h" + +FORCEINLINE FModioLink ToUnreal(const Modio::Terms::Link& In) +{ + FModioLink Out; + Out.Text = ToUnreal(In.Text); + Out.URL = ToUnreal(In.URL); + Out.bRequired = ToUnreal(In.bRequired); + return Out; +} + +FORCEINLINE FModioTerms ToUnreal(const Modio::Terms& In) +{ + FModioTerms Out; + Out.AgreeButtonText = ToUnreal(In.Buttons.AgreeText); + Out.DisagreeButtonText = ToUnreal(In.Buttons.DisagreeText); + Out.WebsiteLink = ToUnreal(In.Links.Website); + Out.TermsLink = ToUnreal(In.Links.Terms); + Out.PrivacyLink = ToUnreal(In.Links.Privacy); + Out.ManageLink = ToUnreal(In.Links.Manage); + Out.TermsText = ToUnreal(In.TermsText); + return Out; +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/URLList.h b/Source/Modio/Private/Internal/Convert/URLList.h new file mode 100644 index 00000000..58120252 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/URLList.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "ModioSDK.h" +#include "Types/ModioURLList.h" + +FORCEINLINE FModioYoutubeURLList ToUnreal(const Modio::YoutubeURLList& In) +{ + return FModioYoutubeURLList(In); +} + + +FORCEINLINE FModioSketchfabURLList ToUnreal(const Modio::SketchfabURLList& In) +{ + return FModioSketchfabURLList(In); +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/Convert/User.h b/Source/Modio/Private/Internal/Convert/User.h new file mode 100644 index 00000000..32724913 --- /dev/null +++ b/Source/Modio/Private/Internal/Convert/User.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "Internal/ModioConvert.h" +#include "ModioSDK.h" +#include "Types/ModioUser.h" +#include "Types/ModioCommonTypes.h" + +FORCEINLINE FModioUser ToUnreal(const Modio::User& In) { + FModioUser Out; + Out.UserId = FModioUserID(ToUnreal(In.UserId)); + Out.Username = ToUnreal(In.Username); + Out.DateOnline = ToUnreal(In.DateOnline); + Out.ProfileUrl = ToUnreal(In.ProfileUrl); + return Out; +} \ No newline at end of file diff --git a/Source/Modio/Private/Internal/ModioConvert.h b/Source/Modio/Private/Internal/ModioConvert.h new file mode 100644 index 00000000..7105d339 --- /dev/null +++ b/Source/Modio/Private/Internal/ModioConvert.h @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "Containers/StringConv.h" +#include "Containers/UnrealString.h" +#include "Internal/ModioPrivateDefines.h" +#include "Misc/DateTime.h" +#include "ModioSDK.h" +#include "Types/ModioCommonTypes.h" +#include +#include +#include + +FORCEINLINE std::string ToSTD(const FString& String); +FORCEINLINE std::vector ToSTD(const TArray& StringArray); +FORCEINLINE std::chrono::system_clock::time_point ToSTD(FDateTime Time); + +// @todo: Make a ToModio that handles TOptional through templates + +FORCEINLINE int64 ToUnreal(std::int64_t Value); +FORCEINLINE uint8 ToUnreal(std::uint8_t Value); +FORCEINLINE double ToUnreal(double Value); +FORCEINLINE bool ToUnreal(bool Value); +FORCEINLINE uint64 ToUnreal(std::size_t Value); +FORCEINLINE FString ToUnreal(const std::string& String); +FORCEINLINE FString ToUnreal(const Modio::filesystem::path& Path); +FORCEINLINE FDateTime ToUnrealDateTime(std::int64_t UnixTimestamp); + +template +FORCEINLINE TArray ToUnreal(std::vector&& OriginalArray); + +template +FORCEINLINE TArray ToUnreal(const std::vector& OriginalArray); + +template +FORCEINLINE std::vector ToModio(const TArray& OriginalArray); + +FORCEINLINE Modio::ApiKey ToModio(const FModioApiKey& In); + +FORCEINLINE Modio::EmailAddress ToModio(const FModioEmailAddress& In); + +FORCEINLINE Modio::EmailAuthCode ToModio(const FModioEmailAuthCode& In); + +FORCEINLINE Modio::ModID ToModio(const FModioModID& In); +FORCEINLINE Modio::GameID ToModio(const FModioGameID& In); +FORCEINLINE Modio::FileMetadataID ToModio(const FModioFileMetadataID& In); +FORCEINLINE Modio::UserID ToModio(const FModioUserID& In); + +#pragma region Implementation + +// @todo: Rename this to ToModio as it doesn't matter that it's the part of STD of modio +FORCEINLINE std::string ToSTD(const FString& String) +{ + return std::string(TCHAR_TO_UTF8(*String)); +} + +// @todo: Rename this to ToModio as it doesn't matter that it's the part of STD of modio +FORCEINLINE std::vector ToSTD(const TArray& StringArray) +{ + std::vector Result; + Result.reserve(StringArray.Num()); + for (const FString& It : StringArray) + { + Result.emplace_back(TCHAR_TO_UTF8(*It)); + } + return Result; +} + +// @todo: Rename this to ToModio as it doesn't matter that it's the part of STD of modio +FORCEINLINE std::chrono::system_clock::time_point ToSTD(FDateTime Time) +{ + // @todonow: Verify that this becomes correct by printf debugging + return std::chrono::system_clock::time_point(std::chrono::system_clock::duration(Time.ToUnixTimestamp())); +} + +FORCEINLINE int64 ToUnreal(std::int64_t Value) +{ + return Value; +} + +FORCEINLINE bool ToUnreal(bool Value) +{ + return Value; +} + +FORCEINLINE uint8 ToUnreal(std::uint8_t Value) +{ + return Value; +} + +FORCEINLINE double ToUnreal(double Value) +{ + return Value; +} + +FORCEINLINE uint64 ToUnreal(std::size_t Value) +{ + static_assert(sizeof(std::size_t) == sizeof(uint64), "size_t is not 64-bits wide. Are you in x64 configuration?"); + return Value; +} + +FString ToUnreal(const std::string& String) +{ + return UTF8_TO_TCHAR(String.c_str()); +} + +FORCEINLINE FString ToUnreal(const Modio::filesystem::path& Path) +{ + return UTF8_TO_TCHAR(Path.generic_u8string().c_str()); +} + +FORCEINLINE FDateTime ToUnrealDateTime(std::int64_t UnixTimestamp) +{ + return FDateTime::FromUnixTimestamp(UnixTimestamp); +} + +template +TArray ToUnreal(std::vector&& OriginalArray) +{ + TArray Result; + + Result.Reserve(OriginalArray.size()); + for (auto& It : OriginalArray) + { + Result.Emplace(ToUnreal(MoveTemp(It))); + } + + return Result; +} + +template +TArray ToUnreal(const std::vector& OriginalArray) +{ + TArray Result; + + Result.Reserve(OriginalArray.size()); + for (const auto& It : OriginalArray) + { + Result.Emplace(ToUnreal(It)); + } + + return Result; +} + +template +std::vector ToModio(const TArray& OriginalArray) +{ + std::vector Out; + Out.reserve(OriginalArray.Num()); + for (const SourceValueType& Element : OriginalArray) + { + Out.emplace_back(ToModio(Element)); + } + return Out; +} + +FORCEINLINE Modio::ApiKey ToModio(const FModioApiKey& In) +{ + return Modio::ApiKey(TCHAR_TO_UTF8(*In.ToString())); +} + +FORCEINLINE Modio::EmailAddress ToModio(const FModioEmailAddress& In) +{ + return Modio::EmailAddress(TCHAR_TO_UTF8(*In.ToString())); +} + +FORCEINLINE Modio::EmailAuthCode ToModio(const FModioEmailAuthCode& In) +{ + return Modio::EmailAuthCode(TCHAR_TO_UTF8(*In.ToString())); +} + +FORCEINLINE Modio::ModID ToModio(const FModioModID& In) +{ + return Modio::ModID(In.ModID); +} + +FORCEINLINE Modio::GameID ToModio(const FModioGameID& In) +{ + return Modio::GameID(In.GameID); +} +FORCEINLINE Modio::FileMetadataID ToModio(const FModioFileMetadataID& In) +{ + return Modio::FileMetadataID(In.FileMetadataID); +} +FORCEINLINE Modio::UserID ToModio(const FModioUserID& In) +{ + return Modio::UserID(In.UserID); +} + +FORCEINLINE FModioModID ToUnreal(Modio::ModID Value); +FORCEINLINE FModioFileMetadataID ToUnreal(Modio::FileMetadataID Value); + +FORCEINLINE Modio::LogLevel ToModio(EModioLogLevel UnrealLogLevel); +FORCEINLINE Modio::AvatarSize ToModio(EModioAvatarSize AvatarSize); +FORCEINLINE Modio::GallerySize ToModio(EModioGallerySize GallerySize); +FORCEINLINE Modio::LogoSize ToModio(EModioLogoSize LogoSize); +FORCEINLINE Modio::Environment ToModio(EModioEnvironment Environment); +FORCEINLINE Modio::Portal ToModio(EModioPortal Portal); + +#pragma region ToModio implementation + +MODIO_BEGIN_CONVERT_SWITCHES + +Modio::LogLevel ToModio(EModioLogLevel UnrealLogLevel) +{ + switch (UnrealLogLevel) + { + case EModioLogLevel::Error: + return Modio::LogLevel::Error; + case EModioLogLevel::Info: + return Modio::LogLevel::Info; + case EModioLogLevel::Trace: + return Modio::LogLevel::Trace; + case EModioLogLevel::Warning: + return Modio::LogLevel::Warning; + } + + checkf(false, TEXT("Missed a case in ToModio(EModioLogLevel UnrealLogLevel)")); + return Modio::LogLevel::Info; +} + +Modio::AvatarSize ToModio(EModioAvatarSize AvatarSize) +{ + switch (AvatarSize) + { + case EModioAvatarSize::Original: + return Modio::AvatarSize::Original; + case EModioAvatarSize::Thumb50: + return Modio::AvatarSize::Thumb50; + case EModioAvatarSize::Thumb100: + return Modio::AvatarSize::Thumb100; + } + + checkf(false, TEXT("Missed a case in ToModio(EModioAvatarSize AvatarSize)")); + return Modio::AvatarSize::Thumb50; +} + +Modio::GallerySize ToModio(EModioGallerySize GallerySize) +{ + switch (GallerySize) + { + case EModioGallerySize::Original: + return Modio::GallerySize::Original; + case EModioGallerySize::Thumb320: + return Modio::GallerySize::Thumb320; + } + + checkf(false, TEXT("Missed a case in ToModio(EModioGallerySize GallerySize)")); + return Modio::GallerySize::Thumb320; +} + +Modio::LogoSize ToModio(EModioLogoSize LogoSize) +{ + switch (LogoSize) + { + case EModioLogoSize::Original: + return Modio::LogoSize::Original; + case EModioLogoSize::Thumb320: + return Modio::LogoSize::Thumb320; + case EModioLogoSize::Thumb640: + return Modio::LogoSize::Thumb640; + case EModioLogoSize::Thumb1280: + return Modio::LogoSize::Thumb1280; + } + + checkf(false, TEXT("Missed a case in ToModio(EModioLogoSize LogoSize)")); + return Modio::LogoSize::Thumb320; +} + +Modio::Environment ToModio(EModioEnvironment Environment) +{ + switch (Environment) + { + case EModioEnvironment::Test: + return Modio::Environment::Test; + case EModioEnvironment::Live: + return Modio::Environment::Live; + } + + checkf(false, TEXT("Missed a case in ToModio(EModioEnvironment Environment)")); + return Modio::Environment::Test; +} + +Modio::Portal ToModio(EModioPortal Portal) +{ + switch (Portal) + { + case EModioPortal::None: + return Modio::Portal::None; + break; + case EModioPortal::Apple: + return Modio::Portal::Apple; + break; + case EModioPortal::EpicGamesStore: + return Modio::Portal::EpicGamesStore; + break; + case EModioPortal::GOG: + return Modio::Portal::GOG; + break; + case EModioPortal::Google: + return Modio::Portal::Google; + break; + case EModioPortal::Itchio: + return Modio::Portal::Itchio; + break; + case EModioPortal::Nintendo: + return Modio::Portal::Nintendo; + break; + case EModioPortal::PSN: + return Modio::Portal::PSN; + break; + case EModioPortal::Steam: + return Modio::Portal::Steam; + break; + case EModioPortal::XboxLive: + return Modio::Portal::XboxLive; + break; + } + checkf(false, TEXT("Missed a case in ToModio(EModioPortal)")); + return Modio::Portal::None; +} + +FORCEINLINE Modio::Language ToModio(EModioLanguage Language) +{ + switch (Language) + { + case EModioLanguage::English: + return Modio::Language::English; + case EModioLanguage::Bulgarian: + return Modio::Language::Bulgarian; + case EModioLanguage::French: + return Modio::Language::French; + case EModioLanguage::German: + return Modio::Language::German; + case EModioLanguage::Italian: + return Modio::Language::Italian; + case EModioLanguage::Polish: + return Modio::Language::Polish; + case EModioLanguage::Portuguese: + return Modio::Language::Portuguese; + case EModioLanguage::Hungarian: + return Modio::Language::Hungarian; + case EModioLanguage::Japanese: + return Modio::Language::Japanese; + case EModioLanguage::Korean: + return Modio::Language::Korean; + case EModioLanguage::Russian: + return Modio::Language::Russian; + case EModioLanguage::Spanish: + return Modio::Language::Spanish; + case EModioLanguage::Thai: + return Modio::Language::Thai; + case EModioLanguage::ChineseSimplified: + return Modio::Language::ChineseSimplified; + case EModioLanguage::ChineseTraditional: + return Modio::Language::ChineseTraditional; + } + + checkf(false, TEXT("Missed a case in ToModio(EModioLanguage Language)")); + return Modio::Language::English; +} + +MODIO_END_CONVERT_SWITCHES + +FModioModID ToUnreal(Modio::ModID Value) +{ + return FModioModID(Value); +} + +FModioFileMetadataID ToUnreal(Modio::FileMetadataID Value) +{ + return FModioFileMetadataID(Value); +} + +#pragma endregion diff --git a/Source/Modio/Private/Internal/ModioPrivateDefines.h b/Source/Modio/Private/Internal/ModioPrivateDefines.h new file mode 100644 index 00000000..44422c85 --- /dev/null +++ b/Source/Modio/Private/Internal/ModioPrivateDefines.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +// This makes missing a value in the switch statement a fatal error, is disabled after our conversion routines +#define MODIO_BEGIN_CONVERT_SWITCHES \ + __pragma(warning(push)) \ + __pragma(warning(error : 4062)) + +#define MODIO_END_CONVERT_SWITCHES \ + __pragma(warning(pop)) diff --git a/Source/Modio/Private/Libraries/ModioCommonTypesLibrary.cpp b/Source/Modio/Private/Libraries/ModioCommonTypesLibrary.cpp index ad71e8fd..1cb957f7 100644 --- a/Source/Modio/Private/Libraries/ModioCommonTypesLibrary.cpp +++ b/Source/Modio/Private/Libraries/ModioCommonTypesLibrary.cpp @@ -1,9 +1,19 @@ -#include "Libraries/ModioCommonTypesLibrary.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Libraries/ModioCommonTypesLibrary.h" #include "Types/ModioAuthenticationParams.h" FModioGameID UModioCommonTypesLibrary::MakeGameId(int64 GameId) { - return FModioGameID(Modio::GameID(GameId)); + return FModioGameID(GameId); } FString UModioCommonTypesLibrary::Conv_GameIDToString(FModioGameID GameId) @@ -66,8 +76,8 @@ FString UModioCommonTypesLibrary::Conv_UserIDToString(FModioUserID UserID) FModioInitializeOptions UModioCommonTypesLibrary::MakeInitializeOptions(int64 GameId, const FString& APIKey, EModioEnvironment GameEnvironment, EModioPortal PortalInUse) { FModioInitializeOptions Options; - Options.GameID = FModioGameID(GameId); - Options.APIKey = FModioApiKey(APIKey); + Options.GameId = FModioGameID(GameId); + Options.ApiKey = FModioApiKey(APIKey); Options.GameEnvironment = GameEnvironment; Options.PortalInUse = PortalInUse; return Options; diff --git a/Source/Modio/Private/Libraries/ModioErrorCodeLibrary.cpp b/Source/Modio/Private/Libraries/ModioErrorCodeLibrary.cpp index c5b94315..68e3bac0 100644 --- a/Source/Modio/Private/Libraries/ModioErrorCodeLibrary.cpp +++ b/Source/Modio/Private/Libraries/ModioErrorCodeLibrary.cpp @@ -1,4 +1,14 @@ -#include "Libraries/ModioErrorCodeLibrary.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Libraries/ModioErrorCodeLibrary.h" bool UModioErrorCodeLibrary::IsError(const FModioErrorCode& Error) { diff --git a/Source/Modio/Private/Libraries/ModioErrorConditionLibrary.cpp b/Source/Modio/Private/Libraries/ModioErrorConditionLibrary.cpp new file mode 100644 index 00000000..550cd05d --- /dev/null +++ b/Source/Modio/Private/Libraries/ModioErrorConditionLibrary.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Libraries/ModioErrorConditionLibrary.h" +#include "ModioSDK.h" + +bool UModioErrorConditionLibrary::ErrorCodeMatches(FModioErrorCode ErrorCode, EModioErrorCondition Condition) +{ + if (Condition == EModioErrorCondition::NoError) + { + return (bool) ErrorCode.GetRawErrorCode(); + } + return Modio::ErrorCodeMatches(ErrorCode.GetRawErrorCode(), static_cast(Condition)); +} diff --git a/Source/Modio/Private/Libraries/ModioFilterParamsLibrary.cpp b/Source/Modio/Private/Libraries/ModioFilterParamsLibrary.cpp index ce8436fe..3a64591c 100644 --- a/Source/Modio/Private/Libraries/ModioFilterParamsLibrary.cpp +++ b/Source/Modio/Private/Libraries/ModioFilterParamsLibrary.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #include "Libraries/ModioFilterParamsLibrary.h" FModioFilterParams& UModioFilterParamsLibrary::SortBy(FModioFilterParams& Filter, EModioSortFieldType ByField, diff --git a/Source/Modio/Private/Libraries/ModioImageLibrary.cpp b/Source/Modio/Private/Libraries/ModioImageLibrary.cpp index 546505d0..1758adba 100644 --- a/Source/Modio/Private/Libraries/ModioImageLibrary.cpp +++ b/Source/Modio/Private/Libraries/ModioImageLibrary.cpp @@ -1,4 +1,14 @@ -#include "Libraries/ModioImageLibrary.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Libraries/ModioImageLibrary.h" #include "Engine/Texture.h" #include "Internal/ModioPrivateDefines.h" diff --git a/Source/Modio/Private/Libraries/ModioModCollectionLibrary.cpp b/Source/Modio/Private/Libraries/ModioModCollectionLibrary.cpp index 167432bd..5f2708a6 100644 --- a/Source/Modio/Private/Libraries/ModioModCollectionLibrary.cpp +++ b/Source/Modio/Private/Libraries/ModioModCollectionLibrary.cpp @@ -1,4 +1,14 @@ -#include "Libraries/ModioModCollectionLibrary.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Libraries/ModioModCollectionLibrary.h" EModioModState UModioModCollectionLibrary::GetModState(const FModioModCollectionEntry& Entry) { @@ -15,7 +25,7 @@ const FModioModInfo& UModioModCollectionLibrary::GetModProfile(const FModioModCo return Entry.GetModProfile(); } -const FString& UModioModCollectionLibrary::GetPath(const FModioModCollectionEntry& Entry) +const FString UModioModCollectionLibrary::GetPath(const FModioModCollectionEntry& Entry) { return Entry.GetPath(); } diff --git a/Source/Modio/Private/Libraries/ModioModInfoListLibrary.cpp b/Source/Modio/Private/Libraries/ModioModInfoListLibrary.cpp index 345f2e28..b7086cdb 100644 --- a/Source/Modio/Private/Libraries/ModioModInfoListLibrary.cpp +++ b/Source/Modio/Private/Libraries/ModioModInfoListLibrary.cpp @@ -1,4 +1,14 @@ -#include "Libraries/ModioModInfoListLibrary.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Libraries/ModioModInfoListLibrary.h" const TArray& UModioModInfoListLibrary::GetMods(const FModioModInfoList& ModInfoList) { diff --git a/Source/Modio/Private/Libraries/ModioModTagOptionsLibrary.cpp b/Source/Modio/Private/Libraries/ModioModTagOptionsLibrary.cpp index 29187001..79781e76 100644 --- a/Source/Modio/Private/Libraries/ModioModTagOptionsLibrary.cpp +++ b/Source/Modio/Private/Libraries/ModioModTagOptionsLibrary.cpp @@ -1,4 +1,14 @@ -#include "Libraries/ModioModTagOptionsLibrary.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Libraries/ModioModTagOptionsLibrary.h" const TArray& UModioModTagOptionsLibrary::GetTags(const FModioModTagOptions& ModTags) { diff --git a/Source/Modio/Private/Libraries/ModioOptionalLibrary.cpp b/Source/Modio/Private/Libraries/ModioOptionalLibrary.cpp index 5b4bea18..a78e95c2 100644 --- a/Source/Modio/Private/Libraries/ModioOptionalLibrary.cpp +++ b/Source/Modio/Private/Libraries/ModioOptionalLibrary.cpp @@ -1,4 +1,14 @@ -#include "Libraries/ModioOptionalLibrary.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Libraries/ModioOptionalLibrary.h" #include "Types/ModioModInfoList.h" #include "Types/ModioModTagOptions.h" #include "Types/ModioUser.h" diff --git a/Source/Modio/Private/Libraries/ModioReportLibrary.cpp b/Source/Modio/Private/Libraries/ModioReportLibrary.cpp new file mode 100644 index 00000000..24bf9339 --- /dev/null +++ b/Source/Modio/Private/Libraries/ModioReportLibrary.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Libraries/ModioReportLibrary.h" +#include "Types/ModioCommonTypes.h" + +FModioReportParams UModioReportLibrary::MakeReportForGame(FModioGameID Game, EModioReportType Type, + FString ReportDescription, FString ReporterName, + FString ReporterContact) +{ + return FModioReportParams(Game, Type, ReportDescription, ReporterName, ReporterContact); +} + +FModioReportParams UModioReportLibrary::MakeReportForUser(FModioUserID User, EModioReportType Type, + FString ReportDescription, FString ReporterName, + FString ReporterContact) +{ + return FModioReportParams(User, Type, ReportDescription, ReporterName, ReporterContact); +} + +FModioReportParams UModioReportLibrary::MakeReportForMod(FModioModID Mod, EModioReportType Type, + FString ReportDescription, FString ReporterName, + FString ReporterContact) +{ + return FModioReportParams(Mod, Type, ReportDescription, ReporterName, ReporterContact); +} diff --git a/Source/Modio/Private/Libraries/ModioSDKLibrary.cpp b/Source/Modio/Private/Libraries/ModioSDKLibrary.cpp index 6b72393a..9516b3a3 100644 --- a/Source/Modio/Private/Libraries/ModioSDKLibrary.cpp +++ b/Source/Modio/Private/Libraries/ModioSDKLibrary.cpp @@ -1,4 +1,14 @@ -#include "Libraries/ModioSDKLibrary.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Libraries/ModioSDKLibrary.h" #include "ModioSettings.h" #include "Internationalization/Regex.h" @@ -22,9 +32,9 @@ FModioInitializeOptions UModioSDKLibrary::GetProjectInitializeOptions() const UModioSettings* Settings = GetDefault(); FModioInitializeOptions Options; - Options.APIKey = FModioApiKey(Settings->ApiKey); + Options.ApiKey = FModioApiKey(Settings->ApiKey); Options.GameEnvironment = Settings->Environment; - Options.GameID = FModioGameID(Settings->GameId); + Options.GameId = FModioGameID(Settings->GameId); return Options; } diff --git a/Source/Modio/Private/Modio.cpp b/Source/Modio/Private/Modio.cpp index 601ff791..f4815473 100644 --- a/Source/Modio/Private/Modio.cpp +++ b/Source/Modio/Private/Modio.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #include "Modio.h" DEFINE_LOG_CATEGORY(LogModio) \ No newline at end of file diff --git a/Source/Modio/Private/ModioImageCache.cpp b/Source/Modio/Private/ModioImageCache.cpp index a5b2e2a8..99febe97 100644 --- a/Source/Modio/Private/ModioImageCache.cpp +++ b/Source/Modio/Private/ModioImageCache.cpp @@ -1,4 +1,14 @@ -#include "ModioImageCache.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "ModioImageCache.h" #include "Engine/Texture2DDynamic.h" bool FModioImageCache::IsStaleState(const FImageState& State) const diff --git a/Source/Modio/Private/ModioModule.cpp b/Source/Modio/Private/ModioModule.cpp index 25fde92d..0476c2d9 100644 --- a/Source/Modio/Private/ModioModule.cpp +++ b/Source/Modio/Private/ModioModule.cpp @@ -1,4 +1,13 @@ - +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #include "ModioModule.h" diff --git a/Source/Modio/Private/ModioModule.h b/Source/Modio/Private/ModioModule.h index 496638c7..17e120ca 100644 --- a/Source/Modio/Private/ModioModule.h +++ b/Source/Modio/Private/ModioModule.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Modules/ModuleManager.h" diff --git a/Source/Modio/Private/ModioPrivatePCH.h b/Source/Modio/Private/ModioPrivatePCH.h index ccc9896d..d77ffa2b 100644 --- a/Source/Modio/Private/ModioPrivatePCH.h +++ b/Source/Modio/Private/ModioPrivatePCH.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once //#include "ModioSDK.h" diff --git a/Source/Modio/Private/ModioSettings.cpp b/Source/Modio/Private/ModioSettings.cpp index 0beb8f3a..3bdc22ed 100644 --- a/Source/Modio/Private/ModioSettings.cpp +++ b/Source/Modio/Private/ModioSettings.cpp @@ -1,4 +1,14 @@ -#include "ModioSettings.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "ModioSettings.h" #include "Engine/Engine.h" #include "ModioSubsystem.h" diff --git a/Source/Modio/Private/ModioSubsystem.cpp b/Source/Modio/Private/ModioSubsystem.cpp index 364404bd..272d9c3c 100644 --- a/Source/Modio/Private/ModioSubsystem.cpp +++ b/Source/Modio/Private/ModioSubsystem.cpp @@ -1,5 +1,31 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #include "ModioSubsystem.h" #include "Engine/Engine.h" +#include "Internal/Convert/AuthParams.h" +#include "Internal/Convert/ErrorCode.h" +#include "Internal/Convert/FilterParams.h" +#include "Internal/Convert/InitializeOptions.h" +#include "Internal/Convert/ModCollectionEntry.h" +#include "Internal/Convert/ModInfo.h" +#include "Internal/Convert/ModInfoList.h" +#include "Internal/Convert/ModManagementEvent.h" +#include "Internal/Convert/ModProgressInfo.h" +#include "Internal/Convert/ModTagInfo.h" +#include "Internal/Convert/ModTagOptions.h" +#include "Internal/Convert/Rating.h" +#include "Internal/Convert/ReportParams.h" +#include "Internal/Convert/Terms.h" +#include "Internal/Convert/User.h" +#include "Internal/ModioConvert.h" #include "ModioSettings.h" #include @@ -38,7 +64,7 @@ bool UModioSubsystem::ShouldCreateSubsystem(UObject* Outer) const void UModioSubsystem::InitializeAsync(const FModioInitializeOptions& Options, FOnErrorOnlyDelegateFast OnInitComplete) { - Modio::InitializeAsync(Options, [this, OnInitComplete](Modio::ErrorCode ec) { + Modio::InitializeAsync(ToModio(Options), [this, OnInitComplete](Modio::ErrorCode ec) { InvalidateUserSubscriptionCache(); OnInitComplete.ExecuteIfBound(ToUnreal(ec)); @@ -54,14 +80,15 @@ void UModioSubsystem::K2_InitializeAsync(const FModioInitializeOptions& Initiali void UModioSubsystem::ListAllModsAsync(const FModioFilterParams& Filter, FOnListAllModsDelegateFast Callback) { - Modio::ListAllModsAsync(*Filter, [Callback](Modio::ErrorCode ec, Modio::Optional Result) { - Callback.ExecuteIfBound(ec, ToUnrealOptional(Result)); - }); + Modio::ListAllModsAsync(ToModio(Filter), + [Callback](Modio::ErrorCode ec, Modio::Optional Result) { + Callback.ExecuteIfBound(ec, ToUnrealOptional(Result)); + }); } void UModioSubsystem::SubscribeToModAsync(FModioModID ModToSubscribeTo, FOnErrorOnlyDelegateFast OnSubscribeComplete) { - Modio::SubscribeToModAsync(ModToSubscribeTo, [this, OnSubscribeComplete](Modio::ErrorCode ec) { + Modio::SubscribeToModAsync(ToModio(ModToSubscribeTo), [this, OnSubscribeComplete](Modio::ErrorCode ec) { InvalidateUserSubscriptionCache(); OnSubscribeComplete.ExecuteIfBound(ToUnreal(ec)); @@ -71,7 +98,7 @@ void UModioSubsystem::SubscribeToModAsync(FModioModID ModToSubscribeTo, FOnError void UModioSubsystem::UnsubscribeFromModAsync(FModioModID ModToUnsubscribeFrom, FOnErrorOnlyDelegateFast OnUnsubscribeComplete) { - Modio::UnsubscribeFromModAsync(ModToUnsubscribeFrom, [this, OnUnsubscribeComplete](Modio::ErrorCode ec) { + Modio::UnsubscribeFromModAsync(ToModio(ModToUnsubscribeFrom), [this, OnUnsubscribeComplete](Modio::ErrorCode ec) { InvalidateUserSubscriptionCache(); OnUnsubscribeComplete.ExecuteIfBound(ToUnreal(ec)); @@ -91,7 +118,7 @@ void UModioSubsystem::EnableModManagement(FOnModManagementDelegateFast Callback) Modio::EnableModManagement([this, Callback](Modio::ModManagementEvent Event) { // @todo: For some smarter caching, look at the event and see if we should invalidate the cache InvalidateUserInstallationCache(); - Callback.ExecuteIfBound(Event); + Callback.ExecuteIfBound(ToUnreal(Event)); }); } @@ -212,7 +239,7 @@ FModioOptionalUser UModioSubsystem::K2_QueryUserProfile() void UModioSubsystem::GetModInfoAsync(FModioModID ModId, FOnGetModInfoDelegateFast Callback) { - Modio::GetModInfoAsync(ModId, [Callback](Modio::ErrorCode ec, Modio::Optional ModInfo) { + Modio::GetModInfoAsync(ToModio(ModId), [Callback](Modio::ErrorCode ec, Modio::Optional ModInfo) { Callback.ExecuteIfBound(ec, ToUnrealOptional(ModInfo)); }); } @@ -227,26 +254,65 @@ void UModioSubsystem::K2_GetModInfoAsync(FModioModID ModId, FOnGetModInfoDelegat void UModioSubsystem::GetModMediaAsync(FModioModID ModId, EModioAvatarSize AvatarSize, FOnGetMediaDelegateFast Callback) { - Modio::GetModMediaAsync(ModId, ToModio(AvatarSize), + Modio::GetModMediaAsync(ToModio(ModId), ToModio(AvatarSize), [Callback](Modio::ErrorCode ec, Modio::Optional Path) { - Callback.ExecuteIfBound(ec, ToUnrealOptional(Path)); + // Manually calling ToUnreal on the path and assigning to the member of FModioImage + // because we already have a Modio::filesystem::path -> FString overload of ToUnreal + // TODO: @modio-ue4 Potentially refactor ToUnreal(Modio::filesystem::path) as a template + // function returning type T so we can be explicit about the expected type + if (Path) + { + FModioImage Out; + Out.ImagePath = ToUnreal(Path.value()); + Callback.ExecuteIfBound(ec, Out); + } + else + { + Callback.ExecuteIfBound(ec, {}); + } }); } void UModioSubsystem::GetModMediaAsync(FModioModID ModId, EModioGallerySize GallerySize, Modio::GalleryIndex Index, FOnGetMediaDelegateFast Callback) { - Modio::GetModMediaAsync(ModId, ToModio(GallerySize), Index, + Modio::GetModMediaAsync(ToModio(ModId), ToModio(GallerySize), Index, [Callback](Modio::ErrorCode ec, Modio::Optional Path) { - Callback.ExecuteIfBound(ec, ToUnrealOptional(Path)); + // Manually calling ToUnreal on the path and assigning to the member of FModioImage + // because we already have a Modio::filesystem::path -> FString overload of ToUnreal + // TODO: @modio-ue4 Potentially refactor ToUnreal(Modio::filesystem::path) as a template + // function returning type T so we can be explicit about the expected type + if (Path) + { + FModioImage Out; + Out.ImagePath = ToUnreal(Path.value()); + Callback.ExecuteIfBound(ec, Out); + } + else + { + Callback.ExecuteIfBound(ec, {}); + } }); } void UModioSubsystem::GetModMediaAsync(FModioModID ModId, EModioLogoSize LogoSize, FOnGetMediaDelegateFast Callback) { - Modio::GetModMediaAsync(ModId, ToModio(LogoSize), + Modio::GetModMediaAsync(ToModio(ModId), ToModio(LogoSize), [Callback](Modio::ErrorCode ec, Modio::Optional Path) { - Callback.ExecuteIfBound(ec, ToUnrealOptional(Path)); + // Manually calling ToUnreal on the path and assigning to the member of FModioImage + // because we already have a Modio::filesystem::path -> FString overload of ToUnreal + // TODO: @modio-ue4 Potentially refactor ToUnreal(Modio::filesystem::path) as a template + // function returning type T so we can be explicit about the expected type + if (Path) + { + FModioImage Out; + Out.ImagePath = ToUnreal(Path.value()); + Callback.ExecuteIfBound(ec, Out); + } + else + { + Callback.ExecuteIfBound(ec, {}); + } }); } @@ -305,7 +371,7 @@ void UModioSubsystem::K2_GetModTagOptionsAsync(FOnGetModTagOptionsDelegate Callb void UModioSubsystem::RequestEmailAuthCodeAsync(const FModioEmailAddress& EmailAddress, FOnErrorOnlyDelegateFast Callback) { - Modio::RequestEmailAuthCodeAsync(EmailAddress, + Modio::RequestEmailAuthCodeAsync(ToModio(EmailAddress), [Callback](Modio::ErrorCode ec) { Callback.ExecuteIfBound(ToUnreal(ec)); }); } @@ -319,7 +385,7 @@ void UModioSubsystem::K2_RequestEmailAuthCodeAsync(const FModioEmailAddress& Ema void UModioSubsystem::AuthenticateUserEmailAsync(const FModioEmailAuthCode& AuthenticationCode, FOnErrorOnlyDelegateFast Callback) { - Modio::AuthenticateUserEmailAsync(AuthenticationCode, + Modio::AuthenticateUserEmailAsync(ToModio(AuthenticationCode), [Callback](FModioErrorCode ec) { Callback.ExecuteIfBound(ec); }); } @@ -335,7 +401,7 @@ void UModioSubsystem::AuthenticateUserExternalAsync(const FModioAuthenticationPa EModioAuthenticationProvider Provider, FOnErrorOnlyDelegateFast Callback) { - Modio::AuthenticateUserExternalAsync(User, ToModio(Provider), + Modio::AuthenticateUserExternalAsync(ToModio(User), ToModio(Provider), [Callback](Modio::ErrorCode ec) { Callback.ExecuteIfBound(ec); }); } @@ -382,7 +448,20 @@ void UModioSubsystem::GetUserMediaAsync(EModioAvatarSize AvatarSize, FOnGetMedia { Modio::GetUserMediaAsync(ToModio(AvatarSize), [Callback](Modio::ErrorCode ec, Modio::Optional Media) { - Callback.ExecuteIfBound(ec, ToUnrealOptional(Media)); + // Manually calling ToUnreal on the path and assigning to the member of FModioImage + // because we already have a Modio::filesystem::path -> FString overload of ToUnreal + // TODO: @modio-ue4 Potentially refactor ToUnreal(Modio::filesystem::path) as a + // template function returning type T so we can be explicit about the expected type + if (Media) + { + FModioImage Out; + Out.ImagePath = ToUnreal(Media.value()); + Callback.ExecuteIfBound(ec, Out); + } + else + { + Callback.ExecuteIfBound(ec, {}); + } }); } @@ -427,7 +506,35 @@ TMap UModioSubsystem::QuerySystemInstalla void UModioSubsystem::ForceUninstallModAsync(FModioModID ModToRemove, FOnErrorOnlyDelegate Callback) { - Modio::ForceUninstallModAsync(ModToRemove, [Callback](FModioErrorCode ec) { Callback.ExecuteIfBound(ec); }); + Modio::ForceUninstallModAsync(ToModio(ModToRemove), + [Callback](FModioErrorCode ec) { Callback.ExecuteIfBound(ec); }); +} + +void UModioSubsystem::SubmitModRatingAsync(FModioModID Mod, EModioRating Rating, + FOnErrorOnlyDelegateFast Callback) +{ + Modio::SubmitModRatingAsync(ToModio(Mod), ToModio(Rating), + [Callback](FModioErrorCode ec) { Callback.ExecuteIfBound(ec); }); +} + +void UModioSubsystem::K2_SubmitModRatingAsync(FModioModID Mod, EModioRating Rating, + FOnErrorOnlyDelegate Callback) +{ + SubmitModRatingAsync(Mod, Rating, FOnErrorOnlyDelegateFast::CreateLambda([Callback](FModioErrorCode ec) { + Callback.ExecuteIfBound(ec); + })); +} + +void UModioSubsystem::ReportContentAsync(FModioReportParams Report, FOnErrorOnlyDelegateFast Callback) +{ + Modio::ReportContentAsync(ToModio(Report), [Callback](FModioErrorCode ec) { Callback.ExecuteIfBound(ec); }); +} + +void UModioSubsystem::K2_ReportContentAsync(FModioReportParams Report, FOnErrorOnlyDelegate Callback) +{ + ReportContentAsync(Report, FOnErrorOnlyDelegateFast::CreateLambda( + [Callback](FModioErrorCode ec) { Callback.ExecuteIfBound(ec); })); + } /// File scope implementations @@ -441,7 +548,7 @@ TMap ToUnreal(std::map&& OriginalMap Result.Reserve(OriginalMap.size()); for (auto& It : OriginalMap) { - Result.Add(*reinterpret_cast(&It.first), DestValue(MoveTemp(It.second))); + Result.Add(ToUnreal(It.first), ToUnreal(It.second)); } return Result; @@ -453,7 +560,7 @@ TOptional ToUnrealOptional(Source Original) TOptional DestinationOptional = {}; if (Original) { - DestinationOptional = Dest(*Original); + DestinationOptional = ToUnreal(Original.value()); } return DestinationOptional; diff --git a/Source/Modio/Private/Tests/Commands/AuthoriseUserEmailAsync.h b/Source/Modio/Private/Tests/Commands/AuthoriseUserEmailAsync.h index fbd13064..3235c9e7 100644 --- a/Source/Modio/Private/Tests/Commands/AuthoriseUserEmailAsync.h +++ b/Source/Modio/Private/Tests/Commands/AuthoriseUserEmailAsync.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/Commands/DisableModManagement.h b/Source/Modio/Private/Tests/Commands/DisableModManagement.h index aa7bf006..07aafb4e 100644 --- a/Source/Modio/Private/Tests/Commands/DisableModManagement.h +++ b/Source/Modio/Private/Tests/Commands/DisableModManagement.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/Commands/EnableModManagement.h b/Source/Modio/Private/Tests/Commands/EnableModManagement.h index e9c9c0fa..aa407593 100644 --- a/Source/Modio/Private/Tests/Commands/EnableModManagement.h +++ b/Source/Modio/Private/Tests/Commands/EnableModManagement.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/Commands/FetchExternalUpdatesAsync.h b/Source/Modio/Private/Tests/Commands/FetchExternalUpdatesAsync.h index 9c622470..118f7cf2 100644 --- a/Source/Modio/Private/Tests/Commands/FetchExternalUpdatesAsync.h +++ b/Source/Modio/Private/Tests/Commands/FetchExternalUpdatesAsync.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/Commands/GetModInfoAsync.h b/Source/Modio/Private/Tests/Commands/GetModInfoAsync.h index 5b7efbab..cd7bb889 100644 --- a/Source/Modio/Private/Tests/Commands/GetModInfoAsync.h +++ b/Source/Modio/Private/Tests/Commands/GetModInfoAsync.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/Commands/GetModMediaAsync.h b/Source/Modio/Private/Tests/Commands/GetModMediaAsync.h index bef89f7d..dfe9e9bc 100644 --- a/Source/Modio/Private/Tests/Commands/GetModMediaAsync.h +++ b/Source/Modio/Private/Tests/Commands/GetModMediaAsync.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" diff --git a/Source/Modio/Private/Tests/Commands/InitializeAsync.h b/Source/Modio/Private/Tests/Commands/InitializeAsync.h index 655bf489..f44da0c0 100644 --- a/Source/Modio/Private/Tests/Commands/InitializeAsync.h +++ b/Source/Modio/Private/Tests/Commands/InitializeAsync.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/Commands/InitializeBadResponseAsync.h b/Source/Modio/Private/Tests/Commands/InitializeBadResponseAsync.h index 185e8e94..0e8c3dcf 100644 --- a/Source/Modio/Private/Tests/Commands/InitializeBadResponseAsync.h +++ b/Source/Modio/Private/Tests/Commands/InitializeBadResponseAsync.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" @@ -12,9 +22,9 @@ class FModioInitializeBadResponseAsyncCommand : public FModioTestLatentCommandBa virtual void Start() override { FModioInitializeOptions Opts; - Opts.APIKey = FModioApiKey("8d561adc585f3292356a20ef6502ae64"); + Opts.ApiKey = FModioApiKey("8d561adc585f3292356a20ef6502ae64"); Opts.GameEnvironment = EModioEnvironment::Test; - Opts.GameID = FModioGameID(788); + Opts.GameId = FModioGameID(788); Modio->InitializeAsync(Opts, FOnErrorOnlyDelegateFast::CreateSP(this, &FModioInitializeBadResponseAsyncCommand::Callback)); } diff --git a/Source/Modio/Private/Tests/Commands/IsModManagementBusy.h b/Source/Modio/Private/Tests/Commands/IsModManagementBusy.h index 9bcccecb..4c812c07 100644 --- a/Source/Modio/Private/Tests/Commands/IsModManagementBusy.h +++ b/Source/Modio/Private/Tests/Commands/IsModManagementBusy.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/Commands/ListAllModsAsync.h b/Source/Modio/Private/Tests/Commands/ListAllModsAsync.h index ae75beda..86e1bf06 100644 --- a/Source/Modio/Private/Tests/Commands/ListAllModsAsync.h +++ b/Source/Modio/Private/Tests/Commands/ListAllModsAsync.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" diff --git a/Source/Modio/Private/Tests/Commands/ModioTestCommandBase.cpp b/Source/Modio/Private/Tests/Commands/ModioTestCommandBase.cpp new file mode 100644 index 00000000..521cbbba --- /dev/null +++ b/Source/Modio/Private/Tests/Commands/ModioTestCommandBase.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Tests/Commands/ModioTestCommandBase.h" + +#if WITH_DEV_AUTOMATION_TESTS + +ModioTestExpectedResult MakeExpected(Modio::ErrorCode RawErrorCode) +{ + ModioTestExpectedResult Expected; + Expected.Set(FModioErrorCode(RawErrorCode)); + return Expected; +} + +ModioTestExpectedResult MakeExpected(Modio::ErrorConditionTypes Condition) +{ + ModioTestExpectedResult Expected; + Expected.Set(Condition); + return Expected; +} + +bool CheckExpectedValue(FModioErrorCode ec, ModioTestExpectedResult ExpectedResult) +{ + if (ExpectedResult.IsType()) + { + return ec.GetRawErrorCode() == ExpectedResult.Get().GetRawErrorCode(); + } + else + { + return Modio::ErrorCodeMatches(ec.GetRawErrorCode(), ExpectedResult.Get()); + } +} + + FModioTestLatentCommandBase::FModioTestLatentCommandBase(FAutomationTestBase* AssociatedTest) + : CurrentTest(AssociatedTest) +{ + Modio = GEngine->GetEngineSubsystem(); +} + +bool FModioTestLatentCommandBase::Update() +{ + switch (CurrentState) + { + case LatentCommandState::NotStarted: + CurrentState = LatentCommandState::InProgress; + Start(); + return false; + break; + case LatentCommandState::InProgress: + if (Modio == nullptr) + { + return true; + } + else + { + Modio->RunPendingHandlers(); + return false; + } + break; + case LatentCommandState::Complete: + + return true; + break; + } + return true; +} + +void FModioTestLatentCommandBase::Done() +{ + CurrentState = LatentCommandState::Complete; +} + +#endif diff --git a/Source/Modio/Private/Tests/Commands/ModioTestCommandBase.h b/Source/Modio/Private/Tests/Commands/ModioTestCommandBase.h index 2371a1e9..e87eab52 100644 --- a/Source/Modio/Private/Tests/Commands/ModioTestCommandBase.h +++ b/Source/Modio/Private/Tests/Commands/ModioTestCommandBase.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "Engine.h" @@ -10,31 +20,11 @@ using ModioTestExpectedResult = TVariant; -ModioTestExpectedResult MakeExpected(Modio::ErrorCode RawErrorCode) -{ - ModioTestExpectedResult Expected; - Expected.Set(FModioErrorCode(RawErrorCode)); - return Expected; -} +ModioTestExpectedResult MakeExpected(Modio::ErrorCode RawErrorCode); -ModioTestExpectedResult MakeExpected(Modio::ErrorConditionTypes Condition) -{ - ModioTestExpectedResult Expected; - Expected.Set(Condition); - return Expected; -} +ModioTestExpectedResult MakeExpected(Modio::ErrorConditionTypes Condition); -bool CheckExpectedValue(FModioErrorCode ec, ModioTestExpectedResult ExpectedResult) -{ - if (ExpectedResult.IsType()) - { - return ec.GetRawErrorCode() == ExpectedResult.Get().GetRawErrorCode(); - } - else - { - return Modio::ErrorCodeMatches(ec.GetRawErrorCode(), ExpectedResult.Get()); - } -} +bool CheckExpectedValue(FModioErrorCode ec, ModioTestExpectedResult ExpectedResult); class FModioTestLatentCommandBase : public IAutomationLatentCommand { @@ -50,45 +40,13 @@ class FModioTestLatentCommandBase : public IAutomationLatentCommand FAutomationTestBase* CurrentTest = nullptr; public: - FModioTestLatentCommandBase(FAutomationTestBase* AssociatedTest) : CurrentTest(AssociatedTest) - { - Modio = GEngine->GetEngineSubsystem(); - } + FModioTestLatentCommandBase(FAutomationTestBase* AssociatedTest); virtual ~FModioTestLatentCommandBase() {} - virtual bool Update() override - { - switch (CurrentState) - { - case LatentCommandState::NotStarted: - CurrentState = LatentCommandState::InProgress; - Start(); - return false; - break; - case LatentCommandState::InProgress: - if (Modio == nullptr) - { - return true; - } - else - { - Modio->RunPendingHandlers(); - return false; - } - break; - case LatentCommandState::Complete: - - return true; - break; - } - return true; - } + virtual bool Update() override; UModioSubsystem* Modio = nullptr; virtual void Start() = 0; - virtual void Done() - { - CurrentState = LatentCommandState::Complete; - } + virtual void Done(); }; class FModioTestLatentCommandBaseExpectedResult : public FModioTestLatentCommandBase diff --git a/Source/Modio/Private/Tests/Commands/QueryCurrentModUpdate.h b/Source/Modio/Private/Tests/Commands/QueryCurrentModUpdate.h index ef827f87..6abe1462 100644 --- a/Source/Modio/Private/Tests/Commands/QueryCurrentModUpdate.h +++ b/Source/Modio/Private/Tests/Commands/QueryCurrentModUpdate.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/Commands/ShutdownAsync.h b/Source/Modio/Private/Tests/Commands/ShutdownAsync.h index 3ce302d5..f8b5c988 100644 --- a/Source/Modio/Private/Tests/Commands/ShutdownAsync.h +++ b/Source/Modio/Private/Tests/Commands/ShutdownAsync.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/Commands/SubscribeToModAsync.h b/Source/Modio/Private/Tests/Commands/SubscribeToModAsync.h index c4973d4e..1f564e5f 100644 --- a/Source/Modio/Private/Tests/Commands/SubscribeToModAsync.h +++ b/Source/Modio/Private/Tests/Commands/SubscribeToModAsync.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/Commands/UnsubFromModAsync.h b/Source/Modio/Private/Tests/Commands/UnsubFromModAsync.h index f4b0a5ca..bec677e6 100644 --- a/Source/Modio/Private/Tests/Commands/UnsubFromModAsync.h +++ b/Source/Modio/Private/Tests/Commands/UnsubFromModAsync.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioSubsystem.h" #include "Tests/Commands/ModioTestCommandBase.h" diff --git a/Source/Modio/Private/Tests/GetModInfoTest.cpp b/Source/Modio/Private/Tests/GetModInfoTest.cpp index 0da8bafb..6e26f030 100644 --- a/Source/Modio/Private/Tests/GetModInfoTest.cpp +++ b/Source/Modio/Private/Tests/GetModInfoTest.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #include "Engine.h" #include "Libraries/ModioSDKLibrary.h" #include "Misc/AutomationTest.h" diff --git a/Source/Modio/Private/Tests/InitShutdownTest.cpp b/Source/Modio/Private/Tests/InitShutdownTest.cpp index c790e736..3dac958f 100644 --- a/Source/Modio/Private/Tests/InitShutdownTest.cpp +++ b/Source/Modio/Private/Tests/InitShutdownTest.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #include "Engine.h" #include "Libraries/ModioSDKLibrary.h" #include "Misc/AutomationTest.h" diff --git a/Source/Modio/Private/Tests/ListAllModsTest.cpp b/Source/Modio/Private/Tests/ListAllModsTest.cpp index e17308e9..82af6fc1 100644 --- a/Source/Modio/Private/Tests/ListAllModsTest.cpp +++ b/Source/Modio/Private/Tests/ListAllModsTest.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #include "Engine.h" #include "Libraries/ModioSDKLibrary.h" #include "Misc/AutomationTest.h" diff --git a/Source/Modio/Private/Tests/ModManagementTest.cpp b/Source/Modio/Private/Tests/ModManagementTest.cpp index 3afc6f19..f80e0dc7 100644 --- a/Source/Modio/Private/Tests/ModManagementTest.cpp +++ b/Source/Modio/Private/Tests/ModManagementTest.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #include "Engine.h" #include "Libraries/ModioSDKLibrary.h" #include "Misc/AutomationTest.h" diff --git a/Source/Modio/Private/Tests/ModioTestValidationData.cpp b/Source/Modio/Private/Tests/ModioTestValidationData.cpp index 55e96020..65490848 100644 --- a/Source/Modio/Private/Tests/ModioTestValidationData.cpp +++ b/Source/Modio/Private/Tests/ModioTestValidationData.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + // Fill out your copyright notice in the Description page of Project Settings. #include "Tests/ModioTestValidationData.h" diff --git a/Source/Modio/Private/Tests/ModioTestValidationData.h b/Source/Modio/Private/Tests/ModioTestValidationData.h index 3a217c39..c4f5bc37 100644 --- a/Source/Modio/Private/Tests/ModioTestValidationData.h +++ b/Source/Modio/Private/Tests/ModioTestValidationData.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + // Fill out your copyright notice in the Description page of Project Settings. #pragma once diff --git a/Source/Modio/Private/Tests/SubscriptionTest.cpp b/Source/Modio/Private/Tests/SubscriptionTest.cpp index 548e7976..5c2aaa53 100644 --- a/Source/Modio/Private/Tests/SubscriptionTest.cpp +++ b/Source/Modio/Private/Tests/SubscriptionTest.cpp @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #include "Engine.h" #include "Libraries/ModioSDKLibrary.h" #include "Misc/AutomationTest.h" diff --git a/Source/Modio/Private/Tests/ToModio.cpp b/Source/Modio/Private/Tests/ToModio.cpp index b394f670..2d153ba5 100644 --- a/Source/Modio/Private/Tests/ToModio.cpp +++ b/Source/Modio/Private/Tests/ToModio.cpp @@ -1,6 +1,18 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #include "Engine.h" +#include "Internal/Convert/AuthParams.h" #include "Libraries/ModioSDKLibrary.h" #include "Misc/AutomationTest.h" +#include "ModioSDK.h" #include "Types/ModioAuthenticationParams.h" #include "Types/ModioModStats.h" @@ -27,6 +39,4 @@ bool FModioConvertDataToNativeFormatTest::RunTest(const FString& Parameters) return true; } - - #endif // WITH_DEV_AUTOMATION_TESTS \ No newline at end of file diff --git a/Source/Modio/Private/Tests/ToUnreal.cpp b/Source/Modio/Private/Tests/ToUnreal.cpp index 571847f5..54bf2dd4 100644 --- a/Source/Modio/Private/Tests/ToUnreal.cpp +++ b/Source/Modio/Private/Tests/ToUnreal.cpp @@ -1,9 +1,20 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #include "Engine.h" #include "Libraries/ModioSDKLibrary.h" #include "Misc/AutomationTest.h" #include "Tests/Commands/InitializeAsync.h" #include "Tests/Commands/ShutdownAsync.h" #include "Tests/Commands/SubscribeToModAsync.h" +#include "Internal/Convert/ModStats.h" #if WITH_DEV_AUTOMATION_TESTS diff --git a/Source/Modio/Private/Types/ModioAuthenticationParams.cpp b/Source/Modio/Private/Types/ModioAuthenticationParams.cpp deleted file mode 100644 index d1cf85e2..00000000 --- a/Source/Modio/Private/Types/ModioAuthenticationParams.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "Types/ModioAuthenticationParams.h" -#include "Internal/ModioConvert.h" -#include "GenericPlatform/GenericPlatformHttp.h" - -FModioAuthenticationParams::operator Modio::AuthenticationParams() const -{ - Modio::AuthenticationParams Params; - Params.AuthToken = ToSTD(FGenericPlatformHttp::UrlEncode(AuthToken)); - Params.UserEmail = UserEmail.TrimStartAndEnd().IsEmpty() ? Modio::Optional(ToSTD(UserEmail)) : Modio::Optional(); - Params.bUserHasAcceptedTerms = bUserHasAcceptedTerms; - - return Params; -} diff --git a/Source/Modio/Private/Types/ModioCommonTypes.cpp b/Source/Modio/Private/Types/ModioCommonTypes.cpp index b56adbb1..08745ab8 100644 --- a/Source/Modio/Private/Types/ModioCommonTypes.cpp +++ b/Source/Modio/Private/Types/ModioCommonTypes.cpp @@ -1,15 +1,57 @@ -#include "Types/ModioCommonTypes.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Types/ModioCommonTypes.h" +#include "ModioSDK.h" + +#include "Internal/ModioConvert.h" FModioModID::FModioModID() : ModID(INDEX_NONE) {} +uint32 GetTypeHash(FModioModID ModioModId) +{ + return FCrc::MemCrc32(&ModioModId.ModID, sizeof(Modio::ModID)); +} + FModioGameID::FModioGameID() : GameID(INDEX_NONE) {} +FModioGameID FModioGameID::InvalidGameID() +{ + return FModioGameID(Modio::GameID::InvalidGameID()); +} + +uint32 GetTypeHash(FModioGameID ModioGameId) +{ + return FCrc::MemCrc32(&ModioGameId.GameID, sizeof(Modio::GameID)); +} + FModioFileMetadataID::FModioFileMetadataID() : FileMetadataID(INDEX_NONE) {} +uint32 GetTypeHash(FModioFileMetadataID FileMetadataID) +{ + return FCrc::MemCrc32(&FileMetadataID.FileMetadataID, sizeof(Modio::FileMetadataID)); +} + FModioUserID::FModioUserID() : UserID(INDEX_NONE) {} +uint32 GetTypeHash(FModioUserID UserID) +{ + return FCrc::MemCrc32(&UserID.UserID, sizeof(Modio::UserID)); +} + FModioApiKey::FModioApiKey(const FString& InApiKey) : ApiKey(TCHAR_TO_UTF8(*InApiKey)) {} -FModioApiKey::FModioApiKey(const Modio::ApiKey& InApiKey) : ApiKey(TCHAR_TO_UTF8((*InApiKey).c_str())) {} + +FModioApiKey FModioApiKey::InvalidAPIKey() +{ + return FModioApiKey(ToUnreal(*Modio::ApiKey::InvalidAPIKey())); +} FModioEmailAddress::FModioEmailAddress(const FString& InEmailAddress) : EmailAddress(InEmailAddress.TrimStartAndEnd()) {} diff --git a/Source/Modio/Private/Types/ModioErrorCode.cpp b/Source/Modio/Private/Types/ModioErrorCode.cpp index 860a167a..13c468b6 100644 --- a/Source/Modio/Private/Types/ModioErrorCode.cpp +++ b/Source/Modio/Private/Types/ModioErrorCode.cpp @@ -1,9 +1,66 @@ -#include "Types/ModioErrorCode.h" -#include +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ -FModioErrorCode::FModioErrorCode(Modio::ErrorCode ec) : Error(ec) {} +#include "Types/ModioErrorCode.h" +#include "ModioSDK.h" + +FModioErrorCode::FModioErrorCode(Modio::ErrorCode ec) +{ + Error = MakeUnique(ec); +} + + FModioErrorCode::FModioErrorCode() + { + Error = MakeUnique(); + } + + FModioErrorCode::FModioErrorCode(const FModioErrorCode& Other) + { + Error = MakeUnique(Other.GetRawErrorCode()); + } + + FModioErrorCode& FModioErrorCode::operator=(const FModioErrorCode& ec) +{ + Error = MakeUnique(ec.GetRawErrorCode()); + return *this; +} + + FModioErrorCode::~FModioErrorCode() + { + Error.Reset(); + } + +FModioErrorCode::operator bool() const +{ + return Error->value() != 0; +} + +int FModioErrorCode::GetValue() const +{ + return Error->value(); +} + +Modio::ErrorCode FModioErrorCode::GetRawErrorCode() const +{ + return *Error; +} FString FModioErrorCode::GetMessage() const { - return FString(UTF8_TO_TCHAR(Error.message().c_str())); + if (*Error) + { + return FString(UTF8_TO_TCHAR(Error->message().c_str())); + } + else + { + return FString(); + } } + diff --git a/Source/Modio/Private/Types/ModioFilterParamsUImpl.cpp b/Source/Modio/Private/Types/ModioFilterParamsUImpl.cpp new file mode 100644 index 00000000..b1dd23ff --- /dev/null +++ b/Source/Modio/Private/Types/ModioFilterParamsUImpl.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Types/ModioFilterParams.h" +#include "Internal/Convert/FilterParams.h" + +FModioFilterParams& FModioFilterParams::MatchingIDs(const TArray& IDs) +{ + IncludedIDs = IDs; + return *this; +} + +FModioFilterParams& FModioFilterParams::ExcludingIDs(const TArray& IDs) +{ + ExcludedIDs = IDs; + return *this; +} + +FModioFilterParams& FModioFilterParams::SortBy(EModioSortFieldType ByField, EModioSortDirection ByDirection) +{ + SortField = ByField; + Direction = ByDirection; + return *this; +} + +FModioFilterParams& FModioFilterParams::NameContains(const FString& SearchString) +{ + SearchKeywords.Empty(); + SearchKeywords.Add(SearchString); + return *this; +} + +FModioFilterParams& FModioFilterParams::NameContains(const TArray& SearchString) +{ + SearchKeywords = SearchString; + return *this; +} + +FModioFilterParams& FModioFilterParams::MarkedLiveAfter(FDateTime LiveAfter) +{ + DateRangeBegin = LiveAfter; + return *this; +} + +FModioFilterParams& FModioFilterParams::MarkedLiveBefore(FDateTime LiveBefore) +{ + DateRangeEnd = LiveBefore; + return *this; +} + +FModioFilterParams& FModioFilterParams::WithTags(const FString& Tag) +{ + Tags.Empty(); + Tags.Add(Tag); + return *this; +} + +FModioFilterParams& FModioFilterParams::WithTags(const TArray& NewTags) +{ + Tags = NewTags; + return *this; +} + +FModioFilterParams& FModioFilterParams::WithoutTags(const FString& Tag) +{ + ExcludedTags.Empty(); + ExcludedTags.Add(Tag); + return *this; +} + +FModioFilterParams& FModioFilterParams::WithoutTags(const TArray& NewTags) +{ + ExcludedTags = NewTags; + return *this; +} + +FModioFilterParams& FModioFilterParams::IndexedResults(uint64 StartIndex, uint64 ResultCount) +{ + isPaged = false; + Index = StartIndex; + Count = ResultCount; + return *this; +} + +FModioFilterParams& FModioFilterParams::PagedResults(uint64 PageNumber, uint64 PageSize) +{ + isPaged = true; + Index = PageNumber; + Count = PageSize; + return *this; +} + +FString FModioFilterParams::ToString() const +{ + return FString(UTF8_TO_TCHAR(ToModio(*this).ToString().c_str())); +} \ No newline at end of file diff --git a/Source/Modio/Private/Types/ModioImage.cpp b/Source/Modio/Private/Types/ModioImage.cpp index 59fce529..0655ba24 100644 --- a/Source/Modio/Private/Types/ModioImage.cpp +++ b/Source/Modio/Private/Types/ModioImage.cpp @@ -1,4 +1,14 @@ -#include "Types/ModioImage.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Types/ModioImage.h" #include "Async/Async.h" #include "Engine/Engine.h" @@ -13,7 +23,6 @@ #include "Modules/ModuleManager.h" #include "RenderingThread.h" -FModioImage::FModioImage(const Modio::filesystem::path& Path) : ImagePath(ToUnreal(Path)) {} #if !UE_SERVER static TOptional> GetImageData(TSharedPtr ImageWrapper, ERGBFormat InFormat); diff --git a/Source/Modio/Private/Types/ModioMetadata.cpp b/Source/Modio/Private/Types/ModioMetadata.cpp deleted file mode 100644 index 7bbde29e..00000000 --- a/Source/Modio/Private/Types/ModioMetadata.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "Types/ModioMetadata.h" -#include "ModioSDK.h" -#include "Internal/ModioConvert.h" -FModioMetadata::FModioMetadata(const Modio::Metadata& Metadata) - : Key(ToUnreal(Metadata.Key)), - Value(ToUnreal(Metadata.Value)) -{} diff --git a/Source/Modio/Private/Types/ModioModCollectionEntryUImpl.cpp b/Source/Modio/Private/Types/ModioModCollectionEntryUImpl.cpp new file mode 100644 index 00000000..dd345f20 --- /dev/null +++ b/Source/Modio/Private/Types/ModioModCollectionEntryUImpl.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Types/ModioModCollectionEntry.h" +#include "Internal/ModioConvert.h" + +EModioModState FModioModCollectionEntry::GetModState() const +{ + return ModState; +} + +FModioModID FModioModCollectionEntry::GetID() const +{ + return ModID; +} + +const FModioModInfo& FModioModCollectionEntry::GetModProfile() const +{ + return ModProfile; +} + +const FString FModioModCollectionEntry::GetPath() const +{ + if (ModPath) + { + return ModPath.GetValue(); + } + else + { + return {}; + } +} diff --git a/Source/Modio/Private/Types/ModioModInfoList.cpp b/Source/Modio/Private/Types/ModioModInfoList.cpp index 3938195c..9ea87854 100644 --- a/Source/Modio/Private/Types/ModioModInfoList.cpp +++ b/Source/Modio/Private/Types/ModioModInfoList.cpp @@ -1,4 +1,16 @@ -#include "Types/ModioModInfoList.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Types/ModioModInfoList.h" +#include "Internal/Convert/ModInfo.h" +#include "ModioSDK.h" FModioModInfoList::FModioModInfoList(const Modio::ModInfoList& ModInfoList) : FModioPagedResult(ModInfoList), diff --git a/Source/Modio/Private/Types/ModioModManagementEvent.cpp b/Source/Modio/Private/Types/ModioModManagementEvent.cpp deleted file mode 100644 index 8757af63..00000000 --- a/Source/Modio/Private/Types/ModioModManagementEvent.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "Types/ModioModManagementEvent.h" -#include "Internal/ModioConvert.h" - -FModioModManagementEvent::FModioModManagementEvent(const Modio::ModManagementEvent& Event) - : ID(ToUnreal(Event.ID)), - Event(ToUnreal(Event.Event)), - Status(ToUnreal(Event.Status)) -{} diff --git a/Source/Modio/Private/Types/ModioModProgressInfo.cpp b/Source/Modio/Private/Types/ModioModProgressInfo.cpp deleted file mode 100644 index 22008423..00000000 --- a/Source/Modio/Private/Types/ModioModProgressInfo.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "Types/ModioModProgressInfo.h" -#include "Internal/ModioConvert.h" -#include "ModioSDK.h" - -FModioModProgressInfo::FModioModProgressInfo(const Modio::ModProgressInfo& ModProgressInfo) - : TotalDownloadSize(ToUnreal(ModProgressInfo.TotalDownloadSize)), - CurrentlyDownloadedBytes(ToUnreal(ModProgressInfo.CurrentlyDownloadedBytes)), - TotalExtractedSizeOnDisk(ToUnreal(ModProgressInfo.TotalExtractedSizeOnDisk)), - CurrentlyExtractedBytes(ToUnreal(ModProgressInfo.CurrentlyExtractedBytes)), - ID(ToUnreal(ModProgressInfo.ID)) -{} diff --git a/Source/Modio/Private/Types/ModioModTag.cpp b/Source/Modio/Private/Types/ModioModTag.cpp deleted file mode 100644 index 0ffd1066..00000000 --- a/Source/Modio/Private/Types/ModioModTag.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "Types/ModioModTag.h" -#include "Internal/ModioConvert.h" -FModioModTag::FModioModTag(const Modio::ModTag& ModTag) : Tag(ToUnreal(ModTag.Tag)) {} diff --git a/Source/Modio/Private/Types/ModioModTagInfo.cpp b/Source/Modio/Private/Types/ModioModTagInfo.cpp deleted file mode 100644 index ff13a1b7..00000000 --- a/Source/Modio/Private/Types/ModioModTagInfo.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "Types/ModioModTagInfo.h" -#include "Internal/ModioConvert.h" - -FModioModTagInfo::FModioModTagInfo(const Modio::ModTagInfo& ModTagInfo) - : TagGroupName(ToUnreal(ModTagInfo.TagGroupName)), - TagGroupValues(ToUnreal(ModTagInfo.TagGroupValues)), - bAllowMultipleSelection(ToUnreal(ModTagInfo.bAllowMultipleSelection)) - -{} diff --git a/Source/Modio/Private/Types/ModioModTagOptions.cpp b/Source/Modio/Private/Types/ModioModTagOptions.cpp index 6f947551..c7955b39 100644 --- a/Source/Modio/Private/Types/ModioModTagOptions.cpp +++ b/Source/Modio/Private/Types/ModioModTagOptions.cpp @@ -1,4 +1,16 @@ -#include "Types/ModioModTagOptions.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Types/ModioModTagOptions.h" +#include "Internal/Convert/ModTagInfo.h" +#include "ModioSDK.h" FModioModTagOptions::FModioModTagOptions(const Modio::ModTagOptions& ModInfoList) : FModioPagedResult(ModInfoList), diff --git a/Source/Modio/Private/Types/ModioSDKPagedResult.cpp b/Source/Modio/Private/Types/ModioPagedResultUImpl.cpp similarity index 65% rename from Source/Modio/Private/Types/ModioSDKPagedResult.cpp rename to Source/Modio/Private/Types/ModioPagedResultUImpl.cpp index 01d3ebdc..e6b6076c 100644 --- a/Source/Modio/Private/Types/ModioSDKPagedResult.cpp +++ b/Source/Modio/Private/Types/ModioPagedResultUImpl.cpp @@ -1,4 +1,15 @@ -#include "Types/ModioPagedResult.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Types/ModioPagedResult.h" +#include "ModioSDK.h" FModioPagedResult::FModioPagedResult(const Modio::PagedResult& PagedResult) : PageIndex(PagedResult.GetPageIndex()), diff --git a/Source/Modio/Private/Types/ModioReportParamsUImpl.cpp b/Source/Modio/Private/Types/ModioReportParamsUImpl.cpp new file mode 100644 index 00000000..f10a0b3a --- /dev/null +++ b/Source/Modio/Private/Types/ModioReportParamsUImpl.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "ModioSDK.h" +#include "Internal/ModioConvert.h" +#include "Types/ModioCommonTypes.h" +#include "Types/ModioReportParams.h" + +FModioReportParams::FModioReportParams(FModioGameID Game, EModioReportType Type, FString ReportDescription, + TOptional ReporterName, TOptional ReporterContact) + : FModioReportParams(ToModio(Game), FModioReportParams::ResourceType::Game, Type, ReportDescription, ReporterName, + ReporterContact) +{} + +FModioReportParams::FModioReportParams(FModioUserID User, EModioReportType Type, FString ReportDescription, + TOptional ReporterName, TOptional ReporterContact) + : FModioReportParams(ToModio(User), FModioReportParams::ResourceType::User, Type, ReportDescription, ReporterName, + ReporterContact) +{} + +FModioReportParams::FModioReportParams(FModioModID Mod, EModioReportType Type, FString ReportDescription, + TOptional ReporterName, + TOptional ReporterContact) + : FModioReportParams(ToModio(Mod), FModioReportParams::ResourceType::Mod, Type, ReportDescription, ReporterName, + ReporterContact) +{} + +FModioReportParams::FModioReportParams(int64 ResourceID, ResourceType ReportedResourceType, EModioReportType Type, + FString ReportDescription, + TOptional ReporterName, TOptional ReporterContact) + : ReportedResourceType(ReportedResourceType), + ResourceID(ResourceID), + Type(Type), + ReporterName(ReporterName), + ReporterContact(ReporterContact), + ReportDescription(ReportDescription) +{} + +FModioReportParams::FModioReportParams() + : ReportedResourceType(FModioReportParams::ResourceType::Game), + ResourceID(ToModio(FModioGameID::InvalidGameID())), + Type(EModioReportType::Other), + ReporterName(), + ReporterContact(), + ReportDescription("") +{} \ No newline at end of file diff --git a/Source/Modio/Private/Types/ModioSDKFileMetadata.cpp b/Source/Modio/Private/Types/ModioSDKFileMetadata.cpp deleted file mode 100644 index f78197d3..00000000 --- a/Source/Modio/Private/Types/ModioSDKFileMetadata.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "Types/ModioFileMetadata.h" -#include "Internal/ModioConvert.h" - -FModioFileMetadata::FModioFileMetadata(const Modio::FileMetadata& ModInfo) - : MetadataId(ToUnreal(ModInfo.MetadataId)), - ModId(ToUnreal(ModInfo.ModId)), - DateAdded(ToUnrealDateTime(ModInfo.DateAdded)), - CurrentVirusScanStatus(ToUnreal(ModInfo.CurrentVirusScanStatus)), - CurrentVirusStatus(ToUnreal(ModInfo.CurrentVirusStatus)), - Filesize(ToUnreal(ModInfo.Filesize)), - Filename(ToUnreal(ModInfo.Filename)), - Version(ToUnreal(ModInfo.Version)), - Changelog(ToUnreal(ModInfo.Changelog)), - MetadataBlob(FString(ModInfo.MetadataBlob.c_str())) -{} diff --git a/Source/Modio/Private/Types/ModioSDKModCollectionEntry.cpp b/Source/Modio/Private/Types/ModioSDKModCollectionEntry.cpp deleted file mode 100644 index 55275ced..00000000 --- a/Source/Modio/Private/Types/ModioSDKModCollectionEntry.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "Types/ModioModCollectionEntry.h" -#include "Internal/ModioConvert.h" - -FModioModCollectionEntry::FModioModCollectionEntry(Modio::ModCollectionEntry&& ModCollectionEntry) - : ModCollectionEntry(MoveTemp(ModCollectionEntry)) -{} - -EModioModState FModioModCollectionEntry::GetModState() const -{ - return ToUnreal(ModCollectionEntry.GetModState()); -} - -FModioModID FModioModCollectionEntry::GetID() const -{ - return ToUnreal(ModCollectionEntry.GetID()); -} - -const FModioModInfo& FModioModCollectionEntry::GetModProfile() const -{ - if (!CachedModInfo) - { - CachedModInfo = ToUnreal(ModCollectionEntry.GetModProfile()); - } - return CachedModInfo.GetValue(); -} - -const FString& FModioModCollectionEntry::GetPath() const -{ - if (!CachedPath) - { - CachedPath = ToUnreal(ModCollectionEntry.GetPath().string()); - } - return CachedPath.GetValue(); -} diff --git a/Source/Modio/Private/Types/ModioSDKModInfo.cpp b/Source/Modio/Private/Types/ModioSDKModInfo.cpp deleted file mode 100644 index df6297c9..00000000 --- a/Source/Modio/Private/Types/ModioSDKModInfo.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "Types/ModioModInfo.h" -#include "Internal/ModioConvert.h" - -FModioModInfo::FModioModInfo(const Modio::ModInfo& ModInfo) - : ModId(ToUnreal(ModInfo.ModId)), - ProfileName(ToUnreal(ModInfo.ProfileName)), - ProfileSummary(ToUnreal(ModInfo.ProfileSummary)), - ProfileDescription(ToUnreal(ModInfo.ProfileDescription)), - ProfileDescriptionPlaintext(ToUnreal(ModInfo.ProfileDescriptionPlaintext)), - ProfileURL(ToUnreal(ModInfo.ProfileURL)), - ProfileSubmittedBy(ToUnreal(ModInfo.ProfileSubmittedBy)), - ProfileDateAdded(ToUnrealDateTime(ModInfo.ProfileDateAdded)), - ProfileDateUpdated(ToUnrealDateTime(ModInfo.ProfileDateUpdated)), - ProfileDateLive(ToUnrealDateTime(ModInfo.ProfileDateLive)), - ProfileMaturityOption(ToUnreal(ModInfo.ProfileMaturityOption)), - MetadataBlob(ModInfo.MetadataBlob.c_str()), // Don't use ToUnreal as that does UTF8->TCHAR conversion - FileInfo(ToUnreal(ModInfo.FileInfo)), - MetadataKvp(ToUnreal(ModInfo.MetadataKvp)), - Tags(ToUnreal(ModInfo.Tags)), - NumGalleryImages(ToUnreal(ModInfo.NumGalleryImages)), - YoutubeURLs(ToUnreal(ModInfo.YoutubeURLs)), - SketchfabURLs(ToUnreal(ModInfo.SketchfabURLs)), - Stats(ToUnreal(ModInfo.Stats)) -{} diff --git a/Source/Modio/Private/Types/ModioSDKModStats.cpp b/Source/Modio/Private/Types/ModioSDKModStats.cpp deleted file mode 100644 index 851f1a68..00000000 --- a/Source/Modio/Private/Types/ModioSDKModStats.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "Types/ModioModStats.h" -#include "ModioSDK.h" -#include "Internal/ModioConvert.h" - -FModioModStats::FModioModStats(const Modio::ModStats& Stats) - : PopularityRankPosition(ToUnreal(Stats.PopularityRankPosition)), - PopularityRankTotalMods(ToUnreal(Stats.PopularityRankTotalMods)), - DownloadsTotal(ToUnreal(Stats.DownloadsTotal)), - SubscribersTotal(ToUnreal(Stats.SubscribersTotal)), - RatingTotal(ToUnreal(Stats.RatingTotal)), - RatingPositive(ToUnreal(Stats.RatingPositive)), - RatingNegative(ToUnreal(Stats.RatingNegative)), - RatingPercentagePositive(ToUnreal(Stats.RatingPercentagePositive)), - RatingWeightedAggregate(ToUnreal(Stats.RatingWeightedAggregate)), - RatingDisplayText(ToUnreal(Stats.RatingDisplayText)) -{} diff --git a/Source/Modio/Private/Types/ModioSDKURLList.cpp b/Source/Modio/Private/Types/ModioSDKURLList.cpp deleted file mode 100644 index 282edaa4..00000000 --- a/Source/Modio/Private/Types/ModioSDKURLList.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "Types/ModioURLList.h" -#include "Internal/ModioConvert.h" - -FModioYoutubeURLList::FModioYoutubeURLList(const Modio::YoutubeURLList& URLList) - : FModioList(ToUnrealList(URLList)) -{} - -FModioSketchfabURLList::FModioSketchfabURLList(const Modio::SketchfabURLList& URLList) - : FModioList(ToUnrealList(URLList)) -{} diff --git a/Source/Modio/Private/Types/ModioTerms.cpp b/Source/Modio/Private/Types/ModioTerms.cpp deleted file mode 100644 index 9179aa48..00000000 --- a/Source/Modio/Private/Types/ModioTerms.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "Types/ModioTerms.h" - -#include "ModioSDK.h" -#include "Internal/ModioConvert.h" - -FModioLink::FModioLink(const Modio::Terms::Link& Link) : - Text(ToUnreal(Link.Text)), - URL(ToUnreal(Link.URL)), - bRequired(ToUnreal(Link.bRequired)) -{ -} - -FModioTerms::FModioTerms(const Modio::Terms& Terms) : - AgreeButtonText(ToUnreal(Terms.Buttons.AgreeText)), - DisagreeButtonText(ToUnreal(Terms.Buttons.DisagreeText)), - WebsiteLink(ToUnreal(Terms.Links.Website)), - TermsLink(ToUnreal(Terms.Links.Terms)), - PrivacyLink(ToUnreal(Terms.Links.Privacy)), - ManageLink(ToUnreal(Terms.Links.Manage)), - TermsText(ToUnreal(Terms.TermsText)) -{ -} - -FModioOptionalTerms::FModioOptionalTerms(TOptional&& ModTagOptions) : - Internal(MoveTemp(ModTagOptions)) -{ -} \ No newline at end of file diff --git a/Source/Modio/Private/Types/ModioURLListUImpl.cpp b/Source/Modio/Private/Types/ModioURLListUImpl.cpp new file mode 100644 index 00000000..6b421127 --- /dev/null +++ b/Source/Modio/Private/Types/ModioURLListUImpl.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "Types/ModioURLList.h" +#include "ModioSDK.h" +#include "Internal/ModioConvert.h" + +FModioYoutubeURLList::FModioYoutubeURLList(const Modio::YoutubeURLList& URLList) + : FModioList(ToUnrealList(URLList)) +{} + +FModioSketchfabURLList::FModioSketchfabURLList(const Modio::SketchfabURLList& URLList) + : FModioList(ToUnrealList(URLList)) +{} diff --git a/Source/Modio/Private/Types/ModioUser.cpp b/Source/Modio/Private/Types/ModioUser.cpp deleted file mode 100644 index 860f4625..00000000 --- a/Source/Modio/Private/Types/ModioUser.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "Types/ModioUser.h" -#include "Internal/ModioConvert.h" - -FModioUser::FModioUser(const Modio::User& User) - : UserId(ToUnreal(User.UserId)), - Username(ToUnreal(User.Username)), - DateOnline(ToUnreal(User.DateOnline)), - ProfileUrl(ToUnreal(User.ProfileUrl)) -{} - -FModioOptionalUser::FModioOptionalUser(TOptional&& ModInfoList) : Internal(ModInfoList) {} diff --git a/Source/Modio/Private/UI/ModioExampleLibrary.cpp b/Source/Modio/Private/UI/ModioExampleLibrary.cpp index 29adf6ba..0ce4d151 100644 --- a/Source/Modio/Private/UI/ModioExampleLibrary.cpp +++ b/Source/Modio/Private/UI/ModioExampleLibrary.cpp @@ -1,4 +1,14 @@ -#include "UI/ModioExampleLibrary.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "UI/ModioExampleLibrary.h" #include "ModioSubsystem.h" #include "Async/Async.h" #include "Engine/Engine.h" diff --git a/Source/Modio/Private/UI/ModioPopupContainer.cpp b/Source/Modio/Private/UI/ModioPopupContainer.cpp index 23db28a8..baf8f3e8 100644 --- a/Source/Modio/Private/UI/ModioPopupContainer.cpp +++ b/Source/Modio/Private/UI/ModioPopupContainer.cpp @@ -1,4 +1,14 @@ -#include "UI/ModioPopupContainer.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#include "UI/ModioPopupContainer.h" #include "UI/ModioPopupBase.h" UModioPopupContainer::UModioPopupContainer(const FObjectInitializer& ObjectInitializer) : diff --git a/Source/Modio/Public/Internal/ModioConvert.h b/Source/Modio/Public/Internal/ModioConvert.h deleted file mode 100644 index e8dd8e44..00000000 --- a/Source/Modio/Public/Internal/ModioConvert.h +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "Containers/StringConv.h" -#include "Containers/UnrealString.h" -#include "Misc/DateTime.h" -#include "ModioSDK.h" - -FORCEINLINE std::string ToSTD(const FString& String); -FORCEINLINE std::vector ToSTD(const TArray& StringArray); -FORCEINLINE std::chrono::system_clock::time_point ToSTD(FDateTime Time); - -// @todo: Make a ToModio that handles TOptional through templates - -FORCEINLINE int64 ToUnreal(std::int64_t Value); -FORCEINLINE uint8 ToUnreal(std::uint8_t Value); -FORCEINLINE double ToUnreal(double Value); -FORCEINLINE bool ToUnreal(bool Value); -FORCEINLINE uint64 ToUnreal(std::size_t Value); -FORCEINLINE FString ToUnreal(const std::string& String); -FORCEINLINE FString ToUnreal(const Modio::filesystem::path& Path); -FORCEINLINE FDateTime ToUnrealDateTime(std::int64_t UnixTimestamp); - -template -FORCEINLINE TArray ToUnreal(std::vector&& OriginalArray); - -template -FORCEINLINE TArray ToUnreal(const std::vector& OriginalArray); - -#pragma region Implementation - -// @todo: Rename this to ToModio as it doesn't matter that it's the part of STD of modio -std::string ToSTD(const FString& String) -{ - return std::string(TCHAR_TO_UTF8(*String)); -} - -// @todo: Rename this to ToModio as it doesn't matter that it's the part of STD of modio -std::vector ToSTD(const TArray& StringArray) -{ - std::vector Result; - Result.reserve(StringArray.Num()); - for (const FString& It : StringArray) - { - Result.emplace_back(TCHAR_TO_UTF8(*It)); - } - return Result; -} - -// @todo: Rename this to ToModio as it doesn't matter that it's the part of STD of modio -std::chrono::system_clock::time_point ToSTD(FDateTime Time) -{ - // @todonow: Verify that this becomes correct by printf debugging - return std::chrono::system_clock::time_point(std::chrono::system_clock::duration(Time.ToUnixTimestamp())); -} - -int64 ToUnreal(std::int64_t Value) -{ - return Value; -} - -bool ToUnreal(bool Value) -{ - return Value; -} - -uint8 ToUnreal(std::uint8_t Value) -{ - return Value; -} - -double ToUnreal(double Value) -{ - return Value; -} - -uint64 ToUnreal(std::size_t Value) -{ - static_assert(sizeof(std::size_t) == sizeof(uint64), "size_t is not 64-bits wide. Are you in x64 configuration?"); - return Value; -} - -FString ToUnreal(const std::string& String) -{ - return UTF8_TO_TCHAR(String.c_str()); -} - -FString ToUnreal(const Modio::filesystem::path& Path) -{ - return UTF8_TO_TCHAR(Path.generic_u8string().c_str()); -} - -FDateTime FORCEINLINE ToUnrealDateTime(std::int64_t UnixTimestamp) -{ - return FDateTime::FromUnixTimestamp(UnixTimestamp); -} - -template -TArray ToUnreal(std::vector&& OriginalArray) -{ - TArray Result; - - Result.Reserve(OriginalArray.size()); - for (auto& It : OriginalArray) - { - Result.Emplace(ToUnreal(MoveTemp(It))); - } - - return Result; -} - -template -TArray ToUnreal(const std::vector& OriginalArray) -{ - TArray Result; - - Result.Reserve(OriginalArray.size()); - for (const auto& It : OriginalArray) - { - Result.Emplace(ToUnreal(It)); - } - - return Result; -} - -#pragma endregion diff --git a/Source/Modio/Public/Internal/ModioPrivateDefines.h b/Source/Modio/Public/Internal/ModioPrivateDefines.h deleted file mode 100644 index a63568b6..00000000 --- a/Source/Modio/Public/Internal/ModioPrivateDefines.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -// This makes missing a value in the switch statement a fatal error, is disabled after our conversion routines -#define MODIO_BEGIN_CONVERT_SWITCHES \ - __pragma(warning(push)) \ - __pragma(warning(error : 4062)) - -#define MODIO_END_CONVERT_SWITCHES \ - __pragma(warning(pop)) diff --git a/Source/Modio/Public/Libraries/ModioCommonTypesLibrary.h b/Source/Modio/Public/Libraries/ModioCommonTypesLibrary.h index 7d1c0ad9..d67ab985 100644 --- a/Source/Modio/Public/Libraries/ModioCommonTypesLibrary.h +++ b/Source/Modio/Public/Libraries/ModioCommonTypesLibrary.h @@ -1,8 +1,19 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "Types/ModioCommonTypes.h" #include "Types/ModioInitializeOptions.h" +#include "Types/ModioAuthenticationParams.h" // clang-format off #include "ModioCommonTypesLibrary.generated.h" @@ -38,7 +49,7 @@ class UModioCommonTypesLibrary : public UBlueprintFunctionLibrary * @return The constructed FModioAuthenticationParams object for use with <> */ UFUNCTION(BlueprintPure, category = "mod.io|Utilities", meta = (NativeMakeFunc)) - static struct FModioAuthenticationParams MakeAuthParams(const FString AuthToken, const FString EmailAddress, const bool bHasAcceptedTOS); + static FModioAuthenticationParams MakeAuthParams(const FString AuthToken, const FString EmailAddress, const bool bHasAcceptedTOS); /** * @brief Create a ApiKey id from a string, should only be used in conjunction with InitializeAsync diff --git a/Source/Modio/Public/Libraries/ModioErrorCodeLibrary.h b/Source/Modio/Public/Libraries/ModioErrorCodeLibrary.h index be132170..d4119c56 100644 --- a/Source/Modio/Public/Libraries/ModioErrorCodeLibrary.h +++ b/Source/Modio/Public/Libraries/ModioErrorCodeLibrary.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "Types/ModioErrorCode.h" diff --git a/Source/Modio/Public/Libraries/ModioErrorConditionLibrary.h b/Source/Modio/Public/Libraries/ModioErrorConditionLibrary.h new file mode 100644 index 00000000..4610f8c5 --- /dev/null +++ b/Source/Modio/Public/Libraries/ModioErrorConditionLibrary.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Types/ModioErrorCode.h" +#include "ModioErrorCondition.h" + +#include "ModioErrorConditionLibrary.generated.h" + + +UCLASS() +class UModioErrorConditionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + /** + * @brief Checks if the passed-in ErrorCode matches the specified error condition + * @param ErrorCode The code to check + * @param Condition The error condition to check against + * @return true if the code matches the condition + */ + UFUNCTION(BlueprintCallable, Category = "mod.io|Error Handling") + static bool ErrorCodeMatches(FModioErrorCode ErrorCode, EModioErrorCondition Condition); +}; \ No newline at end of file diff --git a/Source/Modio/Public/Libraries/ModioFilterParamsLibrary.h b/Source/Modio/Public/Libraries/ModioFilterParamsLibrary.h index 696d4aa1..4bc767bc 100644 --- a/Source/Modio/Public/Libraries/ModioFilterParamsLibrary.h +++ b/Source/Modio/Public/Libraries/ModioFilterParamsLibrary.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "Kismet/BlueprintFunctionLibrary.h" diff --git a/Source/Modio/Public/Libraries/ModioImageLibrary.h b/Source/Modio/Public/Libraries/ModioImageLibrary.h index d024f60d..14091e4b 100644 --- a/Source/Modio/Public/Libraries/ModioImageLibrary.h +++ b/Source/Modio/Public/Libraries/ModioImageLibrary.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "Types/ModioCommonTypes.h" #include "Types/ModioImage.h" diff --git a/Source/Modio/Public/Libraries/ModioModCollectionLibrary.h b/Source/Modio/Public/Libraries/ModioModCollectionLibrary.h index 64049174..ea8c5e6d 100644 --- a/Source/Modio/Public/Libraries/ModioModCollectionLibrary.h +++ b/Source/Modio/Public/Libraries/ModioModCollectionLibrary.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "Types/ModioModCollectionEntry.h" @@ -30,5 +40,5 @@ class UModioModCollectionLibrary : public UBlueprintFunctionLibrary * xref:GetModState[] before trying to load files in this location **/ UFUNCTION(BlueprintPure, Category = "mod.io|Mods") - static const FString& GetPath(const FModioModCollectionEntry& Entry); + static const FString GetPath(const FModioModCollectionEntry& Entry); }; diff --git a/Source/Modio/Public/Libraries/ModioModInfoListLibrary.h b/Source/Modio/Public/Libraries/ModioModInfoListLibrary.h index 74f72cb7..bbebca2f 100644 --- a/Source/Modio/Public/Libraries/ModioModInfoListLibrary.h +++ b/Source/Modio/Public/Libraries/ModioModInfoListLibrary.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "Types/ModioModInfoList.h" diff --git a/Source/Modio/Public/Libraries/ModioModTagOptionsLibrary.h b/Source/Modio/Public/Libraries/ModioModTagOptionsLibrary.h index c3a0ab1b..18018164 100644 --- a/Source/Modio/Public/Libraries/ModioModTagOptionsLibrary.h +++ b/Source/Modio/Public/Libraries/ModioModTagOptionsLibrary.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "Types/ModioModTagOptions.h" diff --git a/Source/Modio/Public/Libraries/ModioOptionalLibrary.h b/Source/Modio/Public/Libraries/ModioOptionalLibrary.h index 5e9c6bdd..f514d6dd 100644 --- a/Source/Modio/Public/Libraries/ModioOptionalLibrary.h +++ b/Source/Modio/Public/Libraries/ModioOptionalLibrary.h @@ -1,7 +1,18 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "Types/ModioModInfo.h" +#include "Types/ModioModInfoList.h" #include "Types/ModioModProgressInfo.h" #include "Types/ModioModTagOptions.h" #include "Types/ModioTerms.h" diff --git a/Source/Modio/Public/Libraries/ModioReportLibrary.h b/Source/Modio/Public/Libraries/ModioReportLibrary.h new file mode 100644 index 00000000..32683c70 --- /dev/null +++ b/Source/Modio/Public/Libraries/ModioReportLibrary.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Misc/Optional.h" +#include "Types/ModioReportParams.h" +#include "Types/ModioCommonTypes.h" + +#include "ModioReportLibrary.generated.h" + + +/** + * + */ +UCLASS() +class MODIO_API UModioReportLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + /// @brief Creates a content report for a game. + /// @param Game The ID of the game being reported + /// @param Type The nature of the content report + /// @param ReportDescription A description of why the content is being reported + /// @param ReporterName Name of the submitting user. Recommended for DMCA reports, but may be empty + /// @param ReporterContact Contact details of the submitting user. Recommended for DMCA reports, but may be + /// empty + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "mod.io|Content Reporting") + static FModioReportParams MakeReportForGame(FModioGameID Game, EModioReportType Type, + FString ReportDescription, FString ReporterName, + FString ReporterContact); + + /// @docpublic + /// @brief Creates a content report for a game. + /// @param User The ID of the User being reported + /// @param Type The nature of the content report + /// @param ReportDescription A description of why the content is being reported + /// @param ReporterName Name of the submitting user. Recommended for DMCA reports, but may be empty + /// @param ReporterContact Contact details of the submitting user. Recommended for DMCA reports, but may be + /// empty + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "mod.io|Content Reporting") + static FModioReportParams MakeReportForUser(FModioUserID User, EModioReportType Type, + FString ReportDescription, FString ReporterName, + FString ReporterContact); + + /// @docpublic + /// @brief Creates a content report for a game. + /// @param Mod The ID of the content being reported + /// @param Type The nature of the content report + /// @param ReportDescription A description of why the content is being reported + /// @param ReporterName Name of the submitting user. Recommended for DMCA reports, but may be empty + /// @param ReporterContact Contact details of the submitting user. Recommended for DMCA reports, but may be + /// empty + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "mod.io|Content Reporting") + static FModioReportParams MakeReportForMod(FModioModID Mod, EModioReportType Type, FString ReportDescription, + FString ReporterName, FString ReporterContact); +}; diff --git a/Source/Modio/Public/Libraries/ModioSDKLibrary.h b/Source/Modio/Public/Libraries/ModioSDKLibrary.h index 531d0dbb..89a639c7 100644 --- a/Source/Modio/Public/Libraries/ModioSDKLibrary.h +++ b/Source/Modio/Public/Libraries/ModioSDKLibrary.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "Types/ModioInitializeOptions.h" diff --git a/Source/Modio/Public/Modio.h b/Source/Modio/Public/Modio.h index c425ecdc..fce5b020 100644 --- a/Source/Modio/Public/Modio.h +++ b/Source/Modio/Public/Modio.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #pragma once diff --git a/Source/Modio/Public/ModioImageCache.h b/Source/Modio/Public/ModioImageCache.h index 040d4e5b..876bd682 100644 --- a/Source/Modio/Public/ModioImageCache.h +++ b/Source/Modio/Public/ModioImageCache.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "UObject/WeakObjectPtr.h" #include "Types/ModioImageState.h" diff --git a/Source/Modio/Public/ModioSDK.h b/Source/Modio/Public/ModioSDK.h index 1af10d13..c0dfd170 100644 --- a/Source/Modio/Public/ModioSDK.h +++ b/Source/Modio/Public/ModioSDK.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once //#if PLATFORM_WINDOWS @@ -10,19 +20,6 @@ #define MODIO_PLATFORM_UNREAL 1 -// Ensure that we can run asio without any exceptions -namespace asio -{ - namespace detail - { - template - void throw_exception(const Exception& e) - { - checkf(false, TEXT("Asio threw a exception with the message %s"), *e.what()); - } - } // namespace detail -} // namespace asio - #pragma push_macro("check") #undef check diff --git a/Source/Modio/Classes/ModioSettings.h b/Source/Modio/Public/ModioSettings.h similarity index 82% rename from Source/Modio/Classes/ModioSettings.h rename to Source/Modio/Public/ModioSettings.h index ecd3bd92..1d6b7a43 100644 --- a/Source/Modio/Classes/ModioSettings.h +++ b/Source/Modio/Public/ModioSettings.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Types/ModioCommonTypes.h" diff --git a/Source/Modio/Public/ModioSubsystem.h b/Source/Modio/Public/ModioSubsystem.h index 34e53ceb..003e09f3 100644 --- a/Source/Modio/Public/ModioSubsystem.h +++ b/Source/Modio/Public/ModioSubsystem.h @@ -1,7 +1,16 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "ModioImageCache.h" -#include "ModioSDK.h" #include "Subsystems/EngineSubsystem.h" #include "Types/ModioAuthenticationParams.h" #include "Types/ModioCommonTypes.h" @@ -15,6 +24,8 @@ #include "Types/ModioModManagementEvent.h" #include "Types/ModioModProgressInfo.h" #include "Types/ModioModTagOptions.h" +#include "Types/ModioRating.h" +#include "Types/ModioReportParams.h" #include "Types/ModioTerms.h" #include "Types/ModioUser.h" #include "Types/ModioValidationError.h" @@ -386,6 +397,36 @@ class UModioSubsystem : public UEngineSubsystem **/ MODIO_API void GetUserMediaAsync(EModioAvatarSize AvatarSize, FOnGetMediaDelegateFast Callback); + + /** + * @brief Submits a rating for a mod on behalf of the current user. Submit a neutral rating to effectively clear a + * rating already submitted by a user. Submitting other values will overwrite any existing rating submitted by this + * user. + * @param Mod The mod the user is rating + * @param Rating The rating the user wishes to submit + * @requires initialized-sdk + * @requires authenticated-user + * @requires no-rate-limiting + * @errorcategory NetworkError|Couldn't connect to mod.io servers + * @error GenericError::SDKNotInitialized|SDK not initialized + * @errorcategory EntityNotFoundError|Specified mod could not be found + * @error UserDataError::InvalidUser|No authenticated user + */ + MODIO_API void SubmitModRatingAsync(FModioModID Mod, EModioRating Rating, FOnErrorOnlyDelegateFast Callback); + + /** + * @brief Sends a content report to mod.io. When using this function, please inform your users that if they provide + * their contact name or details in the Report parameter, that those may be shared with the person responsible for + * the content being reported. For more information on what data in a report will be shared with whom, please see + * link:https://mod.io/report/widget[our website's report form] for more information. + * @param Report Information about the content being reported and a description of the report. + * @param Callback Callback providing a status code to indicate successful submission of the report. + * @requires initialized-sdk + * @errorcategory NetworkError|Couldn't Connect to mod.io servers + * @errorcategory InvalidArgsError|Required information in the report did not pass validation + */ + MODIO_API void ReportContentAsync(FModioReportParams Report, FOnErrorOnlyDelegateFast Callback); + /** Get our image cache */ struct FModioImageCache& GetImageCache() const; @@ -680,5 +721,37 @@ class UModioSubsystem : public UEngineSubsystem **/ UFUNCTION(BlueprintCallable, DisplayName = "GetUserMediaAsync (Avatar)", Category = "mod.io|User") MODIO_API void K2_GetUserMediaAvatarAsync(EModioAvatarSize AvatarSize, FOnGetMediaDelegate Callback); + + /** + * @brief Submits a rating for a mod on behalf of the current user. Submit a neutral rating to effectively clear a + * rating already submitted by a user. Submitting other values will overwrite any existing rating submitted by this + * user. + * @param Mod The mod the user is rating + * @param Rating The rating the user wishes to submit + * @requires initialized-sdk + * @requires authenticated-user + * @requires no-rate-limiting + * @errorcategory NetworkError|Couldn't connect to mod.io servers + * @error GenericError::SDKNotInitialized|SDK not initialized + * @errorcategory EntityNotFoundError|Specified mod could not be found + * @error UserDataError::InvalidUser|No authenticated user + */ + UFUNCTION(BlueprintCallable, DisplayName = "SubmitModRatingAsync", Category = "mod.io|Mods") + MODIO_API void K2_SubmitModRatingAsync(FModioModID Mod, EModioRating Rating, FOnErrorOnlyDelegate Callback); + + /** + * @brief Sends a content report to mod.io. When using this function, please inform your users that if they provide + * their contact name or details in the Report parameter, that those may be shared with the person responsible for + * the content being reported. For more information on what data in a report will be shared with whom, please see + * link:https://mod.io/report/widget[our website's report form] for more information. + * @param Report Information about the content being reported and a description of the report. + * @param Callback Callback providing a status code to indicate successful submission of the report. + * @requires initialized-sdk + * @errorcategory NetworkError|Couldn't Connect to mod.io servers + * @errorcategory InvalidArgsError|Required information in the report did not pass validation + */ + UFUNCTION(BlueprintCallable, DisplayName = "ReportContentAsync", Category = "mod.io") + MODIO_API void K2_ReportContentAsync(FModioReportParams Report, FOnErrorOnlyDelegate Callback); + #pragma endregion }; diff --git a/Source/Modio/Public/Types/ModioAuthenticationParams.h b/Source/Modio/Public/Types/ModioAuthenticationParams.h new file mode 100644 index 00000000..b24485b9 --- /dev/null +++ b/Source/Modio/Public/Types/ModioAuthenticationParams.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "Containers/UnrealString.h" + +#include "ModioAuthenticationParams.generated.h" + +/** @brief Simple struct to encapsulate data passed to external authentication systems */ +UENUM(BlueprintType) +enum class EModioAuthenticationProvider : uint8 +{ + XboxLive, + Steam, + GoG, + Itch, + Switch, + Discord +}; + +/** @brief Simple struct to encapsulate data passed to external authentication systems */ +USTRUCT(BlueprintType) +struct FModioAuthenticationParams +{ + GENERATED_BODY(); + UPROPERTY(BlueprintReadWrite, EditInstanceOnly) + FString AuthToken; + UPROPERTY(BlueprintReadWrite, EditInstanceOnly) + FString UserEmail; + UPROPERTY(BlueprintReadWrite, EditInstanceOnly) + bool bUserHasAcceptedTerms = false; +}; diff --git a/Source/Modio/Public/Types/ModioCommonTypes.h b/Source/Modio/Public/Types/ModioCommonTypes.h new file mode 100644 index 00000000..f5e01f2a --- /dev/null +++ b/Source/Modio/Public/Types/ModioCommonTypes.h @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Misc/Crc.h" + +// clang-format off +#include "ModioCommonTypes.generated.h" +// clang-format on + +//Forward decls +namespace Modio +{ + struct ModID; + struct GameID; + struct FileMetadataID; + struct UserID; +} + + +/** @brief Enum representing what environment your game is deployed in */ +UENUM(BlueprintType) +enum class EModioEnvironment : uint8 +{ + // Test/Private environment + Test, + // Live/Public environment + Live +}; + +/** @brief Enum representing the store or service your game is being distributed through */ +UENUM(BlueprintType) +enum class EModioPortal : uint8 +{ + None, + Apple, + EpicGamesStore, + GOG, + Google, + Itchio, + Nintendo, + PSN, + Steam, + XboxLive +}; + +/** @brief Enum representing mod logo sizes */ +UENUM(BlueprintType) +enum class EModioLogoSize : uint8 +{ + // Original Size + Original, + // 320x180px + Thumb320, + // 640x360px + Thumb640, + // 1280x720px + Thumb1280 +}; + +/** @brief Enum representing avatar image sizes */ +UENUM(BlueprintType) +enum class EModioAvatarSize : uint8 +{ + // Original Size + Original, + // 50x50px Thumbnail + Thumb50, + // 100x100px Thumbnail + Thumb100 +}; + +/** */ +UENUM(BlueprintType) +enum class EModioGallerySize : uint8 +{ + // Original Size + Original, + // 320x180px Thumbnail + Thumb320 +}; + +/** @brief Degree of severity for the log output */ +UENUM() +enum class EModioLogLevel : uint8 +{ + // Detailed low-level debugging output. Not intended for general use + Trace = 0, + // Informational output containing status messages + Info = 1, + // Warnings about incorrect plugin usage, timeouts + Warning = 2, + // Only errors + Error = 3 +}; + +/** @brief Enum representing the languages mod.io support responses in */ +UENUM(BlueprintType) +enum class EModioLanguage : uint8 +{ + English, + Bulgarian, + French, + German, + Italian, + Polish, + Portuguese, + Hungarian, + Japanese, + Korean, + Russian, + Spanish, + Thai, + ChineseSimplified, + ChineseTraditional +}; + +/** @brief Strong type for Mod IDs */ +USTRUCT(BlueprintType) +struct MODIO_API FModioModID +{ + GENERATED_BODY() + + FModioModID(); + constexpr explicit FModioModID(int64 InModId) : ModID(InModId) {} + + friend uint32 GetTypeHash(FModioModID ModioModId); + + friend bool operator==(FModioModID A, FModioModID B) + { + return A.ModID == B.ModID; + } + + friend bool operator!=(FModioModID A, FModioModID B) + { + return A.ModID != B.ModID; + } + + friend bool operator<(FModioModID A, FModioModID B) + { + return A.ModID < B.ModID; + } + + friend bool operator>(FModioModID A, FModioModID B) + { + return A.ModID > B.ModID; + } + + FString ToString() const + { + if (ModID < 0) + { + return TEXT("InvalidModID"); + } + return FString::Printf(TEXT("%lld"), ModID); + } + +private: + friend struct Modio::ModID ToModio(const FModioModID& In); + int64 ModID; +}; + +template<> +struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum + { + WithIdenticalViaEquality = true + }; +}; + +/** @brief Strong type for Game IDs */ +USTRUCT(BlueprintType, meta = (HasNativeMake = "Modio.ModioCommonTypesLibrary.MakeGameId")) +struct MODIO_API FModioGameID +{ + GENERATED_BODY() + + FModioGameID(); + constexpr explicit FModioGameID(int64 InGameId) : GameID(InGameId) {} + + friend uint32 GetTypeHash(FModioGameID ModioGameId); + + friend bool operator==(FModioGameID A, FModioGameID B) + { + return A.GameID == B.GameID; + } + + FString ToString() const + { + if (GameID < 0) + { + return TEXT("InvalidGameID"); + } + return FString::Printf(TEXT("%lld"), GameID); + } + + static FModioGameID InvalidGameID(); + +private: + friend struct Modio::GameID ToModio(const FModioGameID& In); + int64 GameID; +}; + +template<> +struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum + { + WithIdenticalViaEquality = true + }; +}; + +/** @brief Strong type for File Metadata IDs */ +USTRUCT(BlueprintType) +struct MODIO_API FModioFileMetadataID +{ + GENERATED_BODY() + + FModioFileMetadataID(); + constexpr explicit FModioFileMetadataID(int64 InFileMetadataId) : FileMetadataID(InFileMetadataId) {} + + friend uint32 GetTypeHash(FModioFileMetadataID FileMetadataID); + + friend bool operator==(FModioFileMetadataID A, FModioFileMetadataID B) + { + return A.FileMetadataID == B.FileMetadataID; + } + + FString ToString() const + { + if (FileMetadataID < 0) + { + return TEXT("InvalidFileMetadataID"); + } + return FString::Printf(TEXT("%lld"), FileMetadataID); + } + +private: + friend struct Modio::FileMetadataID ToModio(const FModioFileMetadataID& In); + int64 FileMetadataID; +}; + +template<> +struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum + { + WithIdenticalViaEquality = true + }; +}; + +/** @brief Strong type for User IDs */ +USTRUCT(BlueprintType) +struct MODIO_API FModioUserID +{ + GENERATED_BODY() + + FModioUserID(); + + constexpr explicit FModioUserID(int64 InUserID) : UserID(InUserID) {} + + friend uint32 GetTypeHash(FModioUserID UserID); + + friend bool operator==(FModioUserID A, FModioUserID B) + { + return A.UserID == B.UserID; + } + + FString ToString() const + { + if (UserID < 0) + { + return TEXT("InvalidUserID"); + } + return FString::Printf(TEXT("%lld"), UserID); + } + +private: + friend struct Modio::UserID ToModio(const FModioUserID& In); + int64 UserID; +}; + +template<> +struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum + { + WithIdenticalViaEquality = true + }; +}; + +/** @brief Strong type for Api Keys */ +USTRUCT(BlueprintType, meta = (HasNativeMake = "Modio.ModioCommonTypesLibrary.MakeApiKey")) +struct MODIO_API FModioApiKey +{ + GENERATED_BODY() + + FModioApiKey() = default; + explicit FModioApiKey(const FString& InApiKey); + + const FString& ToString() const + { + // Put in the function instead of default constructor to avoid having to allocate memory for + // each empty instance + if (ApiKey.Len() == 0) + { + static FString Invalid(TEXT("InvalidApiKey")); + return Invalid; + } + return ApiKey; + } + + static FModioApiKey InvalidAPIKey(); + +private: + FString ApiKey; +}; + +/** @brief Strong type for email address */ +USTRUCT(BlueprintType) +struct MODIO_API FModioEmailAddress +{ + GENERATED_BODY() + + FModioEmailAddress() = default; + FModioEmailAddress(const FString& InEmailAddress); + + const FString& ToString() const + { + // Put in the function instead of default constructor to avoid having to allocate memory for + // each empty instance + if (EmailAddress.Len() == 0) + { + static FString Invalid(TEXT("InvalidEmailAddress")); + return Invalid; + } + return EmailAddress; + } + +private: + FString EmailAddress; +}; + +/** @brief Strong type for email auth code */ +USTRUCT(BlueprintType) +struct MODIO_API FModioEmailAuthCode +{ + GENERATED_BODY() + + FModioEmailAuthCode() = default; + FModioEmailAuthCode(const FString& InEmailAuthCode); + + const FString& ToString() const + { + // Put in the function instead of default constructor to avoid having to allocate memory for + // each empty instance + if (EmailAuthCode.Len() == 0) + { + static FString Invalid(TEXT("InvalidEmailAuthCode")); + return Invalid; + } + return EmailAuthCode; + } + +private: + FString EmailAuthCode; +}; + +#pragma endregion diff --git a/Source/Modio/Public/Types/ModioErrorCode.h b/Source/Modio/Public/Types/ModioErrorCode.h new file mode 100644 index 00000000..b07e95e8 --- /dev/null +++ b/Source/Modio/Public/Types/ModioErrorCode.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once +#include "Templates/UniquePtr.h" + +// clang-format off +#include "ModioErrorCode.generated.h" +// clang-format on + +namespace Modio +{ + class ErrorCode; +} + +/** @brief wrapper around Modio::ErrorCode */ +USTRUCT(BlueprintType) +struct MODIO_API FModioErrorCode +{ + GENERATED_BODY() + + // This is to allow delegates to pass FModioErrorCode code, but I would have preferred it to be deleted + FModioErrorCode(); + FModioErrorCode(const FModioErrorCode& Other); + FModioErrorCode(Modio::ErrorCode ec); + FModioErrorCode& operator=(const FModioErrorCode& ec); + ~FModioErrorCode(); + /** return true if this error code is a error */ + operator bool() const; + + /** Get the error code */ + int GetValue() const; + Modio::ErrorCode GetRawErrorCode() const; + + /** Get a human readable message from the error code */ + FString GetMessage() const; + +private: + TUniquePtr Error; +}; + diff --git a/Source/Modio/Classes/Types/ModioFileMetadata.h b/Source/Modio/Public/Types/ModioFileMetadata.h similarity index 57% rename from Source/Modio/Classes/Types/ModioFileMetadata.h rename to Source/Modio/Public/Types/ModioFileMetadata.h index 7cdfcb24..80b01163 100644 --- a/Source/Modio/Classes/Types/ModioFileMetadata.h +++ b/Source/Modio/Public/Types/ModioFileMetadata.h @@ -1,7 +1,15 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once -#include "Internal/ModioPrivateDefines.h" -#include "ModioSDK.h" #include "Types/ModioCommonTypes.h" // clang-format off #include "ModioFileMetadata.generated.h" @@ -33,9 +41,6 @@ struct MODIO_API FModioFileMetadata { GENERATED_BODY() - FModioFileMetadata() = default; - FModioFileMetadata(const Modio::FileMetadata& FileMetadata); - /** @brief Unique modfile id. */ UPROPERTY(BlueprintReadOnly, Category = "FileMetadata") FModioFileMetadataID MetadataId; @@ -79,46 +84,3 @@ struct MODIO_API FModioFileMetadata UPROPERTY(BlueprintReadOnly, Category = "FileMetadata|Metadata") FString MetadataBlob; }; - -#pragma region ToUnreal implementation -FORCEINLINE FModioFileMetadata ToUnreal(const Modio::FileMetadata& FileMetadata) -{ - return FModioFileMetadata(FileMetadata); -} - -MODIO_BEGIN_CONVERT_SWITCHES -FORCEINLINE EModioVirusScanStatus ToUnreal(Modio::FileMetadata::VirusScanStatus VirusScanStatus) -{ - switch (VirusScanStatus) - { - case Modio::FileMetadata::VirusScanStatus::NotScanned: - return EModioVirusScanStatus::NotScanned; - case Modio::FileMetadata::VirusScanStatus::ScanComplete: - return EModioVirusScanStatus::ScanComplete; - case Modio::FileMetadata::VirusScanStatus::InProgress: - return EModioVirusScanStatus::InProgress; - case Modio::FileMetadata::VirusScanStatus::TooLargeToScan: - return EModioVirusScanStatus::TooLargeToScan; - case Modio::FileMetadata::VirusScanStatus::FileNotFound: - return EModioVirusScanStatus::FileNotFound; - case Modio::FileMetadata::VirusScanStatus::ErrorScanning: - return EModioVirusScanStatus::ErrorScanning; - } - - return EModioVirusScanStatus::NotScanned; -} - -FORCEINLINE EModioVirusStatus ToUnreal(Modio::FileMetadata::VirusStatus VirusStatus) -{ - switch (VirusStatus) - { - case Modio::FileMetadata::VirusStatus::NoThreat: - return EModioVirusStatus::NoThreat; - case Modio::FileMetadata::VirusStatus::Malicious: - return EModioVirusStatus::Malicious; - } - - return EModioVirusStatus::NoThreat; -} -MODIO_END_CONVERT_SWITCHES -#pragma endregion diff --git a/Source/Modio/Public/Types/ModioFilterParams.h b/Source/Modio/Public/Types/ModioFilterParams.h new file mode 100644 index 00000000..4157c803 --- /dev/null +++ b/Source/Modio/Public/Types/ModioFilterParams.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "Types/ModioCommonTypes.h" + +// clang-format off +#include "ModioFilterParams.generated.h" +// clang-format on + +/// Forward declaration of SDK type for declaration of conversion function below +namespace Modio +{ + class FilterParams; +} + +/// @brief Enum indicating which field should be used to sort the results +UENUM(BlueprintType) +enum class EModioSortFieldType : uint8 +{ + ID, /** use mod ID (default) */ + DownloadsToday, /** use number of downloads in last 24 (exposed in REST API as 'popular' */ + SubscriberCount, /** use number of subscribers */ + Rating, /** use mod rating */ + DateMarkedLive, /** use date mod was marked live */ + DateUpdated /** use date mod was last updated */ +}; + +/// @brief Enum indicating which direction sorting should be applied +UENUM(BlueprintType) +enum class EModioSortDirection : uint8 +{ + Ascending, /** (default) */ + Descending +}; + +/** @brief Class storing a set of filter parameters for use in xref:ListAllModsAsync[] */ +USTRUCT(BlueprintType) +struct MODIO_API FModioFilterParams +{ + GENERATED_BODY() + + /** + * @brief Indicates the filter should only include the specified mods + * @param IDs the set of mods to match + * @return *this + */ + FModioFilterParams& MatchingIDs(const TArray& IDs); + + /** + * @brief Indicates the filter should exclude the specified mods. + * @param IDs the set of mods to exclude + * @return *this + */ + FModioFilterParams& ExcludingIDs(const TArray& IDs); + + /** + * @brief Indicates results should be sorted using the specified field and direction + * @param ByField Field to sort with + * @param ByDirection Direction to sort + * @return *this + **/ + FModioFilterParams& SortBy(EModioSortFieldType ByField, EModioSortDirection ByDirection); + + /** + * @brief Only include mods where the name contains the provided string + * @param SearchString Search string + * @return *this + **/ + FModioFilterParams& NameContains(const FString& SearchString); + + /** + * @brief Only include mods where the name contains at least one of the provided strings (string1 OR string2 OR + *stringN...) + * @tparam ...Args std::string + * @param SearchString First search string + * @param ...args Additional search strings + * @return *this + **/ + FModioFilterParams& NameContains(const TArray& SearchString); + + /** + * @brief Only include mods that were marked live (i.e released) after the specified date + * @param LiveAfter Minimum date + * @return *this + **/ + FModioFilterParams& MarkedLiveAfter(FDateTime LiveAfter); + + /** + * @brief Only include mods that were marked live (i.e released) before the specified date + * @param LiveBefore Maximum date + * @return *this + **/ + FModioFilterParams& MarkedLiveBefore(FDateTime LiveBefore); + + /** + * @brief Only include mods that have the specified tag + * @param Tag Tag to include + * @return *this + **/ + FModioFilterParams& WithTags(const FString& Tag); + + /** + * @brief Only include mods that have all the specified tags (tag1 AND tag2 AND tagN...) + * @param NewTags The set of tags to filter on + * @return *this + **/ + FModioFilterParams& WithTags(const TArray& NewTags); + + /** + * @brief Only include mods that do not have the specified tag + * @param Tag Tag to exclude + * @return *this + **/ + FModioFilterParams& WithoutTags(const FString& Tag); + + /** + * @brief Only include mods that do not have any of the specified tags ( NOT (tag1 OR tag2 OR tagN...)) + * @param NewTags Tags to exclude + * @return *this + **/ + FModioFilterParams& WithoutTags(const TArray& NewTags); + + /** + * @brief Returns a sub-range of query results from StartIndex to StartIndex + ResultCount + * @param StartIndex Zero-based index of first result to return + * @param ResultCount Number of results to return + * @return *this + **/ + FModioFilterParams& IndexedResults(uint64 StartIndex, uint64 ResultCount); + + /** + * @brief Returns a sub-range of query results based on a specified page size and index + * @param PageNumber Zero-based index of page to return + * @param PageSize Number of results in a page + * @return + **/ + FModioFilterParams& PagedResults(uint64 PageNumber, uint64 PageSize); + + /** + * @brief Converts the filter params to a string suitable for use in the REST API. + * @note Performs a allocation to acquire the string + * @return FString containing the filter parameters + */ + FString ToString() const; + +private: + + friend class Modio::FilterParams ToModio(const FModioFilterParams& In ); + + EModioSortDirection Direction = EModioSortDirection::Ascending; + EModioSortFieldType SortField = EModioSortFieldType::ID; + TArray SearchKeywords; + TOptional DateRangeBegin; + TOptional DateRangeEnd; + TArray Tags; + TArray ExcludedTags; + TArray IncludedIDs; + TArray ExcludedIDs; + + bool isPaged = false; + int64 Index = 0; + int64 Count = 100; +}; diff --git a/Source/Modio/Classes/Types/ModioImage.h b/Source/Modio/Public/Types/ModioImage.h similarity index 69% rename from Source/Modio/Classes/Types/ModioImage.h rename to Source/Modio/Public/Types/ModioImage.h index 9b2947fa..31cb366e 100644 --- a/Source/Modio/Classes/Types/ModioImage.h +++ b/Source/Modio/Public/Types/ModioImage.h @@ -1,12 +1,20 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Containers/UnrealString.h" -#include "ModioSDK.h" #include "Types/ModioImageState.h" -// clang-format off #include "ModioImage.generated.h" -// clang-format on + DECLARE_DELEGATE_OneParam(FOnLoadImageDelegateFast, class UTexture2DDynamic*); @@ -16,9 +24,6 @@ struct MODIO_API FModioImage { GENERATED_BODY() - FModioImage() = default; - FModioImage(const Modio::filesystem::path& Path); - /** Get the texture if if has been loaded by any FModioImage instance */ class UTexture2DDynamic* GetTexture() const; @@ -49,21 +54,5 @@ struct FModioOptionalImage { GENERATED_BODY() - // This is here due to it was needed once, but now I get crashes if I remove it - bool Serialize(FArchive& Ar) - { - return true; - } - TOptional Internal; }; - -// This is here due to it was needed once, but now I get crashes if I remove it -template<> -struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 -{ - enum - { - WithSerializer = true - }; -}; diff --git a/Source/Modio/Public/Types/ModioImageState.h b/Source/Modio/Public/Types/ModioImageState.h new file mode 100644 index 00000000..1541ac37 --- /dev/null +++ b/Source/Modio/Public/Types/ModioImageState.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +// clang-format off +#include "ModioImageState.generated.h" +// clang-format on + +UENUM(BlueprintType) +enum class EModioImageState : uint8 +{ + OnDisc, + LoadingIntoMemory, + InMemory, + Corrupted +}; \ No newline at end of file diff --git a/Source/Modio/Classes/Types/ModioInitializeOptions.h b/Source/Modio/Public/Types/ModioInitializeOptions.h similarity index 67% rename from Source/Modio/Classes/Types/ModioInitializeOptions.h rename to Source/Modio/Public/Types/ModioInitializeOptions.h index 350dee72..307846b2 100644 --- a/Source/Modio/Classes/Types/ModioInitializeOptions.h +++ b/Source/Modio/Public/Types/ModioInitializeOptions.h @@ -1,6 +1,15 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once -#include "ModioSDK.h" #include "Types/ModioCommonTypes.h" // clang-format off @@ -12,16 +21,13 @@ struct FModioInitializeOptions { GENERATED_BODY() - /** Implicitly convert it to the underlying type */ - operator Modio::InitializeOptions() const; - /** @brief The Mod.io-provided ID for the game */ UPROPERTY(BlueprintReadOnly, Category = "mod.io") - FModioGameID GameID = FModioGameID::InvalidGameID(); + FModioGameID GameId = FModioGameID::InvalidGameID(); /** @brief The Mod.io-provided API key for your application or game */ UPROPERTY(BlueprintReadOnly, Category = "mod.io") - FModioApiKey APIKey = FModioApiKey::InvalidAPIKey(); + FModioApiKey ApiKey = FModioApiKey::InvalidAPIKey(); /** @brief The mod.io environment you want to run the SDK on */ UPROPERTY(BlueprintReadOnly, Category = "mod.io") diff --git a/Source/Modio/Classes/Types/ModioList.h b/Source/Modio/Public/Types/ModioList.h similarity index 90% rename from Source/Modio/Classes/Types/ModioList.h rename to Source/Modio/Public/Types/ModioList.h index 9986ee80..4e45ccf8 100644 --- a/Source/Modio/Classes/Types/ModioList.h +++ b/Source/Modio/Public/Types/ModioList.h @@ -1,6 +1,15 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once -#include "ModioSDK.h" #include "Templates/UnrealTemplate.h" #include "Internal/ModioConvert.h" diff --git a/Source/Modio/Classes/Types/ModioMetadata.h b/Source/Modio/Public/Types/ModioMetadata.h similarity index 56% rename from Source/Modio/Classes/Types/ModioMetadata.h rename to Source/Modio/Public/Types/ModioMetadata.h index 4cea9021..90d43ed6 100644 --- a/Source/Modio/Classes/Types/ModioMetadata.h +++ b/Source/Modio/Public/Types/ModioMetadata.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Containers/UnrealString.h" @@ -6,19 +16,11 @@ #include "ModioMetadata.generated.h" // clang-format on -namespace Modio -{ - struct Metadata; -} - USTRUCT(BlueprintType) struct MODIO_API FModioMetadata { GENERATED_BODY() - FModioMetadata() = default; - FModioMetadata(const Modio::Metadata& Metadata); - /** Key of the metadata */ UPROPERTY(BlueprintReadOnly, Category = "Metadata") FString Key; @@ -27,10 +29,3 @@ struct MODIO_API FModioMetadata UPROPERTY(BlueprintReadOnly, Category = "Metadata") FString Value; }; - -#pragma region ToUnreal implementation -FORCEINLINE FModioMetadata ToUnreal(const Modio::Metadata& Metadata) -{ - return FModioMetadata(Metadata); -} -#pragma endregion diff --git a/Source/Modio/Public/Types/ModioModCollectionEntry.h b/Source/Modio/Public/Types/ModioModCollectionEntry.h new file mode 100644 index 00000000..22490b3e --- /dev/null +++ b/Source/Modio/Public/Types/ModioModCollectionEntry.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "Types/ModioCommonTypes.h" +#include "Types/ModioModInfo.h" + +// clang-format off +#include "ModioModCollectionEntry.generated.h" +// clang-format on + + +/// @brief Enum representing the current state of a mod +UENUM(BlueprintType) +enum class EModioModState : uint8 +{ + InstallationPending, // dont save + Installed, + UpdatePending, // saved as installed + Downloading, // installing - dont save + Extracting, // installing- don't save + UninstallPending, // saved as installed +}; + +/** @brief Class representing a mod which is installed locally */ +USTRUCT(BlueprintType) +struct MODIO_API FModioModCollectionEntry +{ + GENERATED_BODY() + + EModioModState GetModState() const; + + FModioModID GetID() const; + + const FModioModInfo& GetModProfile() const; + + const FString GetPath() const; + +private: + friend struct FModioModCollectionEntry ToUnreal(const class Modio::ModCollectionEntry& In); + + EModioModState ModState; + FModioModID ModID; + TOptional ModPath; + FModioModInfo ModProfile; +}; diff --git a/Source/Modio/Classes/Types/ModioModInfo.h b/Source/Modio/Public/Types/ModioModInfo.h similarity index 90% rename from Source/Modio/Classes/Types/ModioModInfo.h rename to Source/Modio/Public/Types/ModioModInfo.h index 590dc21a..7ecbb0ff 100644 --- a/Source/Modio/Classes/Types/ModioModInfo.h +++ b/Source/Modio/Public/Types/ModioModInfo.h @@ -1,6 +1,15 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once -#include "ModioSDK.h" #include "Types/ModioFileMetadata.h" #include "Types/ModioMetadata.h" #include "Types/ModioModStats.h" @@ -23,10 +32,6 @@ struct MODIO_API FModioModInfo { GENERATED_BODY() - FModioModInfo() = default; - FModioModInfo(const Modio::ModInfo& ModInfo); - FModioModInfo(const FModioModInfo& ModInfo) = default; - /** @brief Unique Mod ID */ UPROPERTY(BlueprintReadOnly, Category = "ModInfo") FModioModID ModId; @@ -111,6 +116,7 @@ struct MODIO_API FModioModInfo /** @brief Stats and rating information for the mod */ UPROPERTY(BlueprintReadOnly, Category = "Stats") FModioModStats Stats; + friend struct FModioModInfo ToUnreal(const struct Modio::ModInfo& In); }; USTRUCT(BlueprintType) @@ -120,10 +126,3 @@ struct FModioOptionalModInfo TOptional Internal; }; - -#pragma region ToUnreal implementation -FORCEINLINE FModioModInfo ToUnreal(const Modio::ModInfo& ModInfo) -{ - return FModioModInfo(ModInfo); -} -#pragma endregion diff --git a/Source/Modio/Classes/Types/ModioModInfoList.h b/Source/Modio/Public/Types/ModioModInfoList.h similarity index 74% rename from Source/Modio/Classes/Types/ModioModInfoList.h rename to Source/Modio/Public/Types/ModioModInfoList.h index afcdeda8..eb3ed427 100644 --- a/Source/Modio/Classes/Types/ModioModInfoList.h +++ b/Source/Modio/Public/Types/ModioModInfoList.h @@ -1,6 +1,15 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once -#include "ModioSDK.h" #include "Types/ModioList.h" #include "Types/ModioModInfo.h" #include "Types/ModioPagedResult.h" @@ -14,7 +23,7 @@ struct MODIO_API FModioModInfoList : public FModioPagedResult, public FModioList { FModioModInfoList() = default; FModioModInfoList(const FModioPagedResult& PagedResult, TArray&& ModInfoList); - FModioModInfoList(const Modio::ModInfoList& ModInfoList); + FModioModInfoList(const class Modio::ModInfoList& ModInfoList); }; #else @@ -43,9 +52,3 @@ struct MODIO_API FModioOptionalModInfoList TOptional Internal; }; -#pragma region ToUnreal implementation -FORCEINLINE FModioModInfoList ToModio(const Modio::ModInfoList& ModInfoList) -{ - return FModioModInfoList(ModInfoList); -} -#pragma endregion diff --git a/Source/Modio/Public/Types/ModioModManagementEvent.h b/Source/Modio/Public/Types/ModioModManagementEvent.h new file mode 100644 index 00000000..00a62f7e --- /dev/null +++ b/Source/Modio/Public/Types/ModioModManagementEvent.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "Types/ModioCommonTypes.h" +#include "Types/ModioErrorCode.h" + +// clang-format off +#include "ModioModManagementEvent.generated.h" +// clang-format on + +/** @brief What type of event occurred */ +UENUM(BlueprintType) +enum class EModioModManagementEventType : uint8 +{ + Installed, /** Mod installation to local storage */ + Uninstalled, /** Mod uninstallation from local storage*/ + Updated /** Mod local installation updated to latest version*/ +}; + +/** @brief Simple struct representing the outcome of a mod management operation */ +USTRUCT(BlueprintType) +struct MODIO_API FModioModManagementEvent +{ + GENERATED_BODY() + + /** @brief ID for the mod that the event occurred on */ + UPROPERTY(BlueprintReadOnly,Category="ModManagementEvent") + FModioModID ID; + + /** @brief What type of event occurred */ + UPROPERTY(BlueprintReadOnly,Category="ModManagementEvent") + EModioModManagementEventType Event; + + /** @brief Empty if operation completed successfully, truthy/contains error code if operation failed */ + UPROPERTY(BlueprintReadOnly,Category="ModManagementEvent") + FModioErrorCode Status; +}; + diff --git a/Source/Modio/Classes/Types/ModioModProgressInfo.h b/Source/Modio/Public/Types/ModioModProgressInfo.h similarity index 73% rename from Source/Modio/Classes/Types/ModioModProgressInfo.h rename to Source/Modio/Public/Types/ModioModProgressInfo.h index 77737128..88fe2d58 100644 --- a/Source/Modio/Classes/Types/ModioModProgressInfo.h +++ b/Source/Modio/Public/Types/ModioModProgressInfo.h @@ -1,11 +1,18 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once -#include "ModioSDK.h" #include "Types/ModioCommonTypes.h" -// clang-format off #include "ModioModProgressInfo.generated.h" -// clang-format on namespace Modio { @@ -18,9 +25,6 @@ struct MODIO_API FModioModProgressInfo { GENERATED_BODY() - FModioModProgressInfo() = default; - FModioModProgressInfo(const Modio::ModProgressInfo& ModProgressInfo); - /** @brief Total size of the downloaded file */ UPROPERTY(BlueprintReadOnly,Category="ModProgressInfo") int64 TotalDownloadSize; @@ -50,9 +54,3 @@ struct FModioOptionalModProgressInfo TOptional Internal; }; -#pragma region ToUnreal implementation -FORCEINLINE FModioModProgressInfo ToUnreal(const Modio::ModProgressInfo& ModProgressInfo) -{ - return FModioModProgressInfo(ModProgressInfo); -} -#pragma region ToUnreal implementation diff --git a/Source/Modio/Classes/Types/ModioModStats.h b/Source/Modio/Public/Types/ModioModStats.h similarity index 87% rename from Source/Modio/Classes/Types/ModioModStats.h rename to Source/Modio/Public/Types/ModioModStats.h index 8085c83b..c89f9821 100644 --- a/Source/Modio/Classes/Types/ModioModStats.h +++ b/Source/Modio/Public/Types/ModioModStats.h @@ -1,15 +1,18 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Containers/UnrealString.h" -namespace Modio -{ - struct ModStats; -} - -// clang-format off #include "ModioModStats.generated.h" -// clang-format on /** @brief Contains download stats and ratings for a mod */ USTRUCT(BlueprintType) @@ -17,9 +20,6 @@ struct MODIO_API FModioModStats { GENERATED_BODY() - FModioModStats() = default; - FModioModStats(const Modio::ModStats& Stats); - /** @brief Current rank of the mod. */ UPROPERTY(BlueprintReadOnly, Category = "ModStats|Popularity") int64 PopularityRankPosition; @@ -71,10 +71,3 @@ struct MODIO_API FModioModStats UPROPERTY(BlueprintReadOnly, Category = "ModStats|Rating") FString RatingDisplayText; }; - -#pragma region ToUnreal implementation -FORCEINLINE FModioModStats ToUnreal(const Modio::ModStats& Stats) -{ - return FModioModStats(Stats); -} -#pragma endregion diff --git a/Source/Modio/Public/Types/ModioModTag.h b/Source/Modio/Public/Types/ModioModTag.h new file mode 100644 index 00000000..c28931c9 --- /dev/null +++ b/Source/Modio/Public/Types/ModioModTag.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "Containers/UnrealString.h" + +#include "ModioModTag.generated.h" + + +USTRUCT(BlueprintType) +struct MODIO_API FModioModTag +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadOnly, Category = "ModTag") + FString Tag; +}; diff --git a/Source/Modio/Classes/Types/ModioModTagInfo.h b/Source/Modio/Public/Types/ModioModTagInfo.h similarity index 66% rename from Source/Modio/Classes/Types/ModioModTagInfo.h rename to Source/Modio/Public/Types/ModioModTagInfo.h index 2b4ee417..0f82a126 100644 --- a/Source/Modio/Classes/Types/ModioModTagInfo.h +++ b/Source/Modio/Public/Types/ModioModTagInfo.h @@ -1,16 +1,19 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Containers/Array.h" #include "Containers/UnrealString.h" -// clang-format off #include "ModioModTagInfo.generated.h" -// clang-format on - -namespace Modio -{ - struct ModTagInfo; -} /** @brief Metadata about a group of tags that can be used for filtering mods */ USTRUCT(BlueprintType) @@ -18,9 +21,6 @@ struct MODIO_API FModioModTagInfo { GENERATED_BODY() - FModioModTagInfo() = default; - FModioModTagInfo(const Modio::ModTagInfo& ModTagOptions); - /** @brief The display name for the tag */ UPROPERTY(BlueprintReadOnly,Category="mod.io|ModTagInfo") FString TagGroupName; @@ -34,9 +34,3 @@ struct MODIO_API FModioModTagInfo bool bAllowMultipleSelection; }; -#pragma region ToUnreal implementation -FORCEINLINE FModioModTagInfo ToUnreal(const Modio::ModTagInfo& ModTagInfo) -{ - return FModioModTagInfo(ModTagInfo); -} -#pragma endregion diff --git a/Source/Modio/Classes/Types/ModioModTagOptions.h b/Source/Modio/Public/Types/ModioModTagOptions.h similarity index 65% rename from Source/Modio/Classes/Types/ModioModTagOptions.h rename to Source/Modio/Public/Types/ModioModTagOptions.h index 42a5733b..3792f7cd 100644 --- a/Source/Modio/Classes/Types/ModioModTagOptions.h +++ b/Source/Modio/Public/Types/ModioModTagOptions.h @@ -1,12 +1,20 @@ -#pragma once - -#include "ModioSDK.h" -#include "Types/ModioModInfoList.h" +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "Types/ModioList.h" #include "Types/ModioModTagInfo.h" +#include "Types/ModioPagedResult.h" -// clang-format off #include "ModioModTagOptions.generated.h" -// clang-format on #if CPP // Native version of FModioModTagOptions @@ -17,7 +25,8 @@ struct MODIO_API FModioModTagOptions : public FModioPagedResult, public FModioLi }; #else -// Blueprint mirror of FModioModTagOptions that's flattened as blueprints don't understand either template classes or multiple inheritance +// Blueprint mirror of FModioModTagOptions that's flattened as blueprints don't understand either template classes or +// multiple inheritance USTRUCT(NoExport, BlueprintType) struct MODIO_API FModioModTagOptions { @@ -40,10 +49,3 @@ struct FModioOptionalModTagOptions TOptional Internal; }; - -#pragma region ToUnreal implementation -FORCEINLINE FModioModTagOptions ToUnreal(const Modio::ModTagOptions& ModTagOptions) -{ - return FModioModTagOptions(ModTagOptions); -} -#pragma endregion diff --git a/Source/Modio/Public/Types/ModioPagedResult.h b/Source/Modio/Public/Types/ModioPagedResult.h new file mode 100644 index 00000000..434eed88 --- /dev/null +++ b/Source/Modio/Public/Types/ModioPagedResult.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "ModioPagedResult.generated.h" + +namespace Modio +{ + class PagedResult; +} + +/** Base class for all api endpoints that can return paged results */ +USTRUCT(BlueprintType) +struct MODIO_API FModioPagedResult +{ + GENERATED_BODY() + + FModioPagedResult() = default; + FModioPagedResult(const Modio::PagedResult& Other); + FModioPagedResult(int32 ResultOffset, int32 PageSize, int32 TotalResultCount, int32 ResultCount); + + int32 GetPageIndex() const + { + return PageIndex; + } + int32 GetPageSize() const + { + return PageSize; + } + + int32 GetTotalResultCount() const + { + return TotalResultCount; + } + + int32 GetResultCount() const + { + return ResultCount; + } + +protected: + UPROPERTY(BlueprintReadOnly, Category = "mod.io|PagedResult|Page") + int32 PageIndex; + + UPROPERTY(BlueprintReadOnly, Category = "mod.io|PagedResult|Page") + int32 PageSize; + + UPROPERTY(BlueprintReadOnly, Category = "mod.io|PagedResult|Page") + int32 PageCount; + + UPROPERTY(BlueprintReadOnly, Category = "mod.io|PagedResult") + int32 TotalResultCount; + + UPROPERTY(BlueprintReadOnly, Category = "mod.io|PagedResult") + int32 ResultCount; +}; diff --git a/Source/Modio/Public/Types/ModioRating.h b/Source/Modio/Public/Types/ModioRating.h new file mode 100644 index 00000000..cf9c3f13 --- /dev/null +++ b/Source/Modio/Public/Types/ModioRating.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "ModioRating.generated.h" + +UENUM() +enum class EModioRating : uint8 +{ + Neutral, + Positive, + Negative +}; \ No newline at end of file diff --git a/Source/Modio/Public/Types/ModioReportParams.h b/Source/Modio/Public/Types/ModioReportParams.h new file mode 100644 index 00000000..a9b3b776 --- /dev/null +++ b/Source/Modio/Public/Types/ModioReportParams.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once + +#include "ModioReportParams.generated.h" + +namespace Modio +{ + class ReportParams; +} + + +UENUM() +enum class EModioReportType : uint8 +{ + Generic = 0, + DMCA = 1, + NotWorking = 2, + RudeContent = 3, + IllegalContent = 4, + StolenContent = 5, + FalseInformation = 6, + Other = 7 +}; + + +USTRUCT(BlueprintType) +struct MODIO_API FModioReportParams +{ + GENERATED_BODY(); + + + FModioReportParams(); + + /// @brief Creates a content report for a game. + /// @param Game The ID of the game being reported + /// @param Type The nature of the content report + /// @param ReportDescription A description of why the content is being reported + /// @param ReporterName Name of the submitting user. Recommended for DMCA reports, but may be empty + /// @param ReporterContact Contact details of the submitting user. Recommended for DMCA reports, but may be + /// empty + FModioReportParams(struct FModioGameID Game, EModioReportType Type, FString ReportDescription, + TOptional ReporterName, TOptional ReporterContact); + + /// @docpublic + /// @brief Creates a content report for a game. + /// @param User The ID of the User being reported + /// @param Type The nature of the content report + /// @param ReportDescription A description of why the content is being reported + /// @param ReporterName Name of the submitting user. Recommended for DMCA reports, but may be empty + /// @param ReporterContact Contact details of the submitting user. Recommended for DMCA reports, but may be + /// empty + FModioReportParams(struct FModioUserID User, EModioReportType Type, FString ReportDescription, + TOptional ReporterName, TOptional ReporterContact); + + /// @docpublic + /// @brief Creates a content report for a game. + /// @param Mod The ID of the content being reported + /// @param Type The nature of the content report + /// @param ReportDescription A description of why the content is being reported + /// @param ReporterName Name of the submitting user. Recommended for DMCA reports, but may be empty + /// @param ReporterContact Contact details of the submitting user. Recommended for DMCA reports, but may be + /// empty + FModioReportParams(struct FModioModID Mod, EModioReportType Type, FString ReportDescription, + TOptional ReporterName, TOptional ReporterContact); + +private: + + + enum class ResourceType : uint8 + { + Game, + Mod, + User + }; + ResourceType ReportedResourceType; + + int64 ResourceID; + + EModioReportType Type; + + TOptional ReporterName; + + TOptional ReporterContact; + + FString ReportDescription; + + FModioReportParams(int64 ResourceID, ResourceType ReportedResourceType, EModioReportType Type, + FString ReportDescription, TOptional ReporterName, + TOptional ReporterContact); + + friend Modio::ReportParams ToModio(const FModioReportParams& In); +}; \ No newline at end of file diff --git a/Source/Modio/Classes/Types/ModioTerms.h b/Source/Modio/Public/Types/ModioTerms.h similarity index 73% rename from Source/Modio/Classes/Types/ModioTerms.h rename to Source/Modio/Public/Types/ModioTerms.h index f1e33e27..637c18dd 100644 --- a/Source/Modio/Classes/Types/ModioTerms.h +++ b/Source/Modio/Public/Types/ModioTerms.h @@ -1,6 +1,15 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once -#include "ModioSDK.h" #include "Containers/UnrealString.h" #include "ModioTerms.generated.h" @@ -9,10 +18,6 @@ USTRUCT(BlueprintType) struct MODIO_API FModioLink { GENERATED_BODY() - - FModioLink() = default; - FModioLink(const Modio::Terms::Link& Link); - FModioLink(const FModioLink& Link) = default; /** @brief The user-facing text for the link */ UPROPERTY(BlueprintReadOnly,Category="Terms|Link") @@ -33,10 +38,6 @@ USTRUCT(BlueprintType) struct MODIO_API FModioTerms { GENERATED_BODY(); - - FModioTerms() = default; - FModioTerms(const Modio::Terms& Terms); - FModioTerms(const FModioTerms& Terms) = default; /** @brief Text to display on the affirmative/OK button */ UPROPERTY(BlueprintReadOnly,Category="Terms|Buttons") @@ -73,21 +74,5 @@ struct FModioOptionalTerms { GENERATED_BODY() - FModioOptionalTerms() = default; - FModioOptionalTerms(TOptional&& ModTagOptions); - TOptional Internal; }; - -#pragma region ToUnreal implementation -FORCEINLINE FModioTerms ToUnreal(const Modio::Terms& Terms) -{ - return FModioTerms(Terms); -} - -FORCEINLINE FModioLink ToUnreal(const Modio::Terms::Link& Link) -{ - return FModioLink(Link); -} - -#pragma endregion \ No newline at end of file diff --git a/Source/Modio/Classes/Types/ModioURLList.h b/Source/Modio/Public/Types/ModioURLList.h similarity index 68% rename from Source/Modio/Classes/Types/ModioURLList.h rename to Source/Modio/Public/Types/ModioURLList.h index 43d82081..223710e5 100644 --- a/Source/Modio/Classes/Types/ModioURLList.h +++ b/Source/Modio/Public/Types/ModioURLList.h @@ -1,13 +1,26 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Containers/Array.h" #include "Containers/UnrealString.h" -#include "ModioSDK.h" #include "Types/ModioList.h" -// clang-format off #include "ModioURLList.generated.h" -// clang-format on + +namespace Modio +{ + class YoutubeURLList; + class SketchfabURLList; +} #if CPP struct MODIO_API FModioYoutubeURLList : public FModioList @@ -40,15 +53,3 @@ struct FModioSketchfabURLList FModioURLListInternal InternalList; }; #endif - -#pragma region ToUnreal implementation -FORCEINLINE FModioYoutubeURLList ToUnreal(const Modio::YoutubeURLList& UrlList) -{ - return FModioYoutubeURLList(UrlList); -} - -FORCEINLINE FModioSketchfabURLList ToUnreal(const Modio::SketchfabURLList& UrlList) -{ - return FModioSketchfabURLList(UrlList); -} -#pragma endregion \ No newline at end of file diff --git a/Source/Modio/Classes/Types/ModioUser.h b/Source/Modio/Public/Types/ModioUser.h similarity index 75% rename from Source/Modio/Classes/Types/ModioUser.h rename to Source/Modio/Public/Types/ModioUser.h index 2dc7a5eb..fe71e22a 100644 --- a/Source/Modio/Classes/Types/ModioUser.h +++ b/Source/Modio/Public/Types/ModioUser.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Types/ModioCommonTypes.h" @@ -42,15 +52,5 @@ struct MODIO_API FModioOptionalUser { GENERATED_BODY() - FModioOptionalUser() = default; - FModioOptionalUser(TOptional&& ModInfoList); - TOptional Internal; -}; - -#pragma region ToUnreal implementation -FORCEINLINE FModioUser ToUnreal(const Modio::User& Value) -{ - return FModioUser(Value); -} -#pragma endregion +}; \ No newline at end of file diff --git a/Source/Modio/Classes/Types/ModioValidationError.h b/Source/Modio/Public/Types/ModioValidationError.h similarity index 68% rename from Source/Modio/Classes/Types/ModioValidationError.h rename to Source/Modio/Public/Types/ModioValidationError.h index 23788881..1d142f9c 100644 --- a/Source/Modio/Classes/Types/ModioValidationError.h +++ b/Source/Modio/Public/Types/ModioValidationError.h @@ -1,3 +1,13 @@ +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + #pragma once #include "Internal/ModioConvert.h" #include "Containers/UnrealString.h" diff --git a/Source/Modio/Public/UI/ModioExampleLibrary.h b/Source/Modio/Public/UI/ModioExampleLibrary.h index c5c4b1e2..b8055091 100644 --- a/Source/Modio/Public/UI/ModioExampleLibrary.h +++ b/Source/Modio/Public/UI/ModioExampleLibrary.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "ModioSubsystem.h" diff --git a/Source/Modio/Public/UI/ModioPopupBase.h b/Source/Modio/Public/UI/ModioPopupBase.h index e8aef02c..839fc84d 100644 --- a/Source/Modio/Public/UI/ModioPopupBase.h +++ b/Source/Modio/Public/UI/ModioPopupBase.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Blueprint/UserWidget.h" // clang-format off diff --git a/Source/Modio/Public/UI/ModioPopupContainer.h b/Source/Modio/Public/UI/ModioPopupContainer.h index 043cca37..13c3c31c 100644 --- a/Source/Modio/Public/UI/ModioPopupContainer.h +++ b/Source/Modio/Public/UI/ModioPopupContainer.h @@ -1,4 +1,14 @@ -#pragma once +/* + * Copyright (C) 2021 mod.io Pty Ltd. + * + * This file is part of the mod.io UE4 Plugin. + * + * Distributed under the MIT License. (See accompanying file LICENSE or + * view online at ) + * + */ + +#pragma once #include "Blueprint/UserWidget.h" // clang-format off diff --git a/Source/ThirdParty/NativeSDK b/Source/ThirdParty/NativeSDK index e21fb1d9..ffd57991 160000 --- a/Source/ThirdParty/NativeSDK +++ b/Source/ThirdParty/NativeSDK @@ -1 +1 @@ -Subproject commit e21fb1d98861a8e4eb7c17fbe012c2f07376447d +Subproject commit ffd579911c3cb42b3fc8e73f68f5bdccc28a4e5e

    Largest