Save/Load wonderings [solved]

Tile-map editor, saves/loads data from XML files.

It’s taking me 15 seconds to load stuff that takes <= 1 second to save.

file size to load is 3.6mb…

This seems unreasonable to me, but it’s my first tile engine, so I’d appreciate input.

I don’t know anything about the context, but it sounds like it’s the built in thing from MonoGame.Extended? You could always look up the repository and see what’s going on in there.

I’d imagine saving is a lot quicker than loading since, when you’re saving, you just write numerical data from objects that already exist to a file. When you’re loading, you’ve gotta instantiate a bunch of objects and then assign those values.

I’d imagine an optimization you could make would be to thread the load procedure and have it stream from the disk, making the data for the area of the map the player is in available at the start and load in proximity order. Unless the player can move really, really fast, the entire map should be loaded before they can outpace the area available to them.

If off-screen entities need to update during that process, you might need to keep track of how much time elapsed during the load process and have them update based on that elapsed time.

Anyway, those are just my thoughts… hope they help! :slight_smile:

Thanks man! - Yea I was trying to keep my post REALLY short and tight, so i left out ALL detail.

Im not using tiled, I wrote the whole thing myself, so it’s pretty bonkers… I have scenes or rooms made of multiple tile-layers at various zoom levels, so the game has depth layers. So lots of tiles per scene, each with a lot of variables… So lots of data, compared to OLD games.

I like the idea of threading, but you don’t think it’s too complex for an old hobby-man like myself? No experience there.

-I was considering loading map chunks as the player goes through doors, you know, have a little pause from one room to the next, which would be EASY to code from what I already have. But seamless transitions might be cooler… IF in fact the player does not catch up to the doors, before the next room loads… I suppose I could just have the doors open slowly, LOL…

In ANY case, I’m happy to hear that you find it natural that it would take longer to load, your assessment sounds reasonable.

Loading does take longer than saving, but in my engine I save a >40MB file in 1 second and it may take 1 seconds to load the whole world. But I am not using XML but my own binary format.

If you are using the .Net XML Deserializer, that may be the slowdown. If you have lots of references in your data structure, be aware that internally, the XML has to be read first and then iterate over all objects for all objects with references to recreate the references again … I do this manually, but I have optimized my fileformat for doing so.

but 15 seconds is still a lot …

This may explain why I feel like I am seeing exponential load-time growth, on linear level-growth… Its like every NEW addition makes the OLD stuff load slower too…

Hmmmmm… Maybe it would be better to store each level-chunk in a separate file, instead of storing it all together in ONE big file? … Although that sounds a bit silly.

Right? … Thats like a second per screen of content. A bit much for a tile editor I feel like.

My advise would actually be to make your own format … but that’s some work - have you tried binary serialization instead of xml?

No I have not. - mostly because I like to have human readable files, that can be searched through, hand edited… This has proven useful several times during development… Maybe for release?

And honestly, I thought loading data from XML would be faster… Maybe it is instantiating objects that is taking time, and not reading data… And at that point, I don’t think binary serialization would help…?

It’s not so bad and there’s lots of tutorials about the internet. You never really know until you try! C# makes interacting with threads fairly straight forward… you just have to remember who can be working with your data in parallel and try not to do anything toooo silly :slight_smile:

Hi, a user by the name stainless told me 3 lines of code do the trick:

ThreadStart childref = new ThreadStart(Method());
Thread childThread = new Thread(childref);
childThread.Start();

where Method() is whatever job you want done on a seperate thread. It’s SOOOO easy.

I know youve found a solution loading rooms from another thread.

But i think something is wrong here. Loading a 3mb file should take only milliseconds, not 15 seconds.

1 Like

I agree, wholeheartedly, I just don’t know how to do anything about it. Am unable to fix, for the life of me…

It MIGHT be because I instantiate objects from the data loaded. Lots of them. Every tile, layer, room, game_object, effect, etc…? Also I store a lot of things most people might not, like every tile stores its own color and alpha, shader variant, and so forth…

Anyways, I feel like my XML code looks like the examples I see online…

Its structured like this: (this is an empty room with next to no data, attempting to show the xml tree)

