Issue reading from file.

Hey! I'm writing a function for my game.

This function reads data from a file and stores it into a structure, which then is stored to a vector.

Here is my code:
1
2
3
4
5
6
//These variables are defined prior to being used in the function
        const int MAX_INVENTORY_PAGES = 2;
        ifstream inventoryDataFile;
        bool endOfFile;
	string temp;
	int tempNum;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
Inventory * LoadFromFile::loadInventoryData()
{
	endOfFile = false;
	temp = "";
	tempNum = NULL;

	Slot* slots = new Slot;


	inventoryDataFile.open(inventoryDataFilePath);

	if (inventoryDataFile.fail())
	{
		cout << "\n Failed to open level.data.txt!\n";
		pause();
		exit(1);
	}
	else
	{
		cout << "\n\t\t\t\t\t\t|"
			<< "\n File successfully opened!\t\t\t|"
			<< "\n\t\t\t\t\t\t|";
	}

	static Inventory inventory[MAX_INVENTORY_PAGES];

	cout << "\nLoading " << MAX_INVENTORY_PAGES << " inventory pages...\t\t\t\t|"
		<< "\n\t\t\t\t\t\t|";


	for (int count = 0; !endOfFile; count++)
	{
		cout << "\n 1";
		getline(inventoryDataFile, temp, '#');
		inventoryDataFile >> temp;
		tempNum = stoi(temp);

		if (tempNum == -1)
		{
			endOfFile = true;
			cout << "\n\n CLOSING";
			break;
		}
		inventory[count].inventoryPage = tempNum;

		getline(inventoryDataFile, temp, ':');
		inventoryDataFile >> inventory[count].inventoryTexturePath;
		cout << "\nSetting variables without file";
		inventory[count].Texture = TextureManager::loadTexture(inventory[count].inventoryTexturePath.c_str());

		inventory[count].renderCoordinates = { 0, 0, 640, 640 };

		inventory[count].currencyPosition = { 436, 501 };


		getline(inventoryDataFile, temp, '#');
		inventoryDataFile >> tempNum;
		//inventoryDataFile.ignore(numeric_limits<streamsize>::max(), '\n');


		cout << "\n Tempnum : " << tempNum;

		for (int index = 0; index < tempNum; index++)
		{
			cout << "\n\nTempnum: " << tempNum;
			cout << "\nindex " << index;

			getline(inventoryDataFile, temp, ':');
			inventoryDataFile >> slots->position;
			cout << "\n" << slots->position;
			inventoryDataFile.ignore(numeric_limits<streamsize>::max(), '\n');

			getline(inventoryDataFile, temp);
			getline(inventoryDataFile, temp, ':');
			inventoryDataFile >> slots->Rect.x;
			cout << "\n" << slots[index].Rect.x;
			getline(inventoryDataFile, temp, ':');
			inventoryDataFile >> slots->Rect.y;
			cout << "\n" << slots[index].Rect.y;
			getline(inventoryDataFile, temp, ':');
			inventoryDataFile >> slots->Rect.h;
			cout << "\n" << slots[index].Rect.h;
			getline(inventoryDataFile, temp, ':');
			inventoryDataFile >> slots->Rect.w;
			cout << "\n" << slots[index].Rect.w;

			getline(inventoryDataFile, temp, ':');
			inventoryDataFile >> slots->description;
			cout << "\n" << slots->description;

			inventory[count].slots.push_back(*slots);

			slots->description = "";
			slots->position = "";
			slots->Rect = { 0,0,0,0 };
		}

		cout << "\n\t\t\t\t\t\t|"
			<< "\nTotal number of slots: " << inventory[count].slots.size()
			<< "\t\t\t|"
			<< "\nInventory page number " << count << " Successfully loaded!"
			<< "\t\t\t|";
	}

	inventoryDataFile.close();
	if (inventoryDataFile.fail())
	{
		cout << "\n\n Failed closing inventoryDataFile.txt\n";
	}
	else
		cout << "\n\t\t\t\t\t\t|"
		<< "\n inventoryDataFile.txt closed...\t\t\t|"
		<< "\n\t\t\t\t\t\t|";


	delete slots;

	return inventory;
}


inventory is a structure:
1
2
3
4
5
6
7
8
9
10
struct Inventory
{
	int inventoryPage;
	string inventoryTexturePath;
	SDL_Texture *Texture;
	SDL_Rect renderCoordinates;
	vector<Slot> slots;
	SDL_Rect currencyPosition;
	MenuState StateOfMenu;
};


Slot is another one:
1
2
3
4
5
6
struct Slot
{
	string position;
	SDL_Rect Rect;
	string description;
};



You might be wondering, I'm working with SDL_2 which means
*SDL_Texture holds a png image
*SDL_Rect is a struct with 4 int in it { x, y, w, h} (x and y coordinates, height and width)
*the MenuState and TextureManager functions and variables are irrelevant to my problem, you can simply ignore them

