I’d say abstract as much as possible.
I’d have a save file that looked like this (using JSON notation for easiness to type/debug)
{
'game_settings':{'map':'/path/to/map', 'difficulty':0, 'time_in_game'....}
'player_list':[{'name':player_1, 'score':1234, 'resources':{'metal':5, 'fuel':2}}, {'name', player_2, ....]
'building_list':[
{'type':'shipyard', 'health':654, 'position':[pos, rot], 'data':{'construction_unit':'Boat', 'construction_percent':0 ....},
{'type':'town center', 'health':654, 'position':[......
],
'unit_list':[
{'type':'horse', 'health':43, 'position':[pos, rot], 'data':{'carrying_message':False, .....}
]
}
Why did I pick this structure?
Mostly because It’s easily expandable. If you want to add the ability for multiple players, it’s trivial to add. If you need a new unit type, just put a different string in ‘type.’
One key point is that every item in the various lists are the same except for the contents of ‘data’ which depends on the type. This is similar to how blender treats objects - a position in space that ‘contains’ either a mesh, curve etc.
I’m a big fan of JSON because it’s easy to debug/read, and trivial to dump information into. If you don’t want people tweaking the save-files, you could do something else or encrypt the JSON.
Now, you should build your game’s internal architecture with intent to save it/load it. For example, somewhere in your game you will probably have a list of units. So make it so you can do the same operation on every item in that list. Since every entity in your game is (probably) a python class. You can add a to_save_dict() and load_from_dict() function which manipulates the necessary data for that unit. This is what I did in a system that had to deal with user-settable objective data. This was a function like:
class TownCenterClass(building):
def to_json(self):
'''Returns a JSON string of the object'''
out = super().to_json() #Does the object name, position and other things common to all buildings
out['data'] = {'construction_percent':self.construction_percent....}
return out
Then exporting a save file is:
save_file_data = dict()
save_file_data['building_list'] = list()
for building in internal_building_list:
save_file_data['building_list'].append(building.to_json())
json.dump(save_file_data, save_file_path)
And loading it is:
CLASS_DICT = {
'Refinary':RefinaryClass(subclass_of_building),
'Town Center':TownCenterClass(subclass_of_building)
}
for building_data in save_file_building_list:
type_str = building_data['type']
type_class = CLASS_DICT[type_str]
new_building = type_class()
new_building.load_from_json(building_data)
internal_building_list.append(new_building)
Bear in mind I haven’t worked on a save game system in some years, nor of the scale you seem to need.
Now what happens if we want to, say, have units able to go into buildings? Thankfully, it is supremely unlikely that we can have units in multiple places, so we don’t have to store our person in the unit list. We can store it in a unit list inside the building, eg:
building_data = {‘unit_list’:[{‘name’:‘raider’, ‘type’:‘Horse’…}]}
It’s very likely that you’ll already have a system to destroy/recreate entities when they enter buildings. You can take advantage of this and when a person is in a building, work with there data in the same way you do as if they were ‘saved.’ (ie you ‘save’ the person into the building when he enters, and ‘load’ him when he exits).
If we assume I know the basics how to write/read and apply data from .cfg/.txt file to objects and states in scene - how to make the architecture of all this, I mean on more abstract level
Good luck finding this out on these forums. Perhaps a more general game development forum would be more appropriate? If you find a good one let me know. (It seems the indie dev universe is lacking in people who actually design the systems they build)