TiledMapImporter.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Xml.Serialization;
  5. using Microsoft.Xna.Framework.Content.Pipeline;
  6. using MonoGame.Extended.Content.Tiled;
  7. namespace MonoGame.Extended.Content.Pipeline.Tiled
  8. {
  9. [ContentImporter(".tmx", DefaultProcessor = "TiledMapProcessor", DisplayName = "Tiled Map Importer - MonoGame.Extended")]
  10. public class TiledMapImporter : ContentImporter<TiledMapContentItem>
  11. {
  12. public override TiledMapContentItem Import(string filePath, ContentImporterContext context)
  13. {
  14. try
  15. {
  16. if (filePath == null)
  17. throw new ArgumentNullException(nameof(filePath));
  18. ContentLogger.Logger = context.Logger;
  19. ContentLogger.Log($"Importing '{filePath}'");
  20. var map = DeserializeTiledMapContent(filePath, context);
  21. if (map.Width > ushort.MaxValue || map.Height > ushort.MaxValue)
  22. throw new InvalidContentException($"The map '{filePath} is much too large. The maximum supported width and height for a Tiled map is {ushort.MaxValue}.");
  23. ContentLogger.Log($"Imported '{filePath}'");
  24. return new TiledMapContentItem(map);
  25. }
  26. catch (Exception e)
  27. {
  28. context.Logger.LogImportantMessage(e.StackTrace);
  29. throw;
  30. }
  31. }
  32. private static TiledMapContent DeserializeTiledMapContent(string mapFilePath, ContentImporterContext context)
  33. {
  34. using (var reader = new StreamReader(mapFilePath))
  35. {
  36. var mapSerializer = new XmlSerializer(typeof(TiledMapContent));
  37. var map = (TiledMapContent)mapSerializer.Deserialize(reader);
  38. map.FilePath = mapFilePath;
  39. for (var i = 0; i < map.Tilesets.Count; i++)
  40. {
  41. var tileset = map.Tilesets[i];
  42. string getTilesetSource(string source)
  43. => Path.GetFullPath(Path.Combine(Path.GetDirectoryName(mapFilePath), source));
  44. if (!string.IsNullOrWhiteSpace(tileset.Source))
  45. {
  46. tileset.Source = getTilesetSource(tileset.Source);
  47. ContentLogger.Log($"Adding dependency for {tileset.Source}");
  48. // We depend on the tileset. If the tileset changes, the map also needs to rebuild.
  49. context.AddDependency(tileset.Source);
  50. }
  51. else
  52. {
  53. tileset.Image.Source = getTilesetSource(tileset.Image.Source);
  54. ContentLogger.Log($"Adding dependency for {tileset.Image.Source}");
  55. context.AddDependency(tileset.Image.Source);
  56. }
  57. }
  58. ImportLayers(context, map.Layers, Path.GetDirectoryName(mapFilePath));
  59. map.Name = mapFilePath;
  60. return map;
  61. }
  62. }
  63. private static void ImportLayers(ContentImporterContext context, List<TiledMapLayerContent> layers, string path)
  64. {
  65. for (var i = 0; i < layers.Count; i++)
  66. {
  67. if (layers[i] is TiledMapImageLayerContent imageLayer)
  68. {
  69. imageLayer.Image.Source = Path.Combine(path, imageLayer.Image.Source);
  70. ContentLogger.Log($"Adding dependency for '{imageLayer.Image.Source}'");
  71. // Tell the pipeline that we depend on this image and need to rebuild the map if the image changes.
  72. // (Maybe the image is a different size)
  73. context.AddDependency(imageLayer.Image.Source);
  74. }
  75. if (layers[i] is TiledMapObjectLayerContent objectLayer)
  76. foreach (var obj in objectLayer.Objects)
  77. if (!String.IsNullOrWhiteSpace(obj.TemplateSource))
  78. {
  79. obj.TemplateSource = Path.Combine(path, obj.TemplateSource);
  80. ContentLogger.Log($"Adding dependency for '{obj.TemplateSource}'");
  81. // Tell the pipeline that we depend on this template and need to rebuild the map if the template changes.
  82. // (Templates are loaded into objects on process, so all objects which depend on the template file
  83. // need the change to the template)
  84. context.AddDependency(obj.TemplateSource);
  85. }
  86. if (layers[i] is TiledMapGroupLayerContent groupLayer)
  87. // Yay recursion!
  88. ImportLayers(context, groupLayer.Layers, path);
  89. }
  90. }
  91. }
  92. }