My file contains the following:
___PAGE 0___
#0
Texture path:textures/inventoryScreen01.png
___END_OF_PAGE___
#2
Slot position:main_1
Position in inventory:
x:156
y:181
h:45
w:45
Slot description:slot_hat
Slot position:main_2
Position in inventory:
x:211
y:181
h:45
w:45
Slot description:slot_torso
END OF FILE
#-1


And my program output looks like that:

 File successfully opened!

Loading 2 inventory Pages...

 1
Setting variables without file
 Tempnum: 2

Tempnum: 2
index 0
main_1
156
181
45
45
slot_hat

Tempnum: 2
index 1
main_2
0
1
0
96
slot_torso

Total number of slots: 2
Inventory page number 0 Successfully loaded!
 1

 CLOSING

 inventoryDataFile.txt closed...


So I don't really understand what's going south. I think there is something wrong with the stream operations but it works fine for the first iteration of the inner for loop. I don't get what's not working on the second one.

Any insight is more than appreciated!

Thanks in advance,

Regards

Hugo.
Last edited on
This function reads data from a file and stores it into a structure, which then is stored to a vector.
I don't see a vector.

If you're calling open/close on an fstream, you're doing it wrong.

The be frank, the whole thing seems wrong. I would expect to see an something interface like:
1
2
3
4
typedef std::vector<Inventory> InventoryEntriesType;

InventoryEntriesType loadInventoryData(const std::string& filename);
InventoryEntriesType loadInventoryData(std::istream& input_stream);

We could then write:
1
2
3
4
5
InventoryEntriesType loadInventoryData(const std::string& filename)
{
    std::ifstream is(filename);
    return loadInventoryData(is); // InventoryEntriesType loadInventoryData(std::istream& input_stream) does the work
}


It's impossible to help further without seeing the definitions of Slot and Inventory.
Last edited on
I don't see a vector.
inventory[count].slots.push_back(*slots);


The be frank, the whole thing seems wrong. I would expect to see an something interface like:

As I said this is a function for a game, hence the function returning an Inventory object.


It's impossible to help further without seeing the definitions of Slot and Inventory.

They are in my post. I'll recopy them if that helps you:
1
2
3
4
5
6
7
8
9
10
struct Inventory
{
	int inventoryPage;
	string inventoryTexturePath;
	SDL_Texture *Texture;
	SDL_Rect renderCoordinates;
	vector<Slot> slots;
	SDL_Rect currencyPosition;
	MenuState StateOfMenu;
};

1
2
3
4
5
6
struct Slot
{
	string position;
	SDL_Rect Rect;
	string description;
};

Last edited on
I've taken your code and put into the structure I was thinking about. Something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <SDL2/SDL_render.h>
#include <string>
#include <vector>
#include <limits>
#include <istream>
#include <ostream>
#include <fstream>

enum MenuState { MS_Unknown }; // I added this, dunno what it ought to be

struct Slot
{
	std::string position;
	SDL_Rect Rect = { 0, 0, 0, 0 };
	std::string description;
};
std::ostream& saveOn(std::ostream& os, const Slot& n);
std::istream& restoreFrom(std::istream& is, Slot& n);

struct Inventory
{
	int inventoryPage;
	std::string inventoryTexturePath;
	SDL_Texture *Texture = nullptr;
	SDL_Rect renderCoordinates = { 0, 0, 640, 640 };
	std::vector<Slot> slots;
	SDL_Rect currencyPosition = { 436, 501 }; // expecting 4 fields
	MenuState StateOfMenu = MS_Unknown;
};
std::ostream& saveOn(std::ostream& os, const Inventory& n);
std::istream& restoreFrom(std::istream& is, Inventory& n);

//---------------------------------------------------------------------------
//
std::ostream& saveOn(std::ostream& os, const Slot& n)
{
	// I don't know what the file format is
	return os;
}

std::istream& restoreFrom(std::istream& is, Slot& n)
{
	// using your code ...
	std::string line;
	std::getline(is, line, ':'); is >> n.position;

	is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	std::getline(is, line, ':');
	std::getline(is, line, ':'); is >> n.Rect.x;
	std::getline(is, line, ':'); is >> n.Rect.y;
	std::getline(is, line, ':'); is >> n.Rect.h;
	std::getline(is, line, ':'); is >> n.Rect.w;

	std::getline(is, line, ':'); is >> n.description;	

	return is;
}

std::ostream& saveOn(std::ostream& os, const Inventory& n)
{
	// I don't know what the file format is
	return os;
}

std::istream& restoreFrom(std::istream& is, Inventory& n)
{
	// again, using your code ...
	std::string line;
	std::getline(is, line, '#'); is >> line;
	int inventoryPage = atoi(line.c_str());
	if (inventoryPage == -1) {
		is.setstate(std::ios_base::badbit);
		return is;
	}
	n.inventoryPage = inventoryPage;

	std::getline(is, line, ':'); is >> n.inventoryTexturePath;
//	n.Texture = TextureManager::loadTexture(n.inventoryTexturePath.c_str());

	size_t nSlots;
	std::getline(is, line, '#'); is >> nSlots;
	n.slots.resize(nSlots);
	for (size_t i = 0; i != nSlots; ++i)
		if (!restoreFrom(is, n.slots[i])) {
			n.slots.resize(i);
			break;
		}

	return is;
}

