I might have something that can help you though it has nothing to do with the Content Pipeline
Its probably not the best way, but I m currently working on a game and do save/load with Streamwriter and txt files
For this Game I programmed myself a little MapEditor to place, rotate, scale my map Objects in a 3D environment, because placing things via code sucks^^
since the MapEditor and my Game are seperate Programms, I save all my Objects with their ID Position etc in a txt file and put this file in a directory in my main game folder, to load it…
for my main game I also save the current world and player state in txt files like that and load from them during runtime when the player dies for instance,
here an example how to use the Streamwriter/reader from my MapEditor which can save/ load a map into 2 arrays:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace MapEditor
{
public class TextFileManager
{
public static void CreateFile(string name)
{
MapStuff.MapObject[] _itemArray = new MapStuff.MapObject[100];
int _skipIndexes = 0;
if (!File.Exists(name))
{
using (StreamWriter sw = File.CreateText("Saves/"+name))
{
sw.WriteLine("ID Poisiton Forward Upward Scale");
for(int i = 1; i < Global._objectArray.Length;i++)
{
if (Global._objectArray[i] != null)
{
if (Global._objectArray[i]._id > 100)
{
_itemArray[_skipIndexes] = Global._objectArray[i];
_skipIndexes++;
}
else
{
sw.WriteLine(Global._objectArray[i]._id + " " +
Global._objectArray[i]._position.X + ";" + Global._objectArray[i]._position.Y + ";" + Global._objectArray[i]._position.Z + " " +
Global._objectArray[i]._direction.X + ";" + Global._objectArray[i]._direction.Y + ";" + Global._objectArray[i]._direction.Z + " " +
Global._objectArray[i]._upwards.X + ";" + Global._objectArray[i]._upwards.Y + ";" + Global._objectArray[i]._upwards.Z + " " +
Global._objectArray[i]._scale);
}
}
}
for (int i = 0; i < _itemArray.Length; i++)
{
if (_itemArray[i] != null)
{
sw.WriteLine(_itemArray[i]._id + " " +
_itemArray[i]._position.X + ";" + _itemArray[i]._position.Y + ";" + _itemArray[i]._position.Z + " " +
_itemArray[i]._direction.X + ";" + _itemArray[i]._direction.Y + ";" + _itemArray[i]._direction.Z + " " +
_itemArray[i]._upwards.X + ";" + _itemArray[i]._upwards.Y + ";" + _itemArray[i]._upwards.Z + " " +
_itemArray[i]._scale);
}
}
}
}
}
public static void LoadFile(string name)
{
if (File.Exists("Saves/" + name))
{
Global._objectArray = new MapStuff.MapObject[Global._universeSize];
Global._objectArray[0] = new MapStuff.MapObject(1, new Vector3(0, -10f, 5), new Vector3(0, 1, 0), new Vector3(0, 0, 1));
Global._objectArray[0].Load();
using (StreamReader sr = File.OpenText("Saves/" + name))
{
string _line = "";
int i = 0;
while ((_line = sr.ReadLine()) != null)
{
//Position
if (i > 0)
{
int _posInd = 1+Math.Abs(_line.IndexOf(" "));
int _posCom1Ind = 1+Math.Abs(_line.IndexOf(";", _posInd));
int _posCom2Ind = 1+Math.Abs(_line.IndexOf(";", _posCom1Ind));
//Forward
int _directInd = 1+Math.Abs(_line.IndexOf(" ", _posInd + 1));
int _directCom1Ind = 1+Math.Abs(_line.IndexOf(";", _posCom2Ind));
int _directCom2Ind = 1+Math.Abs(_line.IndexOf(";", _directCom1Ind));
//Upwards
int _upInd = 1+Math.Abs(_line.IndexOf(" ", _directInd + 1));
int _upCom1Ind = 1+Math.Abs(_line.IndexOf(";", _directCom2Ind));
int _upCom2Ind = 1+Math.Abs(_line.IndexOf(";", _upCom1Ind));
int _lastSpaceInd = 1 + Math.Abs(_line.IndexOf(" ", _upCom2Ind + 1));
// Console.Out.WriteLine(_line.Substring(_directCom1Ind, _directCom2Ind - _directCom1Ind-1)); //Direct Y
//Position
float _xPos = (float)Convert.ToDouble(_line.Substring(_posInd, _posCom1Ind - _posInd - 1));
float _yPos = (float)Convert.ToDouble(_line.Substring(_posCom1Ind, _posCom2Ind - _posCom1Ind - 1));
float _zPos = (float)Convert.ToDouble(_line.Substring(_posCom2Ind, _directInd - _posCom2Ind - 1));
//Direction
float _xDirect = (float)Convert.ToDouble(_line.Substring(_directInd, _directCom1Ind - _directInd - 1));
float _yDirect = (float)Convert.ToDouble(_line.Substring(_directCom1Ind, _directCom2Ind - _directCom1Ind - 1));
float _zDirect = (float)Convert.ToDouble(_line.Substring(_directCom2Ind, _upInd - _directCom2Ind - 1));
//Direction
float _xUp = (float)Convert.ToDouble(_line.Substring(_upInd, _upCom1Ind - _upInd - 1));
float _yUp = (float)Convert.ToDouble(_line.Substring(_upCom1Ind, _upCom2Ind - _upCom1Ind - 1));
float _zUp = (float)Convert.ToDouble(_line.Substring(_upCom2Ind, _lastSpaceInd - _upCom2Ind - 1));
int _readId = Convert.ToInt32(_line.Substring(0, _posInd));
float _readScale = (float)Convert.ToDouble(_line.Substring(_lastSpaceInd, _line.Length-_lastSpaceInd));
Global._objectArray[i] = new MapStuff.MapObject(_readId, new Vector3(_xPos, _yPos, _zPos),
new Vector3(_xDirect, _yDirect, _zDirect), new Vector3(_xUp, _yUp, _zUp));
Global._objectArray[i]._scale = _readScale;
Global._objectArray[i].Load();
}
// Global._room1[i] = new MapStuff.MapObject()
i++;
}
}
}
}
}
}
sorry I m not sure how to mark things as code in here^^
looks terrible right now
well anyway, just replace the Saves + name at Create/OpenFile() with your path
Edit:
this code creates, read .txt files that look like this
in my game I have for the loadfile function if branches, deciding with the Id about what to do, for instance, id>1000 means item and they behave different etc, for the MapEditor that wasnt neccessary
though because of that I also sort the .txt file list so the items come last
you could simply make a list of your Objects and there stats, and change them in the txt file now and then…
there are probably better ways to do this than txt though
Edit2: tryed marking code now to be better shown as code… this side makes posting code a bit wierd, or I am missing something