<?xml version="1.0" encoding="utf-8"?>
<MapInfo>
	<InfoPiece>
		<Player_1_pos_X>100</Player_1_pos_X>
		<Player_1_pos_Y>100</Player_1_pos_Y>
		<Player_1_current_room>0</Player_1_current_room>
		<Player_1_current_layer>0</Player_1_current_layer>
	</InfoPiece>
	<Rooms>
		<Room>
			<RoomIndex0>
				<X>0</X>
				<Y>0</Y>
				<Width>1920</Width>
				<Height>1008</Height>
				<Layers>
					<Layer>
						<LayerIndex0>
							<Scale>1</Scale>
							<MapHeight>16</MapHeight>
							<MapWidth>29</MapWidth>
							<X>0</X>
							<Y>0</Y>
							<Width>1920</Width>
							<Height>1008</Height>
							<Darknes_Level>0</Darknes_Level>
							<p_color_r>0</p_color_r>
							<p_color_g>0</p_color_g>
							<p_color_b>0</p_color_b>
							<p_alpha>0</p_alpha>
							<sub_alpha>0</sub_alpha>
							<Blink_to>0</Blink_to>
							<AmbientRadius>0</AmbientRadius>
							<ShadowCasters />
							<Waters />
							<TileBlocks />
							<Doors />
							<Objects />
							<Doodads />
							<LightObjects />
							<Mods />
						</LayerIndex0>
					</Layer>
				</Layers>
			</RoomIndex0>
		</Room>
	</Rooms>
</MapInfo>

Do you see any problem with this xml tree structure? Otherwise it must be in the code that uses it.
Again, I can save it all super fast… Just loading takes time…

maybe try profiling or step tru (over) functions to find which ones are actually taking long … 15 sec is just extremely long - you sure you don’t have a deadlock or reading the file byte per byte or something?

Hmm, do you need to do this for each tile? Everybody has different requirements, of course, but could you perhaps preload each tile type on startup and then, when you store/load, index to an array of tile types to get your data?

It might help to look at your data and only store, at the map/room level, values that are unique to each individual tile. So you might still need to store a color, alpha, etc… like you mention above, but is there other data you could cut down on that’s the same for everything?

I have a suspicion that your load is so slow because of the volume of new objects you create while loading. Your profiler should be able to show this… I think. Does it show object instantiation? If not, you could always route the code through a factory, then see if that factory shows up as a hot spot.

Yes. I have in mind doing a “baked” or “export” version for the map for use with the GAME, including generated tile sets so unused textures wont be included…, since at that point there is no need for user tweaking… while using “save files” only in the EDITOR, where I need to modify individual variables…

I just feel like my load times are off by a factor of 10 or 100, like I have some badly slow code parsing the xml file… A systemic error I need to track down.

That’s good thinking, and I have already done that by only loading variables that are actually individually meaningfull… for example, the size of a tile is stored in the containing layer class as “scale”

OK, I will need to look into what all that means - right now gotta go, RL stuff.

Another thought occurred to me… if you absolutely must instantiate objects as you load, you might try pooling a bunch of empty objects. It’s the “new” that’s generally the slow part, assigning values is usually pretty quick.

The general idea is, on program start up, kick off a background thread to create a bunch of empty objects in some kind of storage structure… likely a linked list. How many you create is up to you, but you probably want to create as many as your map will be likely to need.

Then, instead of creating a new object when you’re loading your map, get an existing object from your pool, making sure you remove it from your store. If you’re using a linked list, this is as easy as just setting the head of your list to the next object in the pool.

You can create a method on your object called something like, LoadFromData, and pass it whatever data representation you like. Have it assign its internal members from that data.

This is obviously way less flexible and convenient than object deserialization, but it should be a great deal faster :slight_smile:

1 Like

That’s pretty juicy right there. I like it.

You made me think maybe I should try loading the data, while skipping creation of objects to test out the difference in load time…

Wonder no more… Threading is great, but fixing your loader so you don’t need to is better.

Changing my code from rags to riches bettered my load time from 17 secs to <1… Nice.

Well, at least I learned how easy threading can be.

1 Like