//---------------------------------------------------------------------------
//
typedef std::vector<Inventory> InventoryEntriesType;

InventoryEntriesType loadInventoryData(const std::string& filename);
InventoryEntriesType loadInventoryData(std::istream& is);

InventoryEntriesType loadInventoryData(const std::string& filename)
{
	std::ifstream is(filename);
	return loadInventoryData(is);
}

InventoryEntriesType loadInventoryData(std::istream& is)
{
	InventoryEntriesType inventories;
	
	do {
		Inventory inventory;
		if (restoreFrom(is, inventory))
			inventories.push_back(inventory);
	}
	while (is);
	
	return inventories;
}

int main(int argc, char* argv[])
{
	if (argc != 2)
		return 1;
	
	loadInventoryData(argv[1]);
}
Last edited on
I feel sort of bad. I really appreciate your effort. And I do understand where you're coming from with wanting to apply those changes to the code but The way my code is, however messy it might seem to you, is justified by the structure of the game I'm trying to implement this function into.

I'd really like someone to point out what's wrong in the way I'm trying to read the file, and why I'm getting that input.

I've already created 2 other similar function for other classes than the Inventory one and it works just fine

My problem lies here:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
for (int index = 0; index < tempNum; index++) //Inner for loop, runs ok on first iteration but not the second
		{
			cout << "\n\nTempnum: " << tempNum;           //for debugging purposes
			cout << "\nindex " << index;                            //for debugging purposes

			getline(inventoryDataFile, temp, ':');                  //positioning buffer after "slot position:"
			inventoryDataFile >> slots->position;                //storing slot position in slots
			cout << "\n" << slots->position;                      //for debugging purposes
			inventoryDataFile.ignore(numeric_limits<streamsize>::max(), '\n');

			getline(inventoryDataFile, temp);                      //Ignoring line "position in inventory:"
			getline(inventoryDataFile, temp, ':');                 //positioning buffer after "x:"
			inventoryDataFile >> slots->Rect.x;                 //storing value of x in slots.Rect.x
			cout << "\n" << slots[index].Rect.x;                //for debugging purposes

			getline(inventoryDataFile, temp, ':');                //positioning buffer after "y:"
			inventoryDataFile >> slots->Rect.y;                 //storing value of y in slots.Rect.y
			cout << "\n" << slots[index].Rect.y;                //for debugging purposes

			getline(inventoryDataFile, temp, ':');                 //positioning buffer after "h:"
			inventoryDataFile >> slots->Rect.h;                 //storing value of h in slots.Rect.h
			cout << "\n" << slots[index].Rect.h;                //for debugging purposes

			getline(inventoryDataFile, temp, ':');                //positioning buffer after "w:"
			inventoryDataFile >> slots->Rect.w;                //storing value of w in slots.Rect.w
			cout << "\n" << slots[index].Rect.w;               //for debugging purposes

			getline(inventoryDataFile, temp, ':');                //positioning buffer after "slot description:"
			inventoryDataFile >> slots->description;          //storing value of slot description in slots.description
			cout << "\n" << slots->description;                 //for debugging purposes

			inventory[count].slots.push_back(*slots);        //push back slots in vector of slots withing inventory[count]

			slots->description = "";           //for debugging purposes
			slots->position = "";               //for debugging purposes
			slots->Rect = { 0,0,0,0 };      //for debugging purposes
		}


You can see on the output that on the second iteration (index = 1) x, y, h, and w aren't read properly. Here lies my issue.
 
 File successfully opened!

Loading 2 inventory Pages...

 1
Setting variables without file
 Tempnum: 2

Tempnum: 2
index 0
main_1
156
181
45
45
slot_hat

Tempnum: 2
index 1
main_2
0
1
0
96
slot_torso

Total number of slots: 2
Inventory page number 0 Successfully loaded!
 1

 CLOSING

 inventoryDataFile.txt closed...


Contents of inventoryData.txt:
___PAGE 0___
#0
Texture path:textures/inventoryScreen01.png
___END_OF_PAGE___
#2
Slot position:main_1
Position in inventory:
x:156
y:181
h:45
w:45
Slot description:slot_hat
Slot position:main_2
Position in inventory:
x:211
y:181
h:45
w:45
Slot description:slot_torso
END OF FILE
#-1


I hope this makes things clearer for you.

Thank you for your time!

Regards,

Hugo
Last edited on
My bad, I was trying to access slots[index].Rect whereas I defined it as Slot* slots = new Slot;.

So that's why when index is greater than 0 it failed to output anything that made sense.

Thanks so much for your time kbw!
Topic archived. No new replies allowed.