From bbf01c7960cc13931ccb6192e1d763fab60cef84 Mon Sep 17 00:00:00 2001 From: turupawn Date: Fri, 5 Jun 2020 21:00:46 -0600 Subject: [PATCH 1/2] consecutive DownloadFilesById call crash fix --- Source/modio/Private/ModioSubsystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/modio/Private/ModioSubsystem.cpp b/Source/modio/Private/ModioSubsystem.cpp index ea29431..cdf39d2 100644 --- a/Source/modio/Private/ModioSubsystem.cpp +++ b/Source/modio/Private/ModioSubsystem.cpp @@ -792,17 +792,17 @@ void FModioSubsystem::DownloadModfilesById(const TArray &ModIds, FModioBo { CModIds[i] = ModIds[i]; } + QueueAsyncTask( Request ); modioDownloadModfilesById(Request, CModIds, (u32)ModIds.Num(), FModioAsyncRequest_DownloadModfilesById::Response); delete[] CModIds; - QueueAsyncTask( Request ); } void FModioSubsystem::DownloadSubscribedModfiles(bool UninstallUnsubscribed, FModioBooleanDelegate DownloadSubscribedModfilesDelegate) { FModioAsyncRequest_DownloadSubscribedModfiles *Request = new FModioAsyncRequest_DownloadSubscribedModfiles( this, DownloadSubscribedModfilesDelegate ); - modioDownloadSubscribedModfiles(Request, UninstallUnsubscribed, FModioAsyncRequest_DownloadSubscribedModfiles::Response); QueueAsyncTask( Request ); + modioDownloadSubscribedModfiles(Request, UninstallUnsubscribed, FModioAsyncRequest_DownloadSubscribedModfiles::Response); } bool FModioSubsystem::UninstallMod(int32 ModId) From ea6e15d4ae4b1084bcce5a8a676d48c2019345cb Mon Sep 17 00:00:00 2001 From: turupawn Date: Thu, 11 Jun 2020 18:52:56 -0600 Subject: [PATCH 2/2] added UninstallUnavailableMods to both C++ and BP layers --- ...oAsyncRequest_UninstallUnavailableMods.cpp | 67 +++++++++++++++++++ ...CallbackProxy_UninstallUnavailableMods.cpp | 47 +++++++++++++ Source/modio/Private/ModioSubsystem.cpp | 36 ++++++++++ Source/modio/Private/ModioUE4Utility.cpp | 20 ++++++ ...dioAsyncRequest_UninstallUnavailableMods.h | 26 +++++++ .../CallbackProxy_UninstallUnavailableMods.h | 39 +++++++++++ Source/modio/Public/ModioSubsystem.h | 3 + Source/modio/Public/ModioUE4Utility.h | 4 +- 8 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 Source/modio/Private/AsyncRequest/ModioAsyncRequest_UninstallUnavailableMods.cpp create mode 100644 Source/modio/Private/BlueprintCallbackProxies/CallbackProxy_UninstallUnavailableMods.cpp create mode 100644 Source/modio/Public/AsyncRequest/ModioAsyncRequest_UninstallUnavailableMods.h create mode 100644 Source/modio/Public/BlueprintCallbackProxies/CallbackProxy_UninstallUnavailableMods.h diff --git a/Source/modio/Private/AsyncRequest/ModioAsyncRequest_UninstallUnavailableMods.cpp b/Source/modio/Private/AsyncRequest/ModioAsyncRequest_UninstallUnavailableMods.cpp new file mode 100644 index 0000000..21bd970 --- /dev/null +++ b/Source/modio/Private/AsyncRequest/ModioAsyncRequest_UninstallUnavailableMods.cpp @@ -0,0 +1,67 @@ +// Copyright 2019 modio. All Rights Reserved. +// Released under MIT. + +#include "AsyncRequest/ModioAsyncRequest_UninstallUnavailableMods.h" +#include "ModioUE4Utility.h" + +FModioAsyncRequest_UninstallUnavailableMods::FModioAsyncRequest_UninstallUnavailableMods( FModioSubsystem *Modio, FModioGenericDelegate Delegate, int32 PendingCalls ) : + FModioAsyncRequest( Modio ), + ResponseDelegate( Delegate ) +{ + this->PendingCalls = PendingCalls; +} + +TArray getInstalledMods() +{ + TArray InstalledMods; + u32 installed_mods_count = modioGetAllInstalledModsCount(); + ModioInstalledMod *modio_installed_mods = (ModioInstalledMod *)malloc(installed_mods_count * sizeof(*modio_installed_mods)); + modioGetAllInstalledMods(modio_installed_mods); + for (u32 i = 0; i < installed_mods_count; i++) + { + InstalledMods.Add(modio_installed_mods[i].mod.id); + modioFreeInstalledMod(&modio_installed_mods[i]); + } + free(modio_installed_mods); + return InstalledMods; +} + +void FModioAsyncRequest_UninstallUnavailableMods::Response(void *Object, ModioResponse ModioResponse, ModioMod *ModioMods, u32 ModioModsSize) +{ + UE_LOG(LogTemp, Warning, TEXT("[mod.io] FModioAsyncRequest_UninstallUnavailableMods response returned")); + FModioAsyncRequest_UninstallUnavailableMods* ThisPointer = (FModioAsyncRequest_UninstallUnavailableMods*)Object; + + ThisPointer->PendingCalls--; + for(int32 i=0; i<(int32)ModioModsSize; i++) + { + ThisPointer->AvailableMods.Push(ModioMods[i].id); + } + + if(ThisPointer->PendingCalls == 0) + { + UE_LOG(LogTemp, Warning, TEXT("[mod.io] FModioAsyncRequest_UninstallUnavailableMods response returned")); + for(auto InstalledMod : getInstalledMods()) + { + bool IsAvailable = false; + for(auto AvailableMod : ThisPointer->AvailableMods) + { + if(InstalledMod == AvailableMod) + IsAvailable = true; + } + if(!IsAvailable) + { + UE_LOG(LogTemp, Warning, TEXT("[mod.io] Mod %i is unavailable, will be uninstalled"), InstalledMod); + modioUninstallMod((u32)InstalledMod); + }else + { + UE_LOG(LogTemp, Warning, TEXT("[mod.io] Mod %i is available"), InstalledMod); + } + } + FModioResponse Response; + InitializeResponse( Response, ModioResponse ); + + ThisPointer->ResponseDelegate.ExecuteIfBound( Response ); + + ThisPointer->Done(); + } +} \ No newline at end of file diff --git a/Source/modio/Private/BlueprintCallbackProxies/CallbackProxy_UninstallUnavailableMods.cpp b/Source/modio/Private/BlueprintCallbackProxies/CallbackProxy_UninstallUnavailableMods.cpp new file mode 100644 index 0000000..79b5050 --- /dev/null +++ b/Source/modio/Private/BlueprintCallbackProxies/CallbackProxy_UninstallUnavailableMods.cpp @@ -0,0 +1,47 @@ +// Copyright 2019 modio. All Rights Reserved. +// Released under MIT. + +#include "BlueprintCallbackProxies/CallbackProxy_UninstallUnavailableMods.h" +#include "ModioSubsystem.h" +#include "Engine/Engine.h" + +UCallbackProxy_UninstallUnavailableMods::UCallbackProxy_UninstallUnavailableMods(const FObjectInitializer &ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +UCallbackProxy_UninstallUnavailableMods *UCallbackProxy_UninstallUnavailableMods::UninstallUnavailableMods(UObject *WorldContext) +{ + UCallbackProxy_UninstallUnavailableMods *Proxy = NewObject(); + Proxy->SetFlags(RF_StrongRefOnFrame); + Proxy->WorldContextObject = WorldContext; + return Proxy; +} + +void UCallbackProxy_UninstallUnavailableMods::Activate() +{ + UWorld* World = GEngine->GetWorldFromContextObject( WorldContextObject, EGetWorldErrorMode::LogAndReturnNull ); + FModioSubsystemPtr Modio = FModioSubsystem::Get( World ); + if( Modio.IsValid() ) + { + Modio->UninstallUnavailableMods( FModioGenericDelegate::CreateUObject( this, &UCallbackProxy_UninstallUnavailableMods::OnUninstallUnavailableModsDelegate ) ); + } + else + { + // @todonow: Make something more pretty than this + FModioResponse Response; + OnFailure.Broadcast( Response ); + } +} + +void UCallbackProxy_UninstallUnavailableMods::OnUninstallUnavailableModsDelegate(FModioResponse Response) +{ + if (Response.Code >= 200 && Response.Code < 300) + { + OnSuccess.Broadcast(Response); + } + else + { + OnFailure.Broadcast(Response); + } +} \ No newline at end of file diff --git a/Source/modio/Private/ModioSubsystem.cpp b/Source/modio/Private/ModioSubsystem.cpp index cdf39d2..8c92710 100644 --- a/Source/modio/Private/ModioSubsystem.cpp +++ b/Source/modio/Private/ModioSubsystem.cpp @@ -810,6 +810,42 @@ bool FModioSubsystem::UninstallMod(int32 ModId) return modioUninstallMod((u32)ModId); } +void FModioSubsystem::UninstallUnavailableMods(FModioGenericDelegate UninstallUnavailableModsDelegate) +{ + UE_LOG(LogTemp, Warning, TEXT("[mod.io] Uninstalling unavailable mods")); + int32 ResponseLimit = 100; + int32 PendingCalls = 1 + (this->GetAllInstalledMods().Num() / ResponseLimit); + UE_LOG(LogTemp, Warning, TEXT("[mod.io] A total of %i calls will be made to the mod.io API"), PendingCalls); + FModioAsyncRequest_UninstallUnavailableMods *Request = new FModioAsyncRequest_UninstallUnavailableMods( this, UninstallUnavailableModsDelegate, PendingCalls ); + + ModioFilterCreator modio_filter_creator; + modioInitFilter(&modio_filter_creator); + int32 CurrentCallCount = 0; + TArray ModIds; + QueueAsyncTask( Request ); + for(auto InstalledMod : this->GetAllInstalledMods()) + { + ModIds.Push(InstalledMod.Mod.Id); + CurrentCallCount ++; + modioAddFilterInField(&modio_filter_creator, "id", toString(InstalledMod.Mod.Id).c_str()); + if(CurrentCallCount % 100 == 0) + { + UE_LOG(LogTemp, Warning, TEXT("[mod.io] Calling modioGetAllMods")); + CurrentCallCount = 0; + modioGetAllMods(Request, modio_filter_creator, FModioAsyncRequest_UninstallUnavailableMods::Response); + + modioFreeFilter(&modio_filter_creator); + modioInitFilter(&modio_filter_creator); + } + } + if(CurrentCallCount > 0) + { + UE_LOG(LogTemp, Warning, TEXT("[mod.io] Calling final modioGetAllMods")); + modioGetAllMods(Request, modio_filter_creator, FModioAsyncRequest_UninstallUnavailableMods::Response); + modioFreeFilter(&modio_filter_creator); + } +} + void onModDownload(u32 response_code, u32 mod_id) { FModioSubsystem::ModioOnModDownloadDelegate.ExecuteIfBound( (int32)response_code, (int32)mod_id ); diff --git a/Source/modio/Private/ModioUE4Utility.cpp b/Source/modio/Private/ModioUE4Utility.cpp index 8b71241..4154272 100644 --- a/Source/modio/Private/ModioUE4Utility.cpp +++ b/Source/modio/Private/ModioUE4Utility.cpp @@ -329,4 +329,24 @@ void SetupModioModfileCreator(FModioModfileCreator ModfileCreator, ModioModfileC modioSetModfileCreatorChangelog(&modio_modfile_creator, TCHAR_TO_UTF8(*ModfileCreator.Changelog)); if (ModfileCreator.Filehash != "") modioSetModfileCreatorFilehash(&modio_modfile_creator, TCHAR_TO_UTF8(*ModfileCreator.Filehash)); +} + +std::string toString(int32 number) +{ + if (number == 0) + return "0"; + + if (number < 0) + return "-" + toString(-number); + + std::string temp = ""; + std::string returnvalue = ""; + while (number > 0) + { + temp += number % 10 + 48; + number /= 10; + } + for (size_t i = 0; i < temp.length(); i++) + returnvalue += temp[temp.length() - i - 1]; + return returnvalue; } \ No newline at end of file diff --git a/Source/modio/Public/AsyncRequest/ModioAsyncRequest_UninstallUnavailableMods.h b/Source/modio/Public/AsyncRequest/ModioAsyncRequest_UninstallUnavailableMods.h new file mode 100644 index 0000000..f2e6d09 --- /dev/null +++ b/Source/modio/Public/AsyncRequest/ModioAsyncRequest_UninstallUnavailableMods.h @@ -0,0 +1,26 @@ +// Copyright 2019 modio. All Rights Reserved. +// Released under MIT. + +#pragma once +#include "AsyncRequest/ModioAsyncRequest.h" +#include "Schemas/ModioResponse.h" +#include "Schemas/ModioMod.h" + +/** +* Callback returned when all unavailable mods were uninstalled +* @param ModioResponse - Response from Modio backend +*/ + +class FModioAsyncRequest_UninstallUnavailableMods : public FModioAsyncRequest +{ +public: + int32 PendingCalls; + TArray AvailableMods; + + FModioAsyncRequest_UninstallUnavailableMods( FModioSubsystem *Modio, FModioGenericDelegate Delegate, int32 PendingCalls ); + + static void Response(void *Object, ModioResponse ModioResponse, ModioMod *ModioMods, u32 ModioModsSize); + +private: + FModioGenericDelegate ResponseDelegate; +}; \ No newline at end of file diff --git a/Source/modio/Public/BlueprintCallbackProxies/CallbackProxy_UninstallUnavailableMods.h b/Source/modio/Public/BlueprintCallbackProxies/CallbackProxy_UninstallUnavailableMods.h new file mode 100644 index 0000000..10b42a8 --- /dev/null +++ b/Source/modio/Public/BlueprintCallbackProxies/CallbackProxy_UninstallUnavailableMods.h @@ -0,0 +1,39 @@ +// Copyright 2019 modio. All Rights Reserved. +// Released under MIT. + +#pragma once + +#include "ModioUE4Utility.h" +#include "Customizables/ModioFilterCreator.h" +#include "Schemas/ModioResponse.h" +#include "Schemas/ModioMod.h" +#include "Net/OnlineBlueprintCallProxyBase.h" +#include "CallbackProxy_UninstallUnavailableMods.generated.h" + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( + FUninstallUnavailableModsResult, + FModioResponse, + Response); + +UCLASS() +class MODIO_API UCallbackProxy_UninstallUnavailableMods : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // The world context object in which this call is taking place + UPROPERTY() + UObject* WorldContextObject; + + UPROPERTY(BlueprintAssignable) + FUninstallUnavailableModsResult OnSuccess; + + UPROPERTY(BlueprintAssignable) + FUninstallUnavailableModsResult OnFailure; + + UFUNCTION(BlueprintCallable, Category = "mod.io", meta = (BlueprintInternalUseOnly = "true", DefaultToSelf="WorldContext")) + static UCallbackProxy_UninstallUnavailableMods *UninstallUnavailableMods(UObject *WorldContext); + + virtual void Activate() override; + + virtual void OnUninstallUnavailableModsDelegate(FModioResponse Response); +}; \ No newline at end of file diff --git a/Source/modio/Public/ModioSubsystem.h b/Source/modio/Public/ModioSubsystem.h index 13d8373..3f0941d 100644 --- a/Source/modio/Public/ModioSubsystem.h +++ b/Source/modio/Public/ModioSubsystem.h @@ -37,6 +37,7 @@ #include "AsyncRequest/ModioAsyncRequest_GetUserModfiles.h" #include "AsyncRequest/ModioAsyncRequest_GetUserRatings.h" #include "AsyncRequest/ModioAsyncRequest_SubscribeToMod.h" +#include "AsyncRequest/ModioAsyncRequest_UninstallUnavailableMods.h" #include "AsyncRequest/ModioAsyncRequest_UnsubscribeFromMod.h" #include "AsyncRequest/ModioAsyncRequest_SteamAuth.h" #include "AsyncRequest/ModioAsyncRequest_SubmitReport.h" @@ -175,6 +176,8 @@ struct MODIO_API FModioSubsystem : public TSharedFromThis