Array returns bad values only first time - c++

So I'm working with Steamworks (leaderboards) and i have some strange issue. When i fire my function to get scores, from debugging i know that it works just fine.However my array after 1st function run always returns default values.After I fire function for the second time everything works perfectly fine. I tried to track down the issue however i failed.
Here is my whole code that i am using in this case:
Struct for stats
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;
};
Function that sent request to the steam:
.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;
}
Now callback function from steam:
.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;
}
}
And finally function that write scores in Array:
.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 array is just static TArray Scores and scores=true is only for latent check to go on with functions after calling DownloadScoresAroundUser :)
My normal flow with this is:
1.I already have handle for leaderboard.
2.I'm calling DownloadScoresAroundUser.
3.Flow goes to latent which cannot proceed becouse of scores=false.
4.After i got callback from steam OnDownloadScore fires, giving me all needed info(checked if really and it does!).
5.Then i call TranslateEntries to get all scores with names and rank in Array.
6.Then I'm printing whole array (with break package in unreal) and get default values of my struct.
7.After i fire whole cycle again i get proper values.
If any further info is required let me know :)

This is a bit of a guess, but it appears that you have a latency issue. When you make the request to download the scores, this is a time consuming call that does not block. You set up a callback that will be called when the scores are ready, then return the existing empty Scores object.
When you make your second call, enough time has passed for the scores to have download and Scores to be populated, so it returns some scores.
Note that you have a potential race condition, where DownloadScoresAroundUser can access (return) Scores while your callback is populating that vector.
Here's one possible solution. Before the scores have completed loading, DownloadScoresAroundUser returns an empty Score (or possibly one indicating that scores are being loaded). Once the scores have been loaded and Scores populated, it will return those. Also, the callback (besides populating Scores) can in some fashion notify the caller(s) of DownloadScoresAndUser that new scores are available. They can respond to that by calling in again to get the updated scores and refresh the display.

Translateentries copy data from 0 to 30 but only "Callback->m_cEntryCount" are actually initialized. So if it < at 30, the data from "Callback->m_cEntryCount" to 30 may be wrong. Can you print out the value of this variable "in SteamLeaderboard::OnDownloadScore" ?

Related

how to check if personID is in my_customers (see my example)

