Массив возвращает неверные значения только в первый раз

Итак, я работаю со Steamworks (таблицы лидеров), и у меня возникла странная проблема. Когда я запускаю свою функцию, чтобы получить оценки, из отладки я знаю, что она работает просто отлично. Однако мой массив после первого запуска функции всегда возвращает значения по умолчанию. После того, как я запускаю функцию во второй раз, все работает отлично. Я пытался отследить проблему, однако мне это не удалось.

Вот весь мой код, который я использую в этом случае:

Структура для статистики

 USTRUCT(BlueprintType)
    struct FScorePackage
    {
        GENERATED_BODY()

            UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Leaderboard")
            FString PlayerName = "working";

        UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Leaderboard")
            int32 Rank = 0;

        UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Leaderboard")
            int32 Score = 0;

    };

Функция, отправившая запрос в стим: .h

UFUNCTION(BlueprintCallable, Category = "Steam|Leaderboard", meta = (Latent, LatentInfo = "LatentInfo", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"))
        TArray<FScorePackage> DownloadScoresAroundUser(UObject* WorldContextObject, int AboveUser, int BelowUser, struct FLatentActionInfo LatentInfo);

.cpp

TArray<FScorePackage> USteamLeaderboard::DownloadScoresAroundUser(UObject* WorldContextObject, int AboveUser, int BelowUser, struct FLatentActionInfo LatentInfo)
{
    if (!m_CurrentLeaderboard)
    {
        return Scores;
    }

    if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject))
    {
        FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
        if (LatentActionManager.FindExistingAction<SteamLeaderboardLatentClass>(LatentInfo.CallbackTarget, LatentInfo.UUID) == NULL)
        {
            // load the specified leaderboard data around the current user
            SteamAPICall_t hSteamAPICall = SteamUserStats()->DownloadLeaderboardEntries(m_CurrentLeaderboard, k_ELeaderboardDataRequestGlobalAroundUser, -AboveUser, BelowUser);
            m_callResultDownloadScore.Set(hSteamAPICall, this,&USteamLeaderboard::OnDownloadScore);
            LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new SteamLeaderboardLatentClassScores(LatentInfo));

            return Scores;
        }
        return Scores;
    }
    return Scores;
}

Теперь функция обратного вызова из стима: .h

void OnDownloadScore(LeaderboardScoresDownloaded_t *pResult, bool bIOFailure);
    CCallResult <USteamLeaderboard, LeaderboardScoresDownloaded_t> m_callResultDownloadScore;

.cpp

void USteamLeaderboard::OnDownloadScore(LeaderboardScoresDownloaded_t *pCallback, bool bIOFailure)
{
    if (!bIOFailure)
    {
        m_nLeaderboardEntries = __min(pCallback->m_cEntryCount, 30);

        for (int index = 0; index < m_nLeaderboardEntries; index++)
        {
            SteamUserStats()->GetDownloadedLeaderboardEntry(pCallback->m_hSteamLeaderboardEntries, index, &m_leaderboardEntries[index], NULL, 0);
        }
        TranslateEntries();
        scores = true;


    }
}

И, наконец, функция, записывающая оценки в массив:

.h

UFUNCTION(BlueprintCosmetic, Category = "Steam|Leaderboard")
         TArray<FScorePackage> TranslateEntries();

.cpp

    TArray<FScorePackage> USteamLeaderboard::TranslateEntries()
    {
FScorePackage ThisScore;
        Scores.Init(ThisScore, 30);

        for (int i = 0; i < 30; i++)
        {
            ThisScore.PlayerName = GetSteamName(m_leaderboardEntries[i].m_steamIDUser);
            ThisScore.Rank = m_leaderboardEntries[i].m_nGlobalRank;
            ThisScore.Score = m_leaderboardEntries[i].m_nScore;
            Arrayas[i] = ThisScore;
        }
        return Scores;

    }

Массив Scores является просто статическим TArray Scores и scores=true только для скрытой проверки, которая будет выполняться с функциями после вызова DownloadScoresAroundUser :)

