using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Drawing; using System.Xml; using System.Xml.Serialization; using System.Resources; using System.IO; namespace SpriteLibrary { internal struct ImageStruct { internal Image TheImage; internal string ImageName; } /// /// Store of all the types of things in the ADVDemo /// public class SpriteDatabase { public List SpriteInfoList = new List(); List TheImages = new List(); ResourceManager myResourceManager = null; string Filename = ""; Size SnapGridSize = new Size(5, 5); public SpriteDatabase(ResourceManager theResourceManager, string filename) { myResourceManager = theResourceManager; Filename = filename; Load(); } internal void Load() { LoadSpriteInfo(); } internal ResourceManager GetResourceManager() { return myResourceManager; } /// /// Tell the database to save the sprite definitions. Use this while you are creating your game. /// When you are done, you will usually want to take your sprite definition file and add it to the /// resources of your game. The resources cannot be saved to, so you cannot continue to add new sprites /// once you are loading and saving them from a resources file. But, the resources file is included with /// the program when you build it. /// public void Save() { if(!DoesResourceExist(Filename)) { //we will try to save it as a file try { WriteToXmlFile>(Filename, SpriteInfoList); } catch (Exception e) { throw new Exception("SpriteDatabase failed to save: Filename:" + Filename +"\n" + "ERROR: " + e.ToString(), e); } } } public void SetSnapGridSize(Size GridSize) { if (GridSize.Width <= 0) return; if (GridSize.Height <= 0) return; if (GridSize.Width > 500) return; if (GridSize.Height > 500) return; SnapGridSize = GridSize; } //******************************* //**** Sprite Info Functions *** //******************************* #region SpriteInfo Functions void LoadSpriteInfo() { if (DoesResourceExist(Filename)) { //This clears out the old list, as it gets replaced. SpriteInfoList = LoadObjectFromXmlFile>(Filename, myResourceManager); } else { //try loading it from an actual filename if (File.Exists(Filename)) SpriteInfoList = ReadFromXmlFile>(Filename); } //If neither works, we end up with an empty file. //If it fails, SpriteInfoList is null and things explode. if (SpriteInfoList == null) SpriteInfoList = new List(); //make an empty one so things do not explode. } public List SpriteNames() { List theNames = new List(); foreach (SpriteInfo si in SpriteInfoList) { theNames.Add(si.SpriteName); } return theNames; } internal bool DoesResourceExist(string resourcename) { if (myResourceManager == null) return false; if (myResourceManager.GetObject(resourcename) != null) return true; return false; } public void OpenEditWindow(int FirstItemIndex=-1) { SpriteEntryForm SEF = new SpriteEntryForm(this, SpriteInfoList, SnapGridSize); SEF.ShowDialog(); //Use the updated list returned from the form. SpriteInfoList.Clear(); SpriteInfoList.AddRange(SEF.GetUpdatedList()); } #endregion #region General Functions public Image GetImageFromName(string Name, bool UseSmartImages) { Image MyImage = null; if (UseSmartImages) { foreach (ImageStruct IS in TheImages) { if (IS.ImageName.Equals(Name, StringComparison.InvariantCultureIgnoreCase)) { MyImage = IS.TheImage; break; } } } if (MyImage == null) { ResourceManager rm = myResourceManager; MyImage = (Bitmap)rm.GetObject(Name); if (UseSmartImages) { ImageStruct NewIS = new ImageStruct(); NewIS.ImageName = Name; NewIS.TheImage = MyImage; TheImages.Add(NewIS); } } return MyImage; } public Sprite SmartDuplicateSprite(SpriteController theController, string SpriteName, bool UseSmartImages = true) { Sprite DestSprite = theController.DuplicateSprite(SpriteName); if (DestSprite != null) return DestSprite; //If it does not exist, make it foreach (SpriteInfo SI in SpriteInfoList) { if (SI.SpriteName == SpriteName) { SI.CreateSprite(theController, this); return theController.DuplicateSprite(SpriteName); } } return null; } #endregion #region Generic XML Funcs /// /// Load in an XML serialized item from the specified ResourceManager. You will usually make one of these by /// creating an object and using SpriteDatabase.WriteToXmlFile to /// save it to a file on your desktop. Then you can drag and drop that file into your project and then use this /// LoadObjectFromXmlFile function. /// /// The type of object to load. It could be something as simple as an int, a class, or a list of classes. /// The resource item to load. If you would access it like: properties.resources.myFile, /// the correct value to put here would be "myFile" /// The resource manager. Usually Properties.Resources.ResourceManager /// An object of the value you specified. Or null if it fails. public static T LoadObjectFromXmlFile(string XMLResourceToLoad, ResourceManager MyManager) where T : new() { //Load in the sprite data XmlSerializer serializer = new XmlSerializer(typeof(T)); // Retrieves String and Image resources. object titem = MyManager.GetObject(XMLResourceToLoad); byte[] item = (byte[])System.Text.Encoding.UTF8.GetBytes((string)titem); try { return (T)serializer.Deserialize(new MemoryStream(item)); } finally { } } /// /// Writes the given object instance to an XML file. /// Only Public properties and variables will be written to the file. These can be any type though, even other classes. /// If there are public properties/variables that you do not want written to the file, decorate them with the [XmlIgnore] attribute. /// Object type must have a parameterless constructor. /// /// The type of object being written to the file. /// The file path to write the object instance to. /// The object instance to write to the file. internal static void WriteToXmlFile(string filePath, T objectToWrite) where T : new() { TextWriter writer = null; try { var serializer = new XmlSerializer(typeof(T)); writer = new StreamWriter(filePath); serializer.Serialize(writer, objectToWrite); } finally { if (writer != null) writer.Close(); } } /// /// Reads an object instance from an XML file. /// Object type must have a parameterless constructor. /// /// The type of object to read from the file. /// The file path to read the object instance from. /// Returns a new instance of the object read from the XML file. public static T ReadFromXmlFile(string filePath) where T : new() { TextReader reader = null; try { var serializer = new XmlSerializer(typeof(T)); reader = new StreamReader(filePath); return (T)serializer.Deserialize(reader); } finally { if (reader != null) reader.Close(); } } public static string WriteToXMLString(T toSerialize) { XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType()); using (StringWriter textWriter = new StringWriter()) { xmlSerializer.Serialize(textWriter, toSerialize); return textWriter.ToString(); } } public static T ReadFromXmlString(string toDeserialize) where T : new() { XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); using (StringReader textReader = new StringReader(toDeserialize)) return (T)xmlSerializer.Deserialize(textReader); } public static T CloneByXMLSerializing(T ObjectToClone) { XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); string dest; using (StringWriter textWriter = new StringWriter()) { xmlSerializer.Serialize(textWriter, ObjectToClone); dest = textWriter.ToString(); } using (StringReader textReader = new StringReader(dest)) return (T)xmlSerializer.Deserialize(textReader); } #endregion } }