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<int32> getInstalledMods() +{ + TArray<int32> 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<UCallbackProxy_UninstallUnavailableMods>(); + 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<int32> 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<int32> 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<FModioSubsystem, ESPMo void DownloadSubscribedModfiles(bool UninstallUnsubscribed, FModioBooleanDelegate DownloadSubscribedModfilesDelegate); /** Uninstalls a mod from local storage */ bool UninstallMod(int32 ModId); + /** Uninstall all deleted or hidden mods */ + void UninstallUnavailableMods(FModioGenericDelegate UninstallUnavailableModsDelegate); // Mod Subscription /** Subscribes to the corresponding mod */ diff --git a/Source/modio/Public/ModioUE4Utility.h b/Source/modio/Public/ModioUE4Utility.h index 868b880..bff2c07 100644 --- a/Source/modio/Public/ModioUE4Utility.h +++ b/Source/modio/Public/ModioUE4Utility.h @@ -16,6 +16,7 @@ #include "Customizables/ModioModEditor.h" #include "Customizables/ModioModfileCreator.h" #include "Customizables/ModioFilterCreator.h" +#include <string> extern TArray<FModioMod> ConvertToTArrayMods(ModioMod* ModioMods, u32 ModsSize); extern TArray<FModioModfile> ConvertToTArrayModfiles(ModioModfile* ModioModfiles, u32 ModfilesSize); @@ -31,4 +32,5 @@ extern void SetupModioFilterPagination(int32 Limit, int32 Offset, ModioFilterCre extern void SetupModioModFilterCreator(const FModioFilterCreator &FilterCreator, const TArray<FString> &ModTags, int32 Limit, int32 Offset, ModioFilterCreator& modio_filter_creator); extern void SetupModioModCreator(FModioModCreator ModCreator, ModioModCreator& modio_mod_creator); extern void SetupModioModEditor(FModioModEditor ModEditor, ModioModEditor& modio_mod_editor); -extern void SetupModioModfileCreator(FModioModfileCreator ModfileCreator, ModioModfileCreator& modio_modfile_creator); \ No newline at end of file +extern void SetupModioModfileCreator(FModioModfileCreator ModfileCreator, ModioModfileCreator& modio_modfile_creator); +std::string toString(int32 number); \ No newline at end of file