Level-Save Object problem
I've been having some trouble with the Level-Save Object. I am trying to make a level editor for a game that I'm working on, and so far it has been going well except for a strange crash that keeps happening.
What I want to do with the editor is have it be able to save and load levels that I make, and then also save the changes I make to a level after I have loaded it.
So far it works perfectly saving a level for the first time, and loading it. But when it comes to loading a previously saved file, altering it in a specific way, saving and loading it again, and then trying to save it once more, it crashes the editor.
I have done some tests to determine what exactly seems to cause the crashes, and it seems to have to do with what order I delete and add objects in the level that I edit.
For example, if I make a new level and place three tiles, and save, it works fine. When I load it, it loads properly and works fine. If I add something to it and save and load it again, it works fine. If I delete the last item (the most recently created item) that I created, save and load, it seems to work fine. However, If I load up a level that I have saved previously, and delete the first item that I created (out of 3, for example) and then save and load, it will crash if I try to save it again. It will also do this if I delete an item which was not the first or the last item that I placed (the second object that I placed, assuming I made 3 objects total).
A small workaround is to create a new object for every object that I deleted before saving again, but this eventually causes it to mess up when loading, and some objects start to not load, or get loaded in the wrong place, etc. Obviously this isn't a very desirable workaround. I have tried changing how the editor handles saving and loading, but nothing I have done has really fixed the problem.
It looks as though the specific point that causes the crash has to do with the Output String of the Level-Save object.
I added an event where when I press a key, an edit box will set its text to the output string of the Level-Save object. When I press this key under normal circumstances, the edit box displays the level save data which would be in the file that the Level-Save object saves its data to. But when I press the key after modifying a previously saved level in a way that will cause it to crash if I save it again, it will crash when it tried to display the output string in the edit box.
Here is the copy/pasted output for a level where I do the steps which cause the crash.
(The id|0|, id|1| etc are just something I was trying to do to stop the crashing which didn't work.)
Output after removing the object that was created first:
For the second output, I retrieved it by pressing the key to make the edit box display the output string BEFORE I saved the changes. Once I saved it and loaded it, pressing the key to make it display the second output caused it to crash.
The editor works like this as far as how I have it save/load objects.
Placing an object:
User clicks with left button --->
*Create flatgrass_paste at 0,0 from the cursor object
*Add 1 to id_counter
*Level-Save object Add object of type "flatgrass" from flatgrass_paste, Set value property "id" to value ("id_counter") for object "flatgrass_paste"
Saving the level:
Button save clicked --->
*Powerful Dialogs object Show save file dialog using window handle MainHwnd("powerful dialogs object")
On save file dialog 1 success --->
*Level-Save object Save level to RetString1$("Powerful Dialogs object")
Loading the level:
On Open File Dialog 1 Success --->
*Start loop "load" TotalObjs("Level-Save object") times
*(sets the frame width and height from the save data)
*loopnumber set counter to Loopindex("load")
*Level-Save object Load Level from RetString1$("Powerful Dialogs object")
*Edit Box settext RetString1$("Powerful Dialogs object")
Value of loopnumber_count = value of loopnumber --->
*deactivate group load, activate alot of other groups disabled during loading, and stop loop "load"
*loopnumer and loopnumber_count set to 0
*Level-Save object clear all stored data
On loop "load", ObjType$( "Level-Save Object", ObjAt( "Level-Save Object", LoopIndex("load"))) = "flatgrass" --->
*create flatgrass_paste at 0,0 layer 1
*flatgrass_paste set x postion to ObjX( "Level-Save Object", ObjAt( "Level-Save Object", LoopIndex("load")))
*same sort of thing for y position
*add 1 to loopnumber_count
Deleting an object(I've tried various methods, this is the one I am currently using):
User clicks with middle mouse button on Group.97(all tile objects are part of this group)--->
*Level-Save object set Value Property "id" to -1 for object Group.97
*Level-Save object Remove object Group.97 (Destroy = 0)
There are of course many more events than that in the editor, but those are the basic ones for the problem I am having.
I am probably doing something wrong, but I can't tell. If anyone has encountered this problem before or knows what I need to do to fix it if anything, I would greatly appreciate it.
Re: Level-Save Object problem
Could you upload your mfa in the file archives, so we could have a look at the actual mfa?
Re: Level-Save Object problem
I have uploaded the file.
Re: Level-Save Object problem
Re: Level-Save Object problem
Well I think I figured out a way to fix it.
When placing objects in the editor, I had the level save object adding the object to it through the selector method. (Stored Objects->Add Object (Selector)) Using this method for what I was trying to achieve will cause it to crash as explained in my original post.
Today I tried changing the method it uses to (Stored Objects->Add Object (Fixed)) and now when I try to save a level, load it, save it again, load it again, and then save it again, it doesn't crash.
The only problem I have left is trying to properly remove all of the object value properties of the objects I delete so the save file doesn't become cluttered with old data that no longer has a purpose. But I think this will be easier to solve.
For anyone else who might have the problem I had, try this.
(Make sure the objects you are creating all share a common Qualifier for this method)
To use the Fixed method, make a counter which starts at 1, and when you place an object using the fixed method, create the object, and tell the level save object to add the object type "object name" from value (current value of the counter). Then tell the actual object to set its Alterable Value A to the current value of the counter. Also tell the level save object to set 3 object value properties (fixed) for the object. One for its X position, one for its Y position, and one for its ID. It helps to have all of the objects that you can create share a common Qualifier. Assuming the objects all have a qualifier, setting the X object value should look like this.
Set value property "x" to X("Qualifier")for Object Alterable Value A("Qualifier")
Setting the Y object value should be the same except replace x with y.
Setting the ID object value should look something like this.
Set value property "id" to value("counters current value") for Object Alterable Value A("Qualifier")
At the same time, disable the group that lets you place objects and enable another group, which will deactivate in a short time (half a second or less), add 1 to the counter, and reactivate the group that lets you place objects.
For deleting objects, have an event where when you click on the objects qualifier, the qualifier is destroyed, and the level save object performs Remove Object(Fixed). The level object event should look like this
Remove Object Alterable Value A("Qualifier") (Destroy=0)
For loading, as far as telling the created object to set its x,y coordinates and alterable value a to what is stored in the level save object, do this.
Set X position to ValProp("Level-Save Object", ObjAt("Level-Save Object", LoopIndex ("loopname for loading")), "x")
Its the same for the Y position, just replace the x's with y's.
As for setting the objects alterable value a, it should look like this.
Set Alterable Value A to ValProp("Level-Save Object", ObjAt("Level-Save Object", LoopIndex("loopname for loading")), "id")
Of course, when loading you also need to make the load loop and set it to as many times as there are total objects in the level save object, make events for On loop load and such, and create the appropriate object on the screen, and a number of other things, but the above should explain what I did to solve the problem I was having.
I also found out I could stop a save file that was crashing from crashing if I manually edited the values inside the file with a text editor, but thats not an effective way to do things.
Original file before being loaded, modified, and saved again.
flatgrass|9568281|835|89||flatgrass|9633819|835|17 6||flatgrass|9699357|832|300||flatgrass|9764895|84 2|431||
File that crashes on save/display of output string. (The change made is that the first flatgrass to be originally created was deleted.)
File after having object #'s manually fixed. (Can be saved/output string displayed without crashing)
The difference between the crash copy and the fixed copy is that in the crash copy, the first flatgrass from the original file has been removed. It's value was 9568281.
There are 3 more flatgrass objects after the first, and their values are these in the following order. 9633819, 9699357, and 9764895.
Once the first flatgrass was removed and the file saved, the file now only displays 3 flatgrasses. Their numbers have not been changed, and they are 9633819, 9699357, and 9764895.
Trying to save the level now will result in a crash.
However, if I open the file manually and change each remaining flatgrass objects value, so that they are all shifted to the right, then saving the level will not cause a crash.
I do this by changing the last remaining flatgrass objects value from 9764895 to the value of the one before it, which is 9699357. Then I change the second to last
remaining flatgrass objects value from 9699357 to the value of the one before it, which is 9633819. Finally, I change to first remaining flatgrass objects value from 9633819
to the value of the original first flatgrass object, which was 9568281 before it was deleted. This fixes the problem.
I dont know how the values are assigned to each object that is saved, but they seem to be quite important, as they cause the program to crash when one is removed, unless the values are
shifted as shown in this example.