Мой обычный порядок действий при этом таков: 1. У меня уже есть дескриптор таблицы лидеров. 2. Я звоню в DownloadScoresAroundUser. 3. Поток переходит в латентный режим, который не может продолжаться из-за scores=false. 4. После того, как я получил обратный вызов от Steam, OnDownloadScore срабатывает, предоставляя мне всю необходимую информацию (проверено, действительно ли это так!). 5. Затем я вызываю TranslateEntries, чтобы получить все оценки с именами и рейтингом в массиве. 6. Затем я печатаю весь массив (с пакетом break в нереальном) и получаю значения по умолчанию для моей структуры. 7. После повторного запуска всего цикла я получаю правильные значения.

Если потребуется дополнительная информация, дайте мне знать :)


person Avengar    schedule 10.07.2017    source источник
comment
ОТ наверное, но почему повторяющийся return Scores;? На в конце концов будет достаточно.   -  person user0042    schedule 11.07.2017
comment
ОТ? Я повторял это, потому что раньше это была логическая функция, и всегда возникала ошибка: не все пути возвращают значение. Думаю, я должен изменить записи перевода на void. Могут ли эти возвраты повлиять на мой код? Я имею в виду, что возврат выходит из строя, верно?   -  person Avengar    schedule 11.07.2017
comment
Все 3 возвращаемых значения одинаковы, а операторы return избыточны. Я не знаю, влияет ли это на вашу фактическую ошибку (даже сомневаюсь). Поэтому я сказал, что мой комментарий /OT относится к вашему фактическому вопросу.   -  person user0042    schedule 11.07.2017


Ответы (2)


Это небольшое предположение, но похоже, что у вас проблема с задержкой. Когда вы делаете запрос на загрузку результатов, это трудоемкий вызов, который не блокируется. Вы настраиваете обратный вызов, который будет вызываться, когда оценки будут готовы, а затем возвращает существующий пустой объект Scores.

Когда вы делаете второй вызов, прошло достаточно времени, чтобы баллы были загружены и Scores были заполнены, поэтому он возвращает некоторые баллы.

Обратите внимание, что у вас есть потенциальное состояние гонки, когда DownloadScoresAroundUser может получить доступ (возврат) Scores, пока ваш обратный вызов заполняет этот вектор.

Вот одно из возможных решений. До завершения загрузки партитуры DownloadScoresAroundUser возвращает пустую партитуру (или, возможно, такую, указывающую, что партитура загружается). Как только партитуры будут загружены и Scores заполнены, он вернет их. Кроме того, обратный вызов (помимо заполнения Scores) может каким-то образом уведомлять вызывающего(их) DownloadScoresAndUser о том, что доступны новые оценки. Они могут отреагировать на это, позвонив еще раз, чтобы получить обновленные результаты и обновить дисплей.

person 1201ProgramAlarm    schedule 11.07.2017
comment
Последнее предложение верно. Сначала верните огонь. Прежде чем даже OnDownloadScores и весь остальной код! Вы знаете, может быть, какой-нибудь хороший способ исправить это? Должен ли я просто сделать еще одну функцию, которая возвращает только массив, или есть способ изменить существующую? - person Avengar; 11.07.2017
comment
Сообщение @Avengar отредактировано с подробностями возможного решения. - person 1201ProgramAlarm; 12.07.2017

Translateentries копирует данные от 0 до 30, но фактически инициализируются только «Callback->m_cEntryCount». Так что, если это ‹ на 30, данные от "Callback->m_cEntryCount" до 30 могут быть неправильными. Можете ли вы распечатать значение этой переменной "в SteamLeaderboard::OnDownloadScore"?

person roug    schedule 10.07.2017
comment
Исправление чисел не является проблемой, потому что у меня сейчас только 3 балла для тестовых целей. Отдых всегда по умолчанию. И когда я печатал, все было просто отлично :/ - person Avengar; 11.07.2017