In C++, the interface for this file says
*If no soup left returns OUT_OF_SOUP
* If personID not found in my_customers AND numbBowlsSoupLeft>0 then give this person a bowl of soup (return BOWL_OF_SOUP)
* and record it by creating new customer struct using personID, numbBowlsSoup=1 and adding this struct to my_customers, be sure to decrement numbBowlsSoupLeft.
for my implementation, I'm trying to put
int Soupline::getSoup(int personID) {
if (numBowlsSoupLeft == 0) {
return OUT_OF_SOUP;
}
if (!(personID : my_customers) && numbBowlsSoupLeft > 0) {
}
But that second if statement is giving me syntax errros, I just want to know how to check to see if the personID is IN my_customers?
my_customers was created in the soupline interface using:
std::vector<customer> my_customers; // keeps track of customers
First you want to use find() to search a vector.
Second, please handle the case if numbBowlsSoupLeft < 0, because that can be a huge source of problem.
Third, your syntax error is the (personID : my_customers), the : is for iteration.
int Soupline::getSoup(int personID) {
if (numBowlsSoupLeft <= 0) { // handles negative numBowlsSoupLeft
return OUT_OF_SOUP;
}
bool found_customer = false;
for (auto c : my_customers) {
if (personID == c.person_id()) { // This is my guess on how the id is stored in customer class
// Logic to process soup for customer
found_customer = true;
break;
}
}
if (!found_customer) {
// Logic to process non-customer asking for soup?
}
}
Sorry i dunno what is the return integer is supposed to be, so it is not defined in my code example.

multiple lists into a map

I had a question regarding my code below. I'm reading a file containing lots of data of which some stuff is irrelevant. The data is written out on one line, so I cannot use nextLine or something.
For each vertex, I save the relevant information into dataperpoint. When I go to the next vertex, I want to clear the list to fill it with new relevant information.
The issue that I have is that each time I clear dataperpoint, all values in Map get cleared. When I then try to fill it, all previous positions in the Map get the same values.
How can I do this and make sure that each vertex will get his own list?
Looking forward to your suggestions!
public static Map<Integer, List<Double>> readData(File f) // throws IO exception?
{
// Create Map to store the vertex and list with relevant information in
List<Double> dataperpoint = new ArrayList<Double>();
Map<Integer, List<Double>> data = new HashMap<>();
// Open the scanner
try (Scanner in = new Scanner(f))
{
// To make sure the correct localization is used
in.useLocale(Locale.US);
// The first six integers contain irrelevant information
for (int step = 1; step <= 6; step++)
{
in.nextInt();
}
// Do the information for vertex 0 separately, since it has one data point less
int vertex = in.nextInt();
for (int doubleinfo = 1; doubleinfo <= 4; doubleinfo++) // six relevant variables
{
dataperpoint.add(in.nextDouble());
}
// irrelevant information
for (int irrelevantinfo = 1; irrelevantinfo <= 2; irrelevantinfo++)
{
in.nextInt();
}
// Opening and Closing of time window
dataperpoint.add((double) in.nextInt());
dataperpoint.add((double) in.nextInt());
data.put(vertex, dataperpoint);
while (in.hasNext()) // think of different statement later
{
dataperpoint = new ArrayList<Double>();
vertex = in.nextInt();
for (int doubleinfo = 1; doubleinfo <= 4; doubleinfo++) // six relevant variables
{
dataperpoint.add(in.nextDouble());
}
// irrelevant information
for (int irrelevantinfo = 1; irrelevantinfo <= 3; irrelevantinfo++)
{
in.nextInt();
}
// Opening and Closing of time window
dataperpoint.add((double) in.nextInt());
dataperpoint.add((double) in.nextInt());
data.put(vertex, dataperpoint);
}
in.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
Use LinkedHashMap<> instead of HashMap<> it should solve your problem. Read this Difference between HashMap, LinkedHashMap and TreeMap

Count of CheckBoxList items selected isn't being calculated correctly

I'm currently trying to get a count of a CheckBoxList to use in conjunction with an if and else statement for a project. If the count is not equal to 2 I have a label that prompts the user to select two modules but the count isn't being calculated properly. Any help would be appreciated. Here is the code in question:
protected void RegisterButton_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["UniString"].ConnectionString);
//This integer will hold the number of modules selected
Int32 amount = 0;
for (int i = 0; i < CheckBoxList1.Items.Count; i++)
{
//amount will increment each time a module checkbox is checked
if (CheckBoxList1.Items[i].Selected)
{
amount = amount++;
}
//If amount is not equal to 2 the code below will run
if (amount != 2)
{
//If the number of modules selected is not equal to 2 then this message is displayed and the background of the label in the markup is turned red to draw attention
ModuleSelectionMessage.Text = "Please select 2 modules to successfully register";
ModuleSelectionMessage.BackColor = System.Drawing.Color.Red;
}
else
{...
amount = amount++ is not assign amount value properly,
use amount++ or amount= amount + 1 instead of that..
for (int i = 0; i < CheckBoxList1.Items.Count; i++)
{
//amount will increment each time a module checkbox is checked
if (CheckBoxList1.Items[i].Selected)
{
amount = amount + 1;
}
//other code...
}

Value of an object will not be changed

I created a method which should change values in my shop object. Unfortunately the values are not changed.
edit: 18:13
I could create a new shop object and return it, but I thought it should work with passing the object by reference?
To make my question clearer: My only problem is, that the new values are not stored in the object. I did run the debugging and the values are all correctly calculated and as expected.
The problem is in the lines:
shop.get_stock().push_back(inventory_bonbon);
This line should push a new inventory item to the vector (containing the inventory items), if this inventory item is currently not in stock.
Here I increase the amount of an inventory item, when the item is currently in stock:
i_inventory_shop.increase_amount(shop.get_stock()[i], amount);
(I have unit-tested the increase_amount() method and it works fine.)
The two lines are called as expected (meaning I find when an item is in stock or not).
void IRooms::increase_inventory_shop(Shop & shop, Bonbon & bonbon, int amount)
{
OutputDebugString("I_Game Logic increase_inventory_shop called \n");
IInventoryItemsBonbons i_inventory_shop;
bool bonbon_in_shop = false;
for (int i = 0; i < shop.get_stock().size(); i++)
{
OutputDebugString(("I_Game Logic shop vector size \n" + std::to_string(shop.get_stock().size()) + "\n").c_str());
OutputDebugString(("I_Game Logic bonbon name \n" + bonbon.get_name() + "\n").c_str());
OutputDebugString(("I_Game Logic bonbon amount \n" + std::to_string(amount) + "\n").c_str());
if (bonbon.get_name() == shop.get_stock()[i].get_bonbon().get_name())
{
bonbon_in_shop = true;
OutputDebugString("Bonbon found \n");
i_inventory_shop.increase_amount(shop.get_stock()[i], amount);
break;
}
}
if (bonbon_in_shop == false) {
OutputDebugString("Bonbon not found \n");
InventoryItemBonbons inventory_bonbon = i_inventory_shop.create(amount, bonbon);
shop.get_stock().push_back(inventory_bonbon);
}
}
This method calls: (the method below, I have tested it)
void IInventoryItemsBonbons::increase_amount(InventoryItemBonbons & inventoryitem_shop, int amount)
{
int old_amount = inventoryitem_shop.get_amount();
int new_amount = old_amount + amount;
inventoryitem_shop.set_amount(new_amount);
}
edit 17:51:
Shop.h
std::vector<InventoryItemBonbons> get_stock();
Shop.ccp
std::vector<InventoryItemBonbons> Shop::get_stock()
{
return stock_bonbons;
}
_____________________________________________________________________________edit: 19:54
I have now introduced local variables and I return the local shop.
Shop IRooms::increase_inventory_shop(Shop & shop, Bonbon & bonbon, int amount)
{
Shop shop_temp = shop;
std::vector<InventoryItemBonbons> inventory_items_temp = shop.get_stock();
IInventoryItemsBonbons i_inventory_shop;
bool bonbon_in_shop = false;
for (int i = 0; i < shop_temp.get_stock().size(); i++)
{
if (bonbon.get_name() == shop_temp.get_stock()[i].get_bonbon().get_name())
{
bonbon_in_shop = true;
i_inventory_shop.increase_amount(inventory_items_temp[i], amount);
break;
}
}
if (bonbon_in_shop == false) {
InventoryItemBonbons inventory_bonbon = i_inventory_shop.create(amount, bonbon);
inventory_items_temp.push_back(inventory_bonbon);
}
shop_temp.set_stock(inventory_items_temp);
//shop = shop_temp;
//return shop;
return shop_temp;
}
The only thing I want to know, why the values of shop won't change. I have tried to copy shop_temp to shop, but even this does not work.
std::vector<InventoryItemBonbons> get_stock();
Since get_stock returns by value, not by reference, any changes to the value returned will be lost as soon as that temporary goes out of scope.
shop.get_stock().push_back(inventory_bonbon);
So this modifies the temporary returned by get_stock, which immediately goes out of scope, is destroyed, and the modification is lost.
You probably wanted:
std::vector<InventoryItemBonbons>& get_stock();
...
std::vector<InventoryItemBonbons>& Shop::get_stock()
{
return stock_bonbons;
}

Creating new objects in C++ function causes program to crash

I have a program which allows the user to play Dominoes against 3 CPU players, with varying difficulty. Each CPU player can be either Beginner, Intermediate or Expert, and each difficulty has it's own class. If I initiate my 3 CPU players at the beginning of my 'Window' class (below), the program runs fine.
In Window.h
public:
Window(QWidget *parent = 0);
Intermediate *cpu1;
Beginner *cpu2;
Intermediate *cpu3;
In Window.cpp
Window::Window(QWidget *parent):QDialog(parent) {
cpu1 = new Intermediate;
cpu2 = new Beginner;
cpu3 = new Intermediate;
}
However I want the user to be able to select the CPU difficulties at the beginning of the game, so I now have a function within 'Window' that creates the objects. As soon as I call this function the game freezes and I get an error message pop up saying telling me the program has ended unexpectedly.
void Window:: startGame(){
cpu1 = new Intermediate;
cpu2 = new Beginner;
cpu3 = new Intermediate;
}
If anyone would be able to explain to me what is going on and what I can do to get around this that would be great.
Intermediate.cpp (Beginner.cpp is almost identical)
#include "intermediate.h"
Intermediate::Intermediate()
{
tilePlaced = false;
skipGo = false;
}
void Intermediate::findDoubles(int a[7][2]){
for(int i = 0; i < 7; i++){ // Creates new doubles list after each go.
doublesList[i] = 0;
}
for(int i = 0; i < 7; i++){ // Creates a list of doubles
if ((a[i][0] == a[i][1]) && (a[i][0] != 7)){
doublesList[a[i][0]] = 1;
}
}
}
bool Intermediate::addDomino(){} // Function that finds best domino to replace and returns bool
if(tilePlaced == false){
pass++;
text += "\nPassed turn";
return false;
}
else{
pass = 0;
text += QString("\nPlaced [%1 : %2]").arg(a).arg(b);
return true;
}
}
One way to start would be to narrow down which class is causing the fault. Does it work if they are all Beginner, or if they are all Intermediate? If so then the other one is causing the problem.