void FOnlineAchievementsGameCircle::WriteAchievements( const FUniqueNetId& PlayerId, FOnlineAchievementsWriteRef& WriteObject, const FOnAchievementsWrittenDelegate& Delegate )
{		
	if (AndroidSubsystem->GetCallbackManager() == nullptr || AndroidSubsystem->GetIdentityGameCircle()->GetLoginStatus(0) != ELoginStatus::LoggedIn)
	{
		WriteObject->WriteState = EOnlineAsyncTaskState::Failed;
		Delegate.ExecuteIfBound(PlayerId, false);
		return;
	}


	for (FStatPropertyArray::TConstIterator It(WriteObject->Properties); It; ++It)
	{
		// Access the stat and the value.
		const FVariantData& Stat = It.Value();

		// Create an achievement object which should be reported to the server.
		const FString AchievementId(It.Key().ToString());
		float PercentComplete = 0.0f;

		// Setup the percentage complete with the value we are writing from the variant type
		switch (Stat.GetType())
		{
		case EOnlineKeyValuePairDataType::Int32:
			{
				int32 Value;
				Stat.GetValue(Value);
				PercentComplete = (float)Value;
				break;
			}
		case EOnlineKeyValuePairDataType::Float:
			{
				float Value;
				Stat.GetValue(Value);
				PercentComplete = Value;
				break;
			}
		default:
			{
				UE_LOG(LogOnline, Error, TEXT("FOnlineAchievementsGameCircle Trying to write an achievement with incompatible format. Not a float or int"));
				break;
			}
		}

		AmazonGames::AchievementsClientInterface::updateProgress(FOnlineSubsystemGameCircle::ConvertFStringToStdString(AchievementId).c_str(), 
																	PercentComplete, new FOnlineUpdateProgressCallback(AndroidSubsystem));
	}

	Delegate.ExecuteIfBound(PlayerId, true);
}
void FOnlineAchievementsSteam::OnWriteAchievementsComplete(const FUniqueNetIdSteam& PlayerId, bool bWasSuccessful, FOnlineAchievementsWritePtr& WriteObject, const FOnAchievementsWrittenDelegate& Delegate)
{
	// write object should be valid
	check(WriteObject.IsValid());

	// if write completed successfully, unlock the achievements (and update their cache)
	if (bWasSuccessful)
	{
		TArray<FOnlineAchievement> * PlayerAch = PlayerAchievements.Find(PlayerId);
		check(PlayerAch);	// were we writing for a non-existing player?
		if (NULL != PlayerAch && WriteObject.IsValid())
		{
			// treat each achievement as unlocked
			const int32 AchNum = PlayerAch->Num();
			for (FStatPropertyArray::TConstIterator It(WriteObject->Properties); It; ++It)
			{
				const FString AchievementId = It.Key().ToString();
				for (int32 AchIdx = 0; AchIdx < AchNum; ++AchIdx)
				{
					if ((*PlayerAch)[ AchIdx ].Id == AchievementId)
					{
						// Update and trigger the callback
						(*PlayerAch)[ AchIdx ].Progress = 100.0;
						TriggerOnAchievementUnlockedDelegates(PlayerId, (*PlayerAch)[ AchIdx ].Id);
						break;
					}
				}
			}
		}
	}

	Delegate.ExecuteIfBound(PlayerId, bWasSuccessful);
}
void FOnlineAchievementsNull::WriteAchievements(const FUniqueNetId& PlayerId, FOnlineAchievementsWriteRef& WriteObject, const FOnAchievementsWrittenDelegate& Delegate)
{
    if (!ReadAchievementsFromConfig())
    {
        // we don't have achievements
        WriteObject->WriteState = EOnlineAsyncTaskState::Failed;
        Delegate.ExecuteIfBound(PlayerId, false);
        return;
    }

    FUniqueNetIdString NullId(PlayerId);
    const TArray<FOnlineAchievement> * PlayerAch = PlayerAchievements.Find(NullId);
    if (NULL == PlayerAch)
    {
        // achievements haven't been read for a player
        WriteObject->WriteState = EOnlineAsyncTaskState::Failed;
        Delegate.ExecuteIfBound(PlayerId, false);
        return;
    }

    // treat each achievement as unlocked
    const int32 AchNum = PlayerAch->Num();
    for (FStatPropertyArray::TConstIterator It(WriteObject->Properties); It; ++It)
    {
        const FString AchievementId = It.Key().ToString();
        for (int32 AchIdx = 0; AchIdx < AchNum; ++AchIdx)
        {
            if ((*PlayerAch)[ AchIdx ].Id == AchievementId)
            {
                TriggerOnAchievementUnlockedDelegates(PlayerId, AchievementId);
                break;
            }
        }
    }

    WriteObject->WriteState = EOnlineAsyncTaskState::Done;
    Delegate.ExecuteIfBound(PlayerId, true);
};
void FOnlineAchievementsSteam::WriteAchievements(const FUniqueNetId& PlayerId, FOnlineAchievementsWriteRef& WriteObject, const FOnAchievementsWrittenDelegate& Delegate)
{
	if (!bHaveConfiguredAchievements)
	{
		// we don't have achievements
		UE_LOG_ONLINE(Warning, TEXT("Steam achievements have not been configured in .ini"));

		WriteObject->WriteState = EOnlineAsyncTaskState::Failed;
		Delegate.ExecuteIfBound(PlayerId, false);
		return;
	}

	FUniqueNetIdSteam SteamId(PlayerId);
	// check if this is our player (cannot report for someone else)
	if (SteamUser() == NULL || SteamUser()->GetSteamID() != SteamId)
	{
		// we don't have achievements
		UE_LOG_ONLINE(Warning, TEXT("Cannot report Steam achievements for non-local player %s"), *PlayerId.ToString());

		WriteObject->WriteState = EOnlineAsyncTaskState::Failed;
		Delegate.ExecuteIfBound(PlayerId, false);
		return;
	}

	const TArray<FOnlineAchievement> * PlayerAch = PlayerAchievements.Find(SteamId);
	if (NULL == PlayerAch)
	{
		// achievements haven't been read for a player
		UE_LOG_ONLINE(Warning, TEXT("Steam achievements have not been read for player %s"), *PlayerId.ToString());

		WriteObject->WriteState = EOnlineAsyncTaskState::Failed;
		Delegate.ExecuteIfBound(PlayerId, false);
		return;
	}

	const int32 AchNum = PlayerAch->Num();
	for (FStatPropertyArray::TConstIterator It(WriteObject->Properties); It; ++It)
	{
		const FString AchievementId = It.Key().ToString();
		UE_LOG_ONLINE(Verbose, TEXT("WriteObject AchievementId: '%s'"), *AchievementId);
		for (int32 AchIdx = 0; AchIdx < AchNum; ++AchIdx)
		{
			if ((*PlayerAch)[ AchIdx ].Id == AchievementId)
			{
				// do not unlock it now, but after a successful write
#if !UE_BUILD_SHIPPING
				float Value = 0.0f;
				It.Value().GetValue(Value);
				if (Value <= 0.0f)
				{
					UE_LOG_ONLINE(Verbose, TEXT("Resetting achievement '%s'"), *AchievementId);
					SteamUserStats()->ClearAchievement(TCHAR_TO_UTF8(*AchievementId));
				}
				else
				{
#endif // !UE_BUILD_SHIPPING

					UE_LOG_ONLINE(Verbose, TEXT("Setting achievement '%s'"), *AchievementId);
					SteamUserStats()->SetAchievement(TCHAR_TO_UTF8(*AchievementId));

#if !UE_BUILD_SHIPPING
				}
#endif // !UE_BUILD_SHIPPING
			
				break;
			}
		}
	}

	StatsInt->WriteAchievementsInternal(SteamId, WriteObject, Delegate);
};