|
Allegro 5 file system |
Ariesnl
Member #2,902
November 2002
|
Since the native file dialog doesn't look so nice and also crashes the Windows version of my game. I wanted to make a save/ load screen with a list of slots. Correction.. the Dialog wasn't the problem.. it seems you cannot load a file in windows that was saved in linux for some reason... strange.. looking up the version number just went fine?? Perhaps one day we will find that the human factor is more complicated than space and time (Jean luc Picard) |
RPG Hacker
Member #12,492
January 2011
|
Ariesnl said: However I saw a "warning" not to use the file's path but the ALLEGRO_FS_ENTRY itself to open the file ? How would I do that Is this what you're looking for? Quote: it seems you cannot load a file in windows that was saved in linux for some reason... strange.. looking up the version number just went fine?? How exactly are you saving the data? Are you just putting a pointer of a struct into a file stream? In that case, yeah, the save file won't be platform-independent. Every compiler has different rules for packing of structs and every architecture has its own endianness. Those and probably some more things influence how the data written to the file will be interpreted when read back. If you want truley platform-independent save files, you'll have to work at a byte level. Only write singular bytes to the file stream and do the conversion (multiple bytes <-> actual data type) yourself. Note that this is a lot slower and you're probably better just having platform-dependent save files, for the sake of the game. In my opinion, sharing save files between different platforms isn't really that important, anyways.
|
Ariesnl
Member #2,902
November 2002
|
Partly it is.. however, trying to be "modern" all my load and save routines use C++ filestream... I'm afraid that won't map to a filepointer system ? By the way: g_pUniverse->StoreSector stores the Game engine contents into the current sector.( like the number of ships of a certain kind etc.) 1void SaveGame()
2{
3 ALLEGRO_FILECHOOSER * dlg = NULL;
4 ALLEGRO_PATH * pSavePath = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
5
6 al_append_path_component(pSavePath, "Save");
7
8 dlg = al_create_native_file_dialog( al_path_cstr(pSavePath,ALLEGRO_NATIVE_PATH_SEP),
9
10 "Save Game...",
11
12 "*.uni",
13
14 ALLEGRO_FILECHOOSER_SAVE);
15
16 if (al_show_native_file_dialog(g_pDisplay,dlg))
17
18 {
19
20 ofstream SaveFile(al_get_native_file_dialog_path(dlg, 0),ios::out | ios::binary);
21
22 if (SaveFile)
23
24 {
25
26 g_pUniverse->StoreSector(g_pEnterprise->m_nSectorPositionX,g_pEnterprise->m_nSectorPositionY,g_pEngine);
27
28 g_pEngine->Save(SaveFile);
29
30 g_pUniverse->Save(SaveFile);
31
32 SaveFile.close();
33
34 }
35
36 else
37
38 {
39
40 // handle error
41
42 }
43
44
45
46 }
47
48
49
50 al_destroy_native_file_dialog(dlg);
51
52}
Perhaps one day we will find that the human factor is more complicated than space and time (Jean luc Picard) |
RPG Hacker
Member #12,492
January 2011
|
Ariesnl said: I'm afraid that won't map to a filepointer system ? Well, not mapping to a file pointer is kind of the point of Allegro 5's filesystem. It's meant to just provide the data for you and abstract the actual interface so that you don't have to care where the data comes from. It could come from a native file, from a ZIP file or even from a completely different filesystem (like a network filesystem, for example) if you provide the interfaces for that. If you want something that maps to a native file pointer, Allegro's file I/O is probably what you want instead of filesystem (and even then that's probably using platform-dependent C file interfaces under the hood, not C++ interfaces). As for your save function 1g_pUniverse->StoreSector(g_pEnterprise->m_nSectorPositionX,g_pEnterprise->m_nSectorPositionY,g_pEngine);
2g_pEngine->Save(SaveFile);
3g_pUniverse->Save(SaveFile);
These are really the functions that matter. I need to see how exactly you write some of that data to the actual file stream to know what goes wrong.
|
Ariesnl
Member #2,902
November 2002
|
This is what I have now. But it is not very efficient. 1bool TEngine::Save(ofstream & a_SaveStream)
2{
3 char szVersion[18]="CURRENT_SECTOR_V1";
4 a_SaveStream.write((char*)szVersion,sizeof (szVersion));
5
6
7 std::list<TSprite *>::const_iterator p=m_lstItems.begin();
8 int m_nObjects = CountSaveObjects();
9 a_SaveStream.write((char*)&m_nObjects,sizeof (int));
10 while (p!=m_lstItems.end())
11 {
12 if ( (!(*p)->m_blDestroyed) && ((*p)->m_ID != ID_NONE) && ((*p)->m_ID != ID_SMOKE))
13 {
14 sGameObject object;
15 memset(&object, 0, sizeof(sGameObject));
16 object.m_ID = (*p)->m_ID;
17 object.m_Member = (*p)->m_Member;
18 object.m_dX = (*p)->m_dX;
19 object.m_dY = (*p)->m_dY;
20 object.m_nZ = (*p)->m_nZ;
21 object.m_dAngle = (*p)->m_dAngle;
22 object.m_blCanFind = (*p)->m_blCanFind;
23 object.m_dSpeed = (*p)->m_dSpeed;
24
25
26 if ((*p)->m_ID>ID_BULLET_BOTTOM && (*p)->m_ID<ID_BULLET_TOP)
27 {
28 // sprite is a bullet
29 object.m_nLife = ((TBullet*)(*p))->m_nLife;
30 object.m_nCount = ((TBullet*)(*p))->m_nWait;
31 }
32 else if ((*p)->m_ID>ID_PLANET_BOTTOM && (*p)->m_ID<ID_STAR_TOP)
33 {
34 // sprite is a planet or a star
35
36 }
37
38 if ((*p)->m_ID == ID_EXPLOSION)
39 {
40 // sprite is an explosion
41 object.m_nLife = ((TExplosion*)(*p))->m_nFrame;
42 object.m_nCount = ((TExplosion*)(*p))->m_nWait;
43 }
44
45 if ((*p)->m_ID == ID_SMOKE)
46 {
47 object.m_nLife = ((TSmoke*)(*p))->m_nFrame;
48 object.m_nCount = ((TSmoke*)(*p))->m_nWait;
49 }
50
51 if (((*p)->m_ID>ID_SHIP_BOTTOM)&&((*p)->m_ID<ID_BASE_TOP))
52 {
53 //sprite is a ship or a starbase
54
55 object.m_blDocked = ((TShip *)(*p))->m_blDocked;
56 object.m_blDocking = ((TShip *)(*p))->m_blDocking;
57 object.m_blReleasing = ((TShip *)(*p))->m_blReleasing;
58 object.m_blMustBeDestroyed = ((TShip *)(*p))->m_blMustBeDestroyed;
59 object.m_blMustSurvive = ((TShip *)(*p))->m_blMustSurvive;
60
61 object.m_blMustReachPosition = ((TShip *)(*p))->m_blMustReachPosition;
62 object.m_blDock = ((TShip *)(*p))->m_blDock;
63 object.m_blNoRelease = ((TShip *)(*p))->m_blNoRelease;
64 object.m_blCanFind = ((TShip *)(*p))->m_blCanFind;
65 object.m_dWaypointX = ((TShip *)(*p))->m_dWaypointX;
66
67 object.m_dWaypointY = ((TShip *)(*p))->m_dWaypointY;
68 object.m_nTorpedoes = ((TShip *)(*p))->m_nTorpedoes;
69 object.m_nRepairItem = ((TShip *)(*p))->m_nRepairItem;
70 object.m_nCrew = ((TShip *)(*p))->m_nCrew;
71 object.m_nEnergy = ((TShip *)(*p))->m_nEnergy;
72
73 object.m_nShieldEnergy = ((TShip *)(*p))->m_nShieldEnergy;
74 object.m_nPhaserEnergy = ((TShip *)(*p))->m_nPhaserEnergy;
75 object.m_nPreferedTarget = ((TShip *)(*p))->m_nPreferedTarget;
76 object.m_nPhaserPower = ((TShip *)(*p))->m_nPhaserPower;
77 object.m_blCanCloak = ((TShip *)(*p))->m_blCanCloak;
78
79 object.m_blCanFind = ((TShip *)(*p))->m_blCanFind;
80 object.m_blPhaserOn = ((TShip *)(*p))->m_blPhaserOn;
81 object.m_nCloakCharge = ((TShip *)(*p))->m_nCloakCharge;
82 object.m_nCloakCounter = ((TShip *)(*p))->m_nCloakCounter;
83 object.m_nPhotonTimer = ((TShip *)(*p))->m_nPhotonTimer;
84
85 object.m_nTranslucency = ((TShip *)(*p))->m_nTranslucency;
86 object.m_nTask = ((TShip *)(*p))->m_nTask;
87 object.m_nCloakState = ((TShip *)(*p))->m_nCloakState;
88
89 // store health
90 for (size_t i=0; i< ((TShip *)(*p))->m_lstHealth.size();i++)
91 {
92 object.m_nHealth[(HEALTH)i]=((TShip *)(*p))->m_lstHealth[(HEALTH)i];
93 }
94
95 if ((*p)->m_ID==ID_PLAYER)
96 {
97 // player specific ! sprite is the player
98 object.m_nSectorPositionX = ((TEnterprise *) (*p))->m_nSectorPositionX;
99 object.m_nSectorPositionY = ((TEnterprise *) (*p))->m_nSectorPositionY;
100 object.m_nWarpFactor = ((TEnterprise *) (*p))->m_nWarpFactor;
101 object.m_nProbes = ((TEnterprise *) (*p))->m_nProbes;
102 }
103 }
104
105 a_SaveStream.write((char*)&object,sizeof (sGameObject));
106 }
107 ++p;
108 }
109 return true;
110}
111
112
113
114
115
116
117
118bool TEngine::Load(ifstream & a_LoadStream)
119{
120 Clear(false);
121 char szVersion[18];
122 a_LoadStream.read((char *)szVersion,sizeof(char)*18);
123
124 int m_nObjects;
125 a_LoadStream.read((char *)&m_nObjects,sizeof(int));
126
127 for (int i=0;i<m_nObjects;i++)
128 {
129 sGameObject object;
130 memset(&object, 0, sizeof(sGameObject));
131
132 a_LoadStream.read((char *)&object,sizeof(object));
133 TSprite * pSprite=NULL;
134
135 if ((object.m_ID>=ID_CLASS_A)&&(object.m_ID<ID_BLACK_HOLE))
136 {
137 pSprite = new TSpaceObject(object.m_ID);
138
139 }
140 if (object.m_ID == ID_PROBE)
141 {
142 pSprite = new TProbe(object.m_dX ,
143 object.m_dY,
144 object.m_dSpeed,
145 object.m_dAngle,
146 object.m_nZ,g_pEnterprise);
147 }
148 else if ((object.m_ID>ID_BULLET_BOTTOM)&&(object.m_ID<ID_BULLET_TOP))
149 {
150 pSprite = new TBullet( object.m_dX ,
151 object.m_dY,
152 object.m_dSpeed,
153 object.m_dAngle,
154 object.m_nZ,
155 object.m_ID,
156 object.m_Member);
157
158 ((TBullet *)pSprite)->m_nLife = object.m_nLife;
159 ((TBullet *)pSprite)->m_nWait = object.m_nCount;
160 }
161 else if (object.m_ID == ID_EXPLOSION)
162 {
163 pSprite = new TExplosion(object.m_dX,
164 object.m_dY,
165 object.m_dSpeed,
166 object.m_dAngle,
167 object.m_nZ);
168
169
170 }
171 else if (object.m_ID>ID_SHIP_BOTTOM)
172 {
173 switch (object.m_ID)
174 {
175 case ID_PLAYER:
176 {
177 pSprite = new TEnterprise();
178 g_pEnterprise = (TEnterprise *)pSprite;
179 g_pEnterprise->m_nSectorPositionX = object.m_nSectorPositionX;
180 g_pEnterprise->m_nSectorPositionY = object.m_nSectorPositionY;
181 g_pEnterprise->m_nWarpFactor = object.m_nWarpFactor;
182 g_pEnterprise->m_nProbes = object.m_nProbes;
183 }
184
185
186 break;
187
188 case ID_GALAXYCLASS:
189 pSprite = new TFederation_Ship();
190
191 break;
192
193 case ID_KLINGONBC:
194 {
195 pSprite = new TKlingonBC();
196
197
198
199 }
200 break;
201
202 case ID_KLINGONBOP:
203 {
204 pSprite = new TKlingonBOP();
205 }
206
207 break;
208
209 case ID_ROMULANBOP:
210 {
211 pSprite = new TRomulanBop();
212
213
214
215 }
216 break;
217
218 case ID_FEDERATIONBASE:
219 {
220 pSprite = new TStarbase(ID_FEDERATIONBASE);
221
222 }
223 break;
224
225 case ID_ROMULAN_BASE:
226 {
227 pSprite = new TStarbase(ID_ROMULAN_BASE);
228
229 }
230 break;
231
232
233 default:
234 throw A5Exception("Unknown shiptype");
235 break;
236
237
238 }
239
240 if (pSprite !=NULL)
241 {
242 // save TShip specific
243 ((TShip *)pSprite)->m_nCrew = object.m_nCrew;
244 ((TShip *)pSprite)->m_nRepairItem = object.m_nRepairItem;
245 ((TShip *)pSprite)->m_nTorpedoes = object.m_nTorpedoes;
246 ((TShip *)pSprite)->m_nShieldEnergy = object.m_nShieldEnergy;
247 ((TShip *)pSprite)->m_nPhaserEnergy = object.m_nPhaserEnergy;
248
249 ((TShip *)pSprite)->m_nPreferedTarget = object.m_nPreferedTarget;
250 ((TShip *)pSprite)->m_nPhaserPower = object.m_nPhaserPower;
251 ((TShip *)pSprite)->m_dWaypointX = object.m_dWaypointX;
252 ((TShip *)pSprite)->m_dWaypointX = object.m_dWaypointY;
253 ((TShip *)pSprite)->m_blDocked = object.m_blDocked;
254
255 ((TShip *)pSprite)->m_blDocking = object.m_blDocking;
256 ((TShip *)pSprite)->m_blReleasing = object.m_blReleasing;
257 ((TShip *)pSprite)->m_blMustBeDestroyed = object.m_blMustBeDestroyed;
258 ((TShip *)pSprite)->m_blMustSurvive = object.m_blMustSurvive;
259 ((TShip *)pSprite)->m_blMustReachPosition = object.m_blMustReachPosition;
260
261 ((TShip *)pSprite)->m_blNoRelease = object.m_blNoRelease;
262 ((TShip *)pSprite)->m_blCanFind = object.m_blCanFind;
263 ((TShip *)pSprite)->m_blCanCloak = object.m_blCanCloak;
264 ((TShip *)pSprite)->m_blCanFind = object.m_blCanFind;
265 ((TShip *)pSprite)->m_blPhaserOn = object.m_blPhaserOn;
266
267 ((TShip *)pSprite)->m_nCloakCharge = object.m_nCloakCharge;
268 ((TShip *)pSprite)->m_nCloakCounter = object.m_nCloakCounter;
269 ((TShip *)pSprite)->m_nPhotonTimer = object.m_nPhotonTimer;
270 ((TShip *)pSprite)->m_nTranslucency = object.m_nTranslucency;
271 ((TShip *)pSprite)->m_nTask = object.m_nTask;
272
273 ((TShip *)pSprite)->m_nCloakState = object.m_nCloakState;
274
275 for (size_t i=0;i<((TShip *)pSprite)->m_lstHealth.size();i++)
276 {
277 ((TShip *)pSprite)->m_lstHealth[i]=object.m_nHealth[i];
278 }
279 }
280 }
281
282 if (pSprite !=NULL)
283 {
284 // save TSprite specific
285 pSprite->m_dX = object.m_dX;
286 pSprite->m_dY = object.m_dY;
287 pSprite->m_nZ = object.m_nZ;
288 pSprite->m_dSpeed = object.m_dSpeed;
289 pSprite->m_dAngle = object.m_dAngle;
290 pSprite->m_Member = object.m_Member;
291 pSprite->m_ID = object.m_ID;
292 Add(pSprite);
293 }
294
295 }
296
297std::list<TSprite *>::const_iterator p=m_lstItems.begin();
298while (p!=m_lstItems.end())
299{
300 if (((*p)->m_ID>ID_SHIP_BOTTOM)&&(((TShip *)(*p))->m_blDocked))
301 {
302 ((TShip *)(*p))->m_blCanFind = false;
303 ((TShip *)(*p))->m_blDocking=false;
304 ((TShip *)(*p))->m_blReleasing = false;
305 ((TShip *)(*p))->m_dSpeed=0;
306 ((TShip *)(*p))->m_pBaseTarget=(TShip *) Seekstarbase(((TShip *)(*p))->m_Member,false,100000,((TShip *)(*p))->m_dX,((TShip *)(*p))->m_dY);
307 ((TShip *)(*p))->m_pTarget = ((TShip *)(*p))->m_pBaseTarget;
308 }
309 else if (((*p)->m_ID>ID_SHIP_BOTTOM)&&(((TShip *)(*p))->m_blDocking))
310 {
311 ((TShip *)(*p))->m_blDocking=true;
312 ((TShip *)(*p))->m_blReleasing = false;
313 ((TShip *)(*p))->m_pBaseTarget=(TShip *) Seekstarbase(((TShip *)(*p))->m_Member,false,100000,((TShip *)(*p))->m_dX,((TShip *)(*p))->m_dY);
314 ((TShip *)(*p))->m_pTarget = ((TShip *)(*p))->m_pBaseTarget;
315 }
316
317 ++p;
318}
319
320
321return true;
322
323}
Perhaps one day we will find that the human factor is more complicated than space and time (Jean luc Picard) |
Audric
Member #907
January 2001
|
If you want cross-platform behavior, you need to save your structures one field at a time. Choose an endianness for the file format, and save every multi-byte integer with the specific function for its size (short : 16, long: 32). al_fwrite16le(saveFile, object.m_dX); al_fwrite16le(saveFile, object.m_dY); Same when you reload them : object.m_dX = al_fread16le(saveFile); object.m_dY = al_fread16le(saveFile);
|
|