summaryrefslogtreecommitdiff
path: root/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline
diff options
context:
space:
mode:
authorchai <215380520@qq.com>2024-06-03 10:15:45 +0800
committerchai <215380520@qq.com>2024-06-03 10:15:45 +0800
commitacea7b2e728787a0d83bbf83c8c1f042d2c32e7e (patch)
tree0bfec05c1ca2d71be2c337bcd110a0421f19318b /Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline
parent88febcb02bf127d961c6471d9e846c0e1315f5c3 (diff)
+ plugins project
Diffstat (limited to 'Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline')
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorAnimation.cs24
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorFile.cs15
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorImporter.cs18
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessor.cs24
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessorResult.cs21
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorWriter.cs40
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontChar.cs41
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontCommon.cs41
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontFile.cs31
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontImporter.cs22
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontInfo.cs47
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontKerning.cs20
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontPage.cs17
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessor.cs33
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessorResult.cs16
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontWriter.cs52
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterContextExtensions.cs15
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterResult.cs14
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentItem.cs37
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentLogger.cs14
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentWriterExtensions.cs79
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentImporter.cs15
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessor.cs31
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessorResult.cs8
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentTypeWriter.cs27
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/MonoGame.Extended.Content.Pipeline.csproj25
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/PathExtensions.cs14
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentImporter.cs10
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentProcessor.cs15
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerJsonImporter.cs18
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessor.cs24
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessorResult.cs9
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerWriter.cs45
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/ContentWriterExtensions.cs26
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledContentItem.cs22
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapContentItem.cs12
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapImporter.cs108
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapObjectTemplateImporter.cs54
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapProcessor.cs324
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetContentItem.cs14
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetImporter.cs60
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetProcessor.cs44
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetWriter.cs145
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapWriter.cs227
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/readme.txt15
45 files changed, 1913 insertions, 0 deletions
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorAnimation.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorAnimation.cs
new file mode 100644
index 0000000..14638d4
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorAnimation.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ public class AstridAnimatorAnimation
+ {
+ public string Name { get; set; }
+ public int FramesPerSecond { get; set; }
+ public List<string> Frames { get; set; }
+ public bool IsLooping { get; set; }
+ public bool IsReversed { get; set; }
+ public bool IsPingPong { get; set; }
+
+ public AstridAnimatorAnimation(string name, int framesPerSecond)
+ {
+ Name = name;
+ FramesPerSecond = framesPerSecond;
+ Frames = new List<string>();
+ IsLooping = true;
+ IsReversed = false;
+ IsPingPong = false;
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorFile.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorFile.cs
new file mode 100644
index 0000000..765f2f2
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorFile.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ public class AstridAnimatorFile
+ {
+ public string TextureAtlas { get; set; }
+ public List<AstridAnimatorAnimation> Animations { get; set; }
+
+ public AstridAnimatorFile()
+ {
+ Animations = new List<AstridAnimatorAnimation>();
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorImporter.cs
new file mode 100644
index 0000000..855a0d3
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorImporter.cs
@@ -0,0 +1,18 @@
+using System.IO;
+using System.Text.Json;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ [ContentImporter(".aa", DefaultProcessor = "AstridAnimatorProcessor",
+ DisplayName = "Astrid Animator Importer - MonoGame.Extended")]
+ public class AstridAnimatorImporter : ContentImporter<ContentImporterResult<AstridAnimatorFile>>
+ {
+ public override ContentImporterResult<AstridAnimatorFile> Import(string filename, ContentImporterContext context)
+ {
+ var json = File.ReadAllText(filename);
+ var data = JsonSerializer.Deserialize<AstridAnimatorFile>(json);
+ return new ContentImporterResult<AstridAnimatorFile>(filename, data);
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessor.cs
new file mode 100644
index 0000000..e22d65b
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessor.cs
@@ -0,0 +1,24 @@
+using System.IO;
+using System.Linq;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ [ContentProcessor(DisplayName = "Astrid Animator Processor - MonoGame.Extended")]
+ public class AstridAnimatorProcessor :
+ ContentProcessor<ContentImporterResult<AstridAnimatorFile>, AstridAnimatorProcessorResult>
+ {
+ public override AstridAnimatorProcessorResult Process(ContentImporterResult<AstridAnimatorFile> input,
+ ContentProcessorContext context)
+ {
+ var data = input.Data;
+ var directory = Path.GetDirectoryName(input.FilePath);
+ var frames = data.Animations
+ .SelectMany(i => i.Frames)
+ .OrderBy(f => f)
+ .Distinct();
+
+ return new AstridAnimatorProcessorResult(directory, data, frames);
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessorResult.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessorResult.cs
new file mode 100644
index 0000000..de92ec3
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorProcessorResult.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ public class AstridAnimatorProcessorResult
+ {
+ public string TextureAtlasAssetName { get; private set; }
+ public string Directory { get; private set; }
+ public AstridAnimatorFile Data { get; private set; }
+ public List<string> Frames { get; private set; }
+
+ public AstridAnimatorProcessorResult(string directory, AstridAnimatorFile data, IEnumerable<string> frames)
+ {
+ Directory = directory;
+ Data = data;
+ Frames = new List<string>(frames);
+ TextureAtlasAssetName = Path.GetFileNameWithoutExtension(data.TextureAtlas);
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorWriter.cs
new file mode 100644
index 0000000..6f56f3f
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Animations/AstridAnimatorWriter.cs
@@ -0,0 +1,40 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+
+namespace MonoGame.Extended.Content.Pipeline.Animations
+{
+ [ContentTypeWriter]
+ public class AstridAnimatorWriter : ContentTypeWriter<AstridAnimatorProcessorResult>
+ {
+ public override string GetRuntimeReader(TargetPlatform targetPlatform)
+ {
+ return "MonoGame.Extended.Animations.SpriteSheets.SpriteSheetAnimationFactoryReader, MonoGame.Extended.Animations";
+ }
+
+ protected override void Write(ContentWriter writer, AstridAnimatorProcessorResult input)
+ {
+ var data = input.Data;
+
+ writer.Write(input.TextureAtlasAssetName);
+ writer.Write(input.Frames.Count);
+
+ foreach (var frame in input.Frames)
+ writer.Write(frame);
+
+ writer.Write(data.Animations.Count);
+
+ foreach (var animation in data.Animations)
+ {
+ writer.Write(animation.Name);
+ writer.Write(animation.FramesPerSecond);
+ writer.Write(animation.IsLooping);
+ writer.Write(animation.IsReversed);
+ writer.Write(animation.IsPingPong);
+ writer.Write(animation.Frames.Count);
+
+ foreach (var frame in animation.Frames)
+ writer.Write(input.Frames.IndexOf(frame));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontChar.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontChar.cs
new file mode 100644
index 0000000..c012da4
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontChar.cs
@@ -0,0 +1,41 @@
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ public class BitmapFontChar
+ {
+ [XmlAttribute("id")]
+ public int Id { get; set; }
+
+ [XmlAttribute("x")]
+ public int X { get; set; }
+
+ [XmlAttribute("y")]
+ public int Y { get; set; }
+
+ [XmlAttribute("width")]
+ public int Width { get; set; }
+
+ [XmlAttribute("height")]
+ public int Height { get; set; }
+
+ [XmlAttribute("xoffset")]
+ public int XOffset { get; set; }
+
+ [XmlAttribute("yoffset")]
+ public int YOffset { get; set; }
+
+ [XmlAttribute("xadvance")]
+ public int XAdvance { get; set; }
+
+ [XmlAttribute("page")]
+ public int Page { get; set; }
+
+ [XmlAttribute("chnl")]
+ public int Channel { get; set; }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontCommon.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontCommon.cs
new file mode 100644
index 0000000..6247fcf
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontCommon.cs
@@ -0,0 +1,41 @@
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ public class BitmapFontCommon
+ {
+ [XmlAttribute("lineHeight")]
+ public int LineHeight { get; set; }
+
+ [XmlAttribute("base")]
+ public int Base { get; set; }
+
+ [XmlAttribute("scaleW")]
+ public int ScaleW { get; set; }
+
+ [XmlAttribute("scaleH")]
+ public int ScaleH { get; set; }
+
+ [XmlAttribute("pages")]
+ public int Pages { get; set; }
+
+ [XmlAttribute("packed")]
+ public int Packed { get; set; }
+
+ [XmlAttribute("alphaChnl")]
+ public int AlphaChannel { get; set; }
+
+ [XmlAttribute("redChnl")]
+ public int RedChannel { get; set; }
+
+ [XmlAttribute("greenChnl")]
+ public int GreenChannel { get; set; }
+
+ [XmlAttribute("blueChnl")]
+ public int BlueChannel { get; set; }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontFile.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontFile.cs
new file mode 100644
index 0000000..db77270
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontFile.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ [XmlRoot("font")]
+ public class BitmapFontFile
+ {
+ [XmlElement("info")]
+ public BitmapFontInfo Info { get; set; }
+
+ [XmlElement("common")]
+ public BitmapFontCommon Common { get; set; }
+
+ [XmlArray("pages")]
+ [XmlArrayItem("page")]
+ public List<BitmapFontPage> Pages { get; set; }
+
+ [XmlArray("chars")]
+ [XmlArrayItem("char")]
+ public List<BitmapFontChar> Chars { get; set; }
+
+ [XmlArray("kernings")]
+ [XmlArrayItem("kerning")]
+ public List<BitmapFontKerning> Kernings { get; set; }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontImporter.cs
new file mode 100644
index 0000000..ea4c528
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontImporter.cs
@@ -0,0 +1,22 @@
+using System.IO;
+using System.Xml.Serialization;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ [ContentImporter(".fnt", DefaultProcessor = "BitmapFontProcessor",
+ DisplayName = "BMFont Importer - MonoGame.Extended")]
+ public class BitmapFontImporter : ContentImporter<BitmapFontFile>
+ {
+ public override BitmapFontFile Import(string filename, ContentImporterContext context)
+ {
+ context.Logger.LogMessage("Importing XML file: {0}", filename);
+
+ using (var streamReader = new StreamReader(filename))
+ {
+ var deserializer = new XmlSerializer(typeof(BitmapFontFile));
+ return (BitmapFontFile)deserializer.Deserialize(streamReader);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontInfo.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontInfo.cs
new file mode 100644
index 0000000..1f50cf8
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontInfo.cs
@@ -0,0 +1,47 @@
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ public class BitmapFontInfo
+ {
+ [XmlAttribute("face")]
+ public string Face { get; set; }
+
+ [XmlAttribute("size")]
+ public int Size { get; set; }
+
+ [XmlAttribute("bold")]
+ public int Bold { get; set; }
+
+ [XmlAttribute("italic")]
+ public int Italic { get; set; }
+
+ [XmlAttribute("charset")]
+ public string CharSet { get; set; }
+
+ [XmlAttribute("unicode")]
+ public int Unicode { get; set; }
+
+ [XmlAttribute("stretchH")]
+ public int StretchHeight { get; set; }
+
+ [XmlAttribute("smooth")]
+ public int Smooth { get; set; }
+
+ [XmlAttribute("aa")]
+ public int SuperSampling { get; set; }
+
+ [XmlAttribute("padding")]
+ public string Padding { get; set; }
+
+ [XmlAttribute("spacing")]
+ public string Spacing { get; set; }
+
+ [XmlAttribute("outline")]
+ public int OutLine { get; set; }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontKerning.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontKerning.cs
new file mode 100644
index 0000000..77caf13
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontKerning.cs
@@ -0,0 +1,20 @@
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ public class BitmapFontKerning
+ {
+ [XmlAttribute("first")]
+ public int First { get; set; }
+
+ [XmlAttribute("second")]
+ public int Second { get; set; }
+
+ [XmlAttribute("amount")]
+ public int Amount { get; set; }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontPage.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontPage.cs
new file mode 100644
index 0000000..3841ff5
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontPage.cs
@@ -0,0 +1,17 @@
+using System.Xml.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ // ---- AngelCode BmFont XML serializer ----------------------
+ // ---- By DeadlyDan @ deadlydan@gmail.com -------------------
+ // ---- There's no license restrictions, use as you will. ----
+ // ---- Credits to http://www.angelcode.com/ -----------------
+ public class BitmapFontPage
+ {
+ [XmlAttribute("id")]
+ public int Id { get; set; }
+
+ [XmlAttribute("file")]
+ public string File { get; set; }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessor.cs
new file mode 100644
index 0000000..a859eb5
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessor.cs
@@ -0,0 +1,33 @@
+using System;
+using System.IO;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ [ContentProcessor(DisplayName = "BMFont Processor - MonoGame.Extended")]
+ public class BitmapFontProcessor : ContentProcessor<BitmapFontFile, BitmapFontProcessorResult>
+ {
+ public override BitmapFontProcessorResult Process(BitmapFontFile bitmapFontFile, ContentProcessorContext context)
+ {
+ try
+ {
+ context.Logger.LogMessage("Processing BMFont");
+ var result = new BitmapFontProcessorResult(bitmapFontFile);
+
+ foreach (var fontPage in bitmapFontFile.Pages)
+ {
+ var assetName = Path.GetFileNameWithoutExtension(fontPage.File);
+ context.Logger.LogMessage("Expected texture asset: {0}", assetName);
+ result.TextureAssets.Add(assetName);
+ }
+
+ return result;
+ }
+ catch (Exception ex)
+ {
+ context.Logger.LogMessage("Error {0}", ex);
+ throw;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessorResult.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessorResult.cs
new file mode 100644
index 0000000..5841acc
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontProcessorResult.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ public class BitmapFontProcessorResult
+ {
+ public List<string> TextureAssets { get; private set; }
+ public BitmapFontFile FontFile { get; private set; }
+
+ public BitmapFontProcessorResult(BitmapFontFile fontFile)
+ {
+ FontFile = fontFile;
+ TextureAssets = new List<string>();
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontWriter.cs
new file mode 100644
index 0000000..343c40c
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/BitmapFonts/BitmapFontWriter.cs
@@ -0,0 +1,52 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+
+namespace MonoGame.Extended.Content.Pipeline.BitmapFonts
+{
+ [ContentTypeWriter]
+ public class BitmapFontWriter : ContentTypeWriter<BitmapFontProcessorResult>
+ {
+ protected override void Write(ContentWriter writer, BitmapFontProcessorResult result)
+ {
+ writer.Write(result.TextureAssets.Count);
+
+ foreach (var textureAsset in result.TextureAssets)
+ writer.Write(textureAsset);
+
+ var fontFile = result.FontFile;
+ writer.Write(fontFile.Common.LineHeight);
+ writer.Write(fontFile.Chars.Count);
+
+ foreach (var c in fontFile.Chars)
+ {
+ writer.Write(c.Id);
+ writer.Write(c.Page);
+ writer.Write(c.X);
+ writer.Write(c.Y);
+ writer.Write(c.Width);
+ writer.Write(c.Height);
+ writer.Write(c.XOffset);
+ writer.Write(c.YOffset);
+ writer.Write(c.XAdvance);
+ }
+
+ writer.Write(fontFile.Kernings.Count);
+ foreach(var k in fontFile.Kernings)
+ {
+ writer.Write(k.First);
+ writer.Write(k.Second);
+ writer.Write(k.Amount);
+ }
+ }
+
+ public override string GetRuntimeType(TargetPlatform targetPlatform)
+ {
+ return "MonoGame.Extended.BitmapFonts.BitmapFont, MonoGame.Extended";
+ }
+
+ public override string GetRuntimeReader(TargetPlatform targetPlatform)
+ {
+ return "MonoGame.Extended.BitmapFonts.BitmapFontReader, MonoGame.Extended";
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterContextExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterContextExtensions.cs
new file mode 100644
index 0000000..7f63815
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterContextExtensions.cs
@@ -0,0 +1,15 @@
+using System.IO;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline;
+
+public static class ContentImporterContextExtensions
+{
+ public static string AddDependencyWithLogging(this ContentImporterContext context, string filePath, string source)
+ {
+ source = Path.Combine(Path.GetDirectoryName(filePath), source);
+ ContentLogger.Log($"Adding dependency '{source}'");
+ context.AddDependency(source);
+ return source;
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterResult.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterResult.cs
new file mode 100644
index 0000000..e302ca7
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentImporterResult.cs
@@ -0,0 +1,14 @@
+namespace MonoGame.Extended.Content.Pipeline
+{
+ public class ContentImporterResult<T>
+ {
+ public ContentImporterResult(string filePath, T data)
+ {
+ FilePath = filePath;
+ Data = data;
+ }
+
+ public string FilePath { get; }
+ public T Data { get; }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentItem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentItem.cs
new file mode 100644
index 0000000..e69d48e
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentItem.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline
+{
+ public interface IExternalReferenceRepository
+ {
+ ExternalReference<TInput> GetExternalReference<TInput>(string source);
+ }
+
+ public class ContentItem<T> : ContentItem, IExternalReferenceRepository
+ {
+ public ContentItem(T data)
+ {
+ Data = data;
+ }
+
+ public T Data { get; }
+
+ private readonly Dictionary<string, ContentItem> _externalReferences = new Dictionary<string, ContentItem>();
+
+ public void BuildExternalReference<TInput>(ContentProcessorContext context, string source, OpaqueDataDictionary parameters = null)
+ {
+ var sourceAsset = new ExternalReference<TInput>(source);
+ var externalReference = context.BuildAsset<TInput, TInput>(sourceAsset, "", parameters, "", "");
+ _externalReferences.Add(source, externalReference);
+ }
+
+ public ExternalReference<TInput> GetExternalReference<TInput>(string source)
+ {
+ if (source is not null && _externalReferences.TryGetValue(source, out var contentItem))
+ return contentItem as ExternalReference<TInput>;
+
+ return null;
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentLogger.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentLogger.cs
new file mode 100644
index 0000000..83848a1
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentLogger.cs
@@ -0,0 +1,14 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline
+{
+ public class ContentLogger
+ {
+ public static ContentBuildLogger Logger { get; set; }
+
+ public static void Log(string message)
+ {
+ Logger?.LogMessage(message);
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentWriterExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentWriterExtensions.cs
new file mode 100644
index 0000000..b8cf9d2
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/ContentWriterExtensions.cs
@@ -0,0 +1,79 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+
+namespace MonoGame.Extended.Content.Pipeline
+{
+ public static class ContentWriterExtensions
+ {
+ public static void Write(this ContentWriter contentWriter, Color value)
+ {
+ contentWriter.Write(value.R);
+ contentWriter.Write(value.G);
+ contentWriter.Write(value.B);
+ contentWriter.Write(value.A);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Matrix value)
+ {
+ contentWriter.Write(value.M11);
+ contentWriter.Write(value.M12);
+ contentWriter.Write(value.M13);
+ contentWriter.Write(value.M14);
+ contentWriter.Write(value.M21);
+ contentWriter.Write(value.M22);
+ contentWriter.Write(value.M23);
+ contentWriter.Write(value.M24);
+ contentWriter.Write(value.M31);
+ contentWriter.Write(value.M32);
+ contentWriter.Write(value.M33);
+ contentWriter.Write(value.M34);
+ contentWriter.Write(value.M41);
+ contentWriter.Write(value.M42);
+ contentWriter.Write(value.M43);
+ contentWriter.Write(value.M44);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Quaternion value)
+ {
+ contentWriter.Write(value.X);
+ contentWriter.Write(value.Y);
+ contentWriter.Write(value.Z);
+ contentWriter.Write(value.W);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Vector2 value)
+ {
+ contentWriter.Write(value.X);
+ contentWriter.Write(value.Y);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Vector3 value)
+ {
+ contentWriter.Write(value.X);
+ contentWriter.Write(value.Y);
+ contentWriter.Write(value.Z);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Vector4 value)
+ {
+ contentWriter.Write(value.X);
+ contentWriter.Write(value.Y);
+ contentWriter.Write(value.Z);
+ contentWriter.Write(value.W);
+ }
+
+ public static void Write(this ContentWriter contentWriter, BoundingSphere value)
+ {
+ contentWriter.Write(value.Center);
+ contentWriter.Write(value.Radius);
+ }
+
+ public static void Write(this ContentWriter contentWriter, Rectangle value)
+ {
+ contentWriter.Write(value.X);
+ contentWriter.Write(value.Y);
+ contentWriter.Write(value.Width);
+ contentWriter.Write(value.Height);
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentImporter.cs
new file mode 100644
index 0000000..437d7eb
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentImporter.cs
@@ -0,0 +1,15 @@
+using System.IO;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.Json
+{
+ [ContentImporter(".json", DefaultProcessor = nameof(JsonContentProcessor), DisplayName = "JSON Importer - MonoGame.Extended")]
+ public class JsonContentImporter : ContentImporter<ContentImporterResult<string>>
+ {
+ public override ContentImporterResult<string> Import(string filename, ContentImporterContext context)
+ {
+ var json = File.ReadAllText(filename);
+ return new ContentImporterResult<string>(filename, json);
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessor.cs
new file mode 100644
index 0000000..6be4ac3
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessor.cs
@@ -0,0 +1,31 @@
+using System;
+using System.ComponentModel;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace MonoGame.Extended.Content.Pipeline.Json
+{
+ [ContentProcessor(DisplayName = "JSON Processor - MonoGame.Extended")]
+ public class JsonContentProcessor : ContentProcessor<ContentImporterResult<string>, JsonContentProcessorResult>
+ {
+ [DefaultValue(typeof(Type), "System.Object")]
+ public string ContentType { get; set; }
+
+ public override JsonContentProcessorResult Process(ContentImporterResult<string> input, ContentProcessorContext context)
+ {
+ try
+ {
+ var output = new JsonContentProcessorResult
+ {
+ ContentType = ContentType,
+ Json = input.Data
+ };
+ return output;
+ }
+ catch (Exception ex)
+ {
+ context.Logger.LogMessage("Error {0}", ex);
+ throw;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessorResult.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessorResult.cs
new file mode 100644
index 0000000..eaef99e
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentProcessorResult.cs
@@ -0,0 +1,8 @@
+namespace MonoGame.Extended.Content.Pipeline.Json
+{
+ public class JsonContentProcessorResult
+ {
+ public string ContentType { get; set; }
+ public string Json { get; set; }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentTypeWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentTypeWriter.cs
new file mode 100644
index 0000000..6efa696
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Json/JsonContentTypeWriter.cs
@@ -0,0 +1,27 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+
+namespace MonoGame.Extended.Content.Pipeline.Json
+{
+ [ContentTypeWriter]
+ public class JsonContentTypeWriter : ContentTypeWriter<JsonContentProcessorResult>
+ {
+ private string _runtimeType;
+
+ protected override void Write(ContentWriter writer, JsonContentProcessorResult result)
+ {
+ _runtimeType = result.ContentType;
+ writer.Write(result.Json);
+ }
+
+ public override string GetRuntimeReader(TargetPlatform targetPlatform)
+ {
+ return _runtimeType;// "MonoGame.Extended.Serialization.SpriteFactoryContentTypeReader, MonoGame.Extended";
+ }
+
+ public override string GetRuntimeType(TargetPlatform targetPlatform)
+ {
+ return _runtimeType;// "MonoGame.Extended.Serialization.SpriteFactoryContentTypeReader, MonoGame.Extended";
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/MonoGame.Extended.Content.Pipeline.csproj b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/MonoGame.Extended.Content.Pipeline.csproj
new file mode 100644
index 0000000..70b81e8
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/MonoGame.Extended.Content.Pipeline.csproj
@@ -0,0 +1,25 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <ItemGroup>
+ <Content Include="$(ArtifactsPath)/bin/MonoGame.Extended.Content.Pipeline/release/*.dll" Pack="True" PackagePath="tools" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <Description>Content Pipeline importers and processors to make MonoGame more awesome.</Description>
+ <PackageTags>monogame content importer processor reader tiled texturepacker bmfont animations</PackageTags>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Autofac" Version="5.2.0" />
+
+ <PackageReference Include="MonoGame.Framework.Content.Pipeline"
+ Version="3.8.1.303"
+ PrivateAssets="All" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\MonoGame.Extended.Tiled\MonoGame.Extended.Tiled.csproj" />
+ <ProjectReference Include="..\MonoGame.Extended\MonoGame.Extended.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/PathExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/PathExtensions.cs
new file mode 100644
index 0000000..b85afb5
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/PathExtensions.cs
@@ -0,0 +1,14 @@
+using System;
+using System.IO;
+
+namespace MonoGame.Extended.Content.Pipeline
+{
+ public static class PathExtensions
+ {
+ public static string GetApplicationFullPath(params string[] pathParts)
+ {
+ var path = Path.Combine(pathParts);
+ return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path);
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentImporter.cs
new file mode 100644
index 0000000..3c4607d
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentImporter.cs
@@ -0,0 +1,10 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using MonoGame.Extended.Content.Pipeline.Json;
+
+namespace MonoGame.Extended.Content.Pipeline.SpriteFactory
+{
+ [ContentImporter(".sf", DefaultProcessor = nameof(SpriteFactoryContentProcessor), DisplayName = "Sprite Factory Importer - MonoGame.Extended")]
+ public class SpriteFactoryContentImporter : JsonContentImporter
+ {
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentProcessor.cs
new file mode 100644
index 0000000..4920f33
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/SpriteFactory/SpriteFactoryContentProcessor.cs
@@ -0,0 +1,15 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using MonoGame.Extended.Content.Pipeline.Json;
+
+namespace MonoGame.Extended.Content.Pipeline.SpriteFactory
+{
+ [ContentProcessor(DisplayName = "Sprite Factory Processor - MonoGame.Extended")]
+ public class SpriteFactoryContentProcessor : JsonContentProcessor
+ {
+ public SpriteFactoryContentProcessor()
+ {
+ ContentType = "MonoGame.Extended MonoGame.Extended.Animations.SpriteFactory.SpriteFactoryFileReader, MonoGame.Extended.Animations";
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerJsonImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerJsonImporter.cs
new file mode 100644
index 0000000..a80e654
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerJsonImporter.cs
@@ -0,0 +1,18 @@
+using System.IO;
+using System.Text.Json;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using MonoGame.Extended.TextureAtlases;
+
+
+namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
+{
+ [ContentImporter(".json", DefaultProcessor = "TexturePackerProcessor", DisplayName = "TexturePacker JSON Importer - MonoGame.Extended")]
+ public class TexturePackerJsonImporter : ContentImporter<TexturePackerFile>
+ {
+ public override TexturePackerFile Import(string filename, ContentImporterContext context)
+ {
+ var json = File.ReadAllText(filename);
+ return JsonSerializer.Deserialize<TexturePackerFile>(json);
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessor.cs
new file mode 100644
index 0000000..1f14ee7
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessor.cs
@@ -0,0 +1,24 @@
+using System;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using MonoGame.Extended.TextureAtlases;
+
+namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
+{
+ [ContentProcessor(DisplayName = "TexturePacker Processor - MonoGame.Extended")]
+ public class TexturePackerProcessor : ContentProcessor<TexturePackerFile, TexturePackerProcessorResult>
+ {
+ public override TexturePackerProcessorResult Process(TexturePackerFile input, ContentProcessorContext context)
+ {
+ try
+ {
+ var output = new TexturePackerProcessorResult {Data = input};
+ return output;
+ }
+ catch (Exception ex)
+ {
+ context.Logger.LogMessage("Error {0}", ex);
+ throw;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessorResult.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessorResult.cs
new file mode 100644
index 0000000..a996259
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerProcessorResult.cs
@@ -0,0 +1,9 @@
+using MonoGame.Extended.TextureAtlases;
+
+namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
+{
+ public class TexturePackerProcessorResult
+ {
+ public TexturePackerFile Data { get; set; }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerWriter.cs
new file mode 100644
index 0000000..3fd15ff
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/TextureAtlases/TexturePackerWriter.cs
@@ -0,0 +1,45 @@
+using System.Diagnostics;
+using System.IO;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+
+namespace MonoGame.Extended.Content.Pipeline.TextureAtlases
+{
+ [ContentTypeWriter]
+ public class TexturePackerWriter : ContentTypeWriter<TexturePackerProcessorResult>
+ {
+ protected override void Write(ContentWriter writer, TexturePackerProcessorResult result)
+ {
+ var data = result.Data;
+ var metadata = data.Metadata;
+
+ var assetName = Path.GetFileNameWithoutExtension(metadata.Image);
+ Debug.Assert(assetName != null, "assetName != null");
+
+ writer.Write(assetName);
+ writer.Write(data.Regions.Count);
+
+ foreach (var region in data.Regions)
+ {
+ var regionName = Path.ChangeExtension(region.Filename, null);
+ Debug.Assert(regionName != null, "regionName != null");
+
+ writer.Write(regionName);
+ writer.Write(region.Frame.X);
+ writer.Write(region.Frame.Y);
+ writer.Write(region.Frame.Width);
+ writer.Write(region.Frame.Height);
+ }
+ }
+
+ public override string GetRuntimeType(TargetPlatform targetPlatform)
+ {
+ return "MonoGame.Extended.TextureAtlases.TextureAtlas, MonoGame.Extended";
+ }
+
+ public override string GetRuntimeReader(TargetPlatform targetPlatform)
+ {
+ return "MonoGame.Extended.TextureAtlases.TextureAtlasReader, MonoGame.Extended";
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/ContentWriterExtensions.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/ContentWriterExtensions.cs
new file mode 100644
index 0000000..28ded17
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/ContentWriterExtensions.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ public static class ContentWriterExtensions
+ {
+ // ReSharper disable once SuggestBaseTypeForParameter
+ public static void WriteTiledMapProperties(this ContentWriter writer, IReadOnlyCollection<TiledMapPropertyContent> value)
+ {
+ if (value == null)
+ {
+ writer.Write(0);
+ return;
+ }
+ writer.Write(value.Count);
+ foreach (var property in value)
+ {
+ writer.Write(property.Name);
+ writer.Write(property.Value ?? string.Empty);
+ WriteTiledMapProperties(writer, property.Properties);
+ }
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledContentItem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledContentItem.cs
new file mode 100644
index 0000000..b376252
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledContentItem.cs
@@ -0,0 +1,22 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled;
+
+public class TiledContentItem<T>: ContentItem<T>
+{
+ public TiledContentItem(T data) : base(data)
+ {
+ }
+
+ public void BuildExternalReference<T>(ContentProcessorContext context, TiledMapImageContent image)
+ {
+ var parameters = new OpaqueDataDictionary
+ {
+ { "ColorKeyColor", image.TransparentColor },
+ { "ColorKeyEnabled", true }
+ };
+ BuildExternalReference<Texture2DContent>(context, image.Source, parameters);
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapContentItem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapContentItem.cs
new file mode 100644
index 0000000..b0b7b5d
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapContentItem.cs
@@ -0,0 +1,12 @@
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ public class TiledMapContentItem : TiledContentItem<TiledMapContent>
+ {
+ public TiledMapContentItem(TiledMapContent data)
+ : base(data)
+ {
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapImporter.cs
new file mode 100644
index 0000000..70e2bee
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapImporter.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml.Serialization;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentImporter(".tmx", DefaultProcessor = "TiledMapProcessor", DisplayName = "Tiled Map Importer - MonoGame.Extended")]
+ public class TiledMapImporter : ContentImporter<TiledMapContentItem>
+ {
+ public override TiledMapContentItem Import(string filePath, ContentImporterContext context)
+ {
+ try
+ {
+ if (filePath == null)
+ throw new ArgumentNullException(nameof(filePath));
+
+ ContentLogger.Logger = context.Logger;
+ ContentLogger.Log($"Importing '{filePath}'");
+
+ var map = DeserializeTiledMapContent(filePath, context);
+
+ if (map.Width > ushort.MaxValue || map.Height > ushort.MaxValue)
+ throw new InvalidContentException($"The map '{filePath} is much too large. The maximum supported width and height for a Tiled map is {ushort.MaxValue}.");
+
+ ContentLogger.Log($"Imported '{filePath}'");
+
+ return new TiledMapContentItem(map);
+
+ }
+ catch (Exception e)
+ {
+ context.Logger.LogImportantMessage(e.StackTrace);
+ throw;
+ }
+ }
+
+ private static TiledMapContent DeserializeTiledMapContent(string mapFilePath, ContentImporterContext context)
+ {
+ using (var reader = new StreamReader(mapFilePath))
+ {
+ var mapSerializer = new XmlSerializer(typeof(TiledMapContent));
+ var map = (TiledMapContent)mapSerializer.Deserialize(reader);
+
+ map.FilePath = mapFilePath;
+
+ for (var i = 0; i < map.Tilesets.Count; i++)
+ {
+ var tileset = map.Tilesets[i];
+
+ string getTilesetSource(string source)
+ => Path.GetFullPath(Path.Combine(Path.GetDirectoryName(mapFilePath), source));
+
+ if (!string.IsNullOrWhiteSpace(tileset.Source))
+ {
+ tileset.Source = getTilesetSource(tileset.Source);
+ ContentLogger.Log($"Adding dependency for {tileset.Source}");
+ // We depend on the tileset. If the tileset changes, the map also needs to rebuild.
+ context.AddDependency(tileset.Source);
+ }
+ else
+ {
+ tileset.Image.Source = getTilesetSource(tileset.Image.Source);
+ ContentLogger.Log($"Adding dependency for {tileset.Image.Source}");
+ context.AddDependency(tileset.Image.Source);
+ }
+ }
+
+ ImportLayers(context, map.Layers, Path.GetDirectoryName(mapFilePath));
+
+ map.Name = mapFilePath;
+ return map;
+ }
+ }
+
+ private static void ImportLayers(ContentImporterContext context, List<TiledMapLayerContent> layers, string path)
+ {
+ for (var i = 0; i < layers.Count; i++)
+ {
+ if (layers[i] is TiledMapImageLayerContent imageLayer)
+ {
+ imageLayer.Image.Source = Path.Combine(path, imageLayer.Image.Source);
+ ContentLogger.Log($"Adding dependency for '{imageLayer.Image.Source}'");
+
+ // Tell the pipeline that we depend on this image and need to rebuild the map if the image changes.
+ // (Maybe the image is a different size)
+ context.AddDependency(imageLayer.Image.Source);
+ }
+ if (layers[i] is TiledMapObjectLayerContent objectLayer)
+ foreach (var obj in objectLayer.Objects)
+ if (!String.IsNullOrWhiteSpace(obj.TemplateSource))
+ {
+ obj.TemplateSource = Path.Combine(path, obj.TemplateSource);
+ ContentLogger.Log($"Adding dependency for '{obj.TemplateSource}'");
+ // Tell the pipeline that we depend on this template and need to rebuild the map if the template changes.
+ // (Templates are loaded into objects on process, so all objects which depend on the template file
+ // need the change to the template)
+ context.AddDependency(obj.TemplateSource);
+ }
+ if (layers[i] is TiledMapGroupLayerContent groupLayer)
+ // Yay recursion!
+ ImportLayers(context, groupLayer.Layers, path);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapObjectTemplateImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapObjectTemplateImporter.cs
new file mode 100644
index 0000000..eeddcaa
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapObjectTemplateImporter.cs
@@ -0,0 +1,54 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using System;
+using System.IO;
+using System.Xml.Serialization;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentImporter(".tx", DefaultProcessor = "TiledMapObjectTemplateProcessor", DisplayName = "Tiled Map Object Template Importer - MonoGame.Extended")]
+ public class TiledMapObjectTemplateImporter : ContentImporter<TiledMapObjectTemplateContent>
+ {
+ public override TiledMapObjectTemplateContent Import(string filePath, ContentImporterContext context)
+ {
+ try
+ {
+ if (filePath == null)
+ throw new ArgumentNullException(nameof(filePath));
+
+ ContentLogger.Logger = context.Logger;
+ ContentLogger.Log($"Importing '{filePath}'");
+
+ var template = DeserializeTileMapObjectTemplateContent(filePath, context);
+
+ ContentLogger.Log($"Imported '{filePath}'");
+
+ return template;
+ }
+ catch (Exception e)
+ {
+ context.Logger.LogImportantMessage(e.StackTrace);
+ return null;
+ }
+ }
+
+ private static TiledMapObjectTemplateContent DeserializeTileMapObjectTemplateContent(string filePath, ContentImporterContext context)
+ {
+ using (var reader = new StreamReader(filePath))
+ {
+ var templateSerializer = new XmlSerializer(typeof(TiledMapObjectTemplateContent));
+ var template = (TiledMapObjectTemplateContent)templateSerializer.Deserialize(reader);
+
+ if (!string.IsNullOrWhiteSpace(template.Tileset?.Source))
+ {
+ template.Tileset.Source = Path.Combine(Path.GetDirectoryName(filePath), template.Tileset.Source);
+ ContentLogger.Log($"Adding dependency '{template.Tileset.Source}'");
+ // We depend on this tileset.
+ context.AddDependency(template.Tileset.Source);
+ }
+
+ return template;
+ }
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapProcessor.cs
new file mode 100644
index 0000000..9668a72
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapProcessor.cs
@@ -0,0 +1,324 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using MonoGame.Extended.Tiled;
+using MonoGame.Extended.Tiled.Serialization;
+using MonoGame.Framework.Utilities.Deflate;
+using CompressionMode = System.IO.Compression.CompressionMode;
+using GZipStream = System.IO.Compression.GZipStream;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ public static class TiledMapContentHelper
+ {
+ public static void Process(TiledMapObjectContent obj, ContentProcessorContext context)
+ {
+ if (!string.IsNullOrWhiteSpace(obj.TemplateSource))
+ {
+ var externalReference = new ExternalReference<TiledMapObjectLayerContent>(obj.TemplateSource);
+ var template = context.BuildAndLoadAsset<TiledMapObjectLayerContent, TiledMapObjectTemplateContent>(externalReference, "");
+
+ // Nothing says a template can't reference another template.
+ // Yay recusion!
+ Process(template.Object, context);
+
+ if (!obj._globalIdentifier.HasValue && template.Object._globalIdentifier.HasValue)
+ obj.GlobalIdentifier = template.Object.GlobalIdentifier;
+
+ if (!obj._height.HasValue && template.Object._height.HasValue)
+ obj.Height = template.Object.Height;
+
+ if (!obj._identifier.HasValue && template.Object._identifier.HasValue)
+ obj.Identifier = template.Object.Identifier;
+
+ if (!obj._rotation.HasValue && template.Object._rotation.HasValue)
+ obj.Rotation = template.Object.Rotation;
+
+ if (!obj._visible.HasValue && template.Object._visible.HasValue)
+ obj.Visible = template.Object.Visible;
+
+ if (!obj._width.HasValue && template.Object._width.HasValue)
+ obj.Width = template.Object.Width;
+
+ if (!obj._x.HasValue && template.Object._x.HasValue)
+ obj.X = template.Object.X;
+
+ if (!obj._y.HasValue && template.Object._y.HasValue)
+ obj.Y = template.Object.Y;
+
+ if (obj.Ellipse == null && template.Object.Ellipse != null)
+ obj.Ellipse = template.Object.Ellipse;
+
+ if (string.IsNullOrWhiteSpace(obj.Name) && !string.IsNullOrWhiteSpace(template.Object.Name))
+ obj.Name = template.Object.Name;
+
+ if (obj.Polygon == null && template.Object.Polygon != null)
+ obj.Polygon = template.Object.Polygon;
+
+ if (obj.Polyline == null && template.Object.Polyline != null)
+ obj.Polyline = template.Object.Polyline;
+
+ foreach (var tProperty in template.Object.Properties)
+ {
+ if (!obj.Properties.Exists(p => p.Name == tProperty.Name))
+ obj.Properties.Add(tProperty);
+ }
+
+ if (string.IsNullOrWhiteSpace(obj.Type) && !string.IsNullOrWhiteSpace(template.Object.Type))
+ obj.Type = template.Object.Type;
+
+ if (string.IsNullOrWhiteSpace(obj.Class) && !string.IsNullOrWhiteSpace(template.Object.Class))
+ obj.Class = template.Object.Class;
+ }
+ }
+ }
+
+
+ [ContentProcessor(DisplayName = "Tiled Map Processor - MonoGame.Extended")]
+ public class TiledMapProcessor : ContentProcessor<TiledMapContentItem, TiledMapContentItem>
+ {
+ public override TiledMapContentItem Process(TiledMapContentItem contentItem, ContentProcessorContext context)
+ {
+ try
+ {
+ ContentLogger.Logger = context.Logger;
+ var map = contentItem.Data;
+
+ if (map.Orientation == TiledMapOrientationContent.Hexagonal || map.Orientation == TiledMapOrientationContent.Staggered)
+ throw new NotSupportedException($"{map.Orientation} Tiled Maps are currently not implemented!");
+
+ foreach (var tileset in map.Tilesets)
+ {
+ if (string.IsNullOrWhiteSpace(tileset.Source))
+ {
+ // Load the Texture2DContent for the tileset as it will be saved into the map content file.
+ contentItem.BuildExternalReference<Texture2DContent>(context, tileset.Image);
+ }
+ else
+ {
+ // Link to the tileset for the content loader to load at runtime.
+ //var externalReference = new ExternalReference<TiledMapTilesetContent>(tileset.Source);
+ //tileset.Content = context.BuildAsset<TiledMapTilesetContent, TiledMapTilesetContent>(externalReference, "");
+ contentItem.BuildExternalReference<TiledMapTilesetContent>(context, tileset.Source);
+ }
+ }
+
+ ProcessLayers(contentItem, map, context, map.Layers);
+
+ return contentItem;
+ }
+ catch (Exception ex)
+ {
+ context.Logger.LogImportantMessage(ex.Message);
+ throw;
+ }
+ }
+
+ private static void ProcessLayers(TiledMapContentItem contentItem, TiledMapContent map, ContentProcessorContext context, List<TiledMapLayerContent> layers)
+ {
+ foreach (var layer in layers)
+ {
+ switch (layer)
+ {
+ case TiledMapImageLayerContent imageLayer:
+ ContentLogger.Log($"Processing image layer '{imageLayer.Name}'");
+ contentItem.BuildExternalReference<Texture2DContent>(context, imageLayer.Image);
+ ContentLogger.Log($"Processed image layer '{imageLayer.Name}'");
+ break;
+
+ case TiledMapTileLayerContent tileLayer when tileLayer.Data.Chunks.Count > 0:
+ throw new NotSupportedException($"{map.FilePath} contains data chunks. These are currently not supported.");
+
+ case TiledMapTileLayerContent tileLayer:
+ var data = tileLayer.Data;
+ var encodingType = data.Encoding ?? "xml";
+ var compressionType = data.Compression ?? "xml";
+
+ ContentLogger.Log($"Processing tile layer '{tileLayer.Name}': Encoding: '{encodingType}', Compression: '{compressionType}'");
+ var tileData = DecodeTileLayerData(encodingType, tileLayer);
+ var tiles = CreateTiles(map.RenderOrder, map.Width, map.Height, tileData);
+ tileLayer.Tiles = tiles;
+ ContentLogger.Log($"Processed tile layer '{tileLayer}': {tiles.Length} tiles");
+ break;
+
+ case TiledMapObjectLayerContent objectLayer:
+ ContentLogger.Log($"Processing object layer '{objectLayer.Name}'");
+
+ foreach (var obj in objectLayer.Objects)
+ TiledMapContentHelper.Process(obj, context);
+
+ ContentLogger.Log($"Processed object layer '{objectLayer.Name}'");
+ break;
+
+ case TiledMapGroupLayerContent groupLayer:
+ ProcessLayers(contentItem, map, context, groupLayer.Layers);
+ break;
+ }
+ }
+ }
+
+ private static List<TiledMapTileContent> DecodeTileLayerData(string encodingType, TiledMapTileLayerContent tileLayer)
+ {
+ List<TiledMapTileContent> tiles;
+
+ switch (encodingType)
+ {
+ case "xml":
+ tiles = tileLayer.Data.Tiles;
+ break;
+ case "csv":
+ tiles = DecodeCommaSeperatedValuesData(tileLayer.Data);
+ break;
+ case "base64":
+ tiles = DecodeBase64Data(tileLayer.Data, tileLayer.Width, tileLayer.Height);
+ break;
+ default:
+ throw new NotSupportedException($"The tile layer encoding '{encodingType}' is not supported.");
+ }
+
+ return tiles;
+ }
+
+ private static TiledMapTile[] CreateTiles(TiledMapTileDrawOrderContent renderOrder, int mapWidth, int mapHeight, List<TiledMapTileContent> tileData)
+ {
+ TiledMapTile[] tiles;
+
+ switch (renderOrder)
+ {
+ case TiledMapTileDrawOrderContent.LeftDown:
+ tiles = CreateTilesInLeftDownOrder(tileData, mapWidth, mapHeight).ToArray();
+ break;
+ case TiledMapTileDrawOrderContent.LeftUp:
+ tiles = CreateTilesInLeftUpOrder(tileData, mapWidth, mapHeight).ToArray();
+ break;
+ case TiledMapTileDrawOrderContent.RightDown:
+ tiles = CreateTilesInRightDownOrder(tileData, mapWidth, mapHeight).ToArray();
+ break;
+ case TiledMapTileDrawOrderContent.RightUp:
+ tiles = CreateTilesInRightUpOrder(tileData, mapWidth, mapHeight).ToArray();
+ break;
+ default:
+ throw new NotSupportedException($"{renderOrder} is not supported.");
+ }
+
+ return tiles.ToArray();
+ }
+
+ private static IEnumerable<TiledMapTile> CreateTilesInLeftDownOrder(List<TiledMapTileContent> tileLayerData, int mapWidth, int mapHeight)
+ {
+ for (var y = 0; y < mapHeight; y++)
+ {
+ for (var x = mapWidth - 1; x >= 0; x--)
+ {
+ var dataIndex = x + y * mapWidth;
+ var globalIdentifier = tileLayerData[dataIndex].GlobalIdentifier;
+ if (globalIdentifier == 0)
+ continue;
+ var tile = new TiledMapTile(globalIdentifier, (ushort)x, (ushort)y);
+ yield return tile;
+ }
+ }
+ }
+
+ private static IEnumerable<TiledMapTile> CreateTilesInLeftUpOrder(List<TiledMapTileContent> tileLayerData, int mapWidth, int mapHeight)
+ {
+ for (var y = mapHeight - 1; y >= 0; y--)
+ {
+ for (var x = mapWidth - 1; x >= 0; x--)
+ {
+ var dataIndex = x + y * mapWidth;
+ var globalIdentifier = tileLayerData[dataIndex].GlobalIdentifier;
+ if (globalIdentifier == 0)
+ continue;
+ var tile = new TiledMapTile(globalIdentifier, (ushort)x, (ushort)y);
+ yield return tile;
+ }
+ }
+ }
+
+ private static IEnumerable<TiledMapTile> CreateTilesInRightDownOrder(List<TiledMapTileContent> tileLayerData, int mapWidth, int mapHeight)
+ {
+ for (var y = 0; y < mapHeight; y++)
+ {
+ for (var x = 0; x < mapWidth; x++)
+ {
+ var dataIndex = x + y * mapWidth;
+ var globalIdentifier = tileLayerData[dataIndex].GlobalIdentifier;
+ if (globalIdentifier == 0)
+ continue;
+ var tile = new TiledMapTile(globalIdentifier, (ushort)x, (ushort)y);
+ yield return tile;
+ }
+ }
+ }
+
+ private static IEnumerable<TiledMapTile> CreateTilesInRightUpOrder(List<TiledMapTileContent> tileLayerData, int mapWidth, int mapHeight)
+ {
+ for (var y = mapHeight - 1; y >= 0; y--)
+ {
+ for (var x = mapWidth - 1; x >= 0; x--)
+ {
+ var dataIndex = x + y * mapWidth;
+ var globalIdentifier = tileLayerData[dataIndex].GlobalIdentifier;
+ if (globalIdentifier == 0)
+ continue;
+ var tile = new TiledMapTile(globalIdentifier, (ushort)x, (ushort)y);
+ yield return tile;
+ }
+ }
+ }
+
+ private static List<TiledMapTileContent> DecodeBase64Data(TiledMapTileLayerDataContent data, int width, int height)
+ {
+ var tileList = new List<TiledMapTileContent>();
+ var encodedData = data.Value.Trim();
+ var decodedData = Convert.FromBase64String(encodedData);
+
+ using (var stream = OpenStream(decodedData, data.Compression))
+ {
+ using (var reader = new BinaryReader(stream))
+ {
+ data.Tiles = new List<TiledMapTileContent>();
+
+ for (var y = 0; y < width; y++)
+ {
+ for (var x = 0; x < height; x++)
+ {
+ var gid = reader.ReadUInt32();
+ tileList.Add(new TiledMapTileContent
+ {
+ GlobalIdentifier = gid
+ });
+ }
+ }
+ }
+ }
+
+ return tileList;
+ }
+
+ private static List<TiledMapTileContent> DecodeCommaSeperatedValuesData(TiledMapTileLayerDataContent data)
+ {
+ return data.Value
+ .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(uint.Parse)
+ .Select(x => new TiledMapTileContent { GlobalIdentifier = x })
+ .ToList();
+ }
+
+ private static Stream OpenStream(byte[] decodedData, string compressionMode)
+ {
+ var memoryStream = new MemoryStream(decodedData, false);
+
+ return compressionMode switch
+ {
+ "gzip" => new GZipStream(memoryStream, CompressionMode.Decompress),
+ "zlib" => new ZlibStream(memoryStream, Framework.Utilities.Deflate.CompressionMode.Decompress),
+ _ => memoryStream
+ };
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetContentItem.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetContentItem.cs
new file mode 100644
index 0000000..d4b2221
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetContentItem.cs
@@ -0,0 +1,14 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ public class TiledMapTilesetContentItem : TiledContentItem<TiledMapTilesetContent>
+ {
+ public TiledMapTilesetContentItem(TiledMapTilesetContent data)
+ : base(data)
+ {
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetImporter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetImporter.cs
new file mode 100644
index 0000000..c848bde
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetImporter.cs
@@ -0,0 +1,60 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using System;
+using System.IO;
+using System.Xml.Serialization;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentImporter(".tsx", DefaultProcessor = "TiledMapTilesetProcessor", DisplayName = "Tiled Map Tileset Importer - MonoGame.Extended")]
+ public class TiledMapTilesetImporter : ContentImporter<TiledMapTilesetContentItem>
+ {
+ public override TiledMapTilesetContentItem Import(string filePath, ContentImporterContext context)
+ {
+ try
+ {
+ if (filePath == null)
+ throw new ArgumentNullException(nameof(filePath));
+
+ ContentLogger.Logger = context.Logger;
+ ContentLogger.Log($"Importing '{filePath}'");
+
+ var tileset = DeserializeTiledMapTilesetContent(filePath, context);
+
+ ContentLogger.Log($"Imported '{filePath}'");
+
+ return new TiledMapTilesetContentItem(tileset);
+ }
+ catch (Exception e)
+ {
+ context.Logger.LogImportantMessage(e.StackTrace);
+ throw;
+ }
+ }
+
+ private TiledMapTilesetContent DeserializeTiledMapTilesetContent(string filePath, ContentImporterContext context)
+ {
+ using (var reader = new StreamReader(filePath))
+ {
+ var tilesetSerializer = new XmlSerializer(typeof(TiledMapTilesetContent));
+ var tileset = (TiledMapTilesetContent)tilesetSerializer.Deserialize(reader);
+
+ if (tileset.Image is not null)
+ tileset.Image.Source = context.AddDependencyWithLogging(filePath, tileset.Image.Source);
+
+ foreach (var tile in tileset.Tiles)
+ {
+ foreach (var obj in tile.Objects)
+ {
+ if (!string.IsNullOrWhiteSpace(obj.TemplateSource))
+ obj.TemplateSource = context.AddDependencyWithLogging(filePath, obj.TemplateSource);
+ }
+ if (tile.Image is not null)
+ tile.Image.Source = context.AddDependencyWithLogging(filePath, tile.Image.Source);
+ }
+
+ return tileset;
+ }
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetProcessor.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetProcessor.cs
new file mode 100644
index 0000000..5682602
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetProcessor.cs
@@ -0,0 +1,44 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using System;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentProcessor(DisplayName = "Tiled Map Tileset Processor - MonoGame.Extended")]
+ public class TiledMapTilesetProcessor : ContentProcessor<TiledMapTilesetContentItem, TiledMapTilesetContentItem>
+ {
+ public override TiledMapTilesetContentItem Process(TiledMapTilesetContentItem contentItem, ContentProcessorContext context)
+ {
+ try
+ {
+ var tileset = contentItem.Data;
+
+ ContentLogger.Logger = context.Logger;
+ ContentLogger.Log($"Processing tileset '{tileset.Name}'");
+
+ // Build the Texture2D asset and load it as it will be saved as part of this tileset file.
+ if (tileset.Image is not null)
+ contentItem.BuildExternalReference<Texture2DContent>(context, tileset.Image);
+
+ foreach (var tile in tileset.Tiles)
+ {
+ foreach (var obj in tile.Objects)
+ {
+ TiledMapContentHelper.Process(obj, context);
+ }
+ if (tile.Image is not null)
+ contentItem.BuildExternalReference<Texture2DContent>(context, tile.Image);
+ }
+
+ ContentLogger.Log($"Processed tileset '{tileset.Name}'");
+
+ return contentItem;
+ }
+ catch (Exception ex)
+ {
+ context.Logger.LogImportantMessage(ex.Message);
+ throw ex;
+ }
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetWriter.cs
new file mode 100644
index 0000000..48690ad
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapTilesetWriter.cs
@@ -0,0 +1,145 @@
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+using MonoGame.Extended.Tiled;
+using System;
+using System.Globalization;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentTypeWriter]
+ public class TiledMapTilesetWriter : ContentTypeWriter<TiledMapTilesetContentItem>
+ {
+ public override string GetRuntimeReader(TargetPlatform targetPlatform) => "MonoGame.Extended.Tiled.TiledMapTilesetReader, MonoGame.Extended.Tiled";
+
+ public override string GetRuntimeType(TargetPlatform targetPlatform) => "MonoGame.Extended.Tiled.TiledMapTileset, MonoGame.Extended.Tiled";
+
+ protected override void Write(ContentWriter writer, TiledMapTilesetContentItem contentItem)
+ {
+ try
+ {
+ WriteTileset(writer, contentItem.Data, contentItem);
+ }
+ catch (Exception ex)
+ {
+ ContentLogger.Logger.LogImportantMessage(ex.StackTrace);
+ throw;
+ }
+ }
+
+ public static void WriteTileset(ContentWriter writer, TiledMapTilesetContent tileset, IExternalReferenceRepository externalReferenceRepository)
+ {
+ var externalReference = externalReferenceRepository.GetExternalReference<Texture2DContent>(tileset.Image?.Source);
+ writer.WriteExternalReference(externalReference);
+ writer.Write(tileset.Class ?? tileset.Type ?? string.Empty);
+ writer.Write(tileset.TileWidth);
+ writer.Write(tileset.TileHeight);
+ writer.Write(tileset.TileCount);
+ writer.Write(tileset.Spacing);
+ writer.Write(tileset.Margin);
+ writer.Write(tileset.Columns);
+ writer.Write(tileset.Tiles.Count);
+
+ foreach (var tilesetTile in tileset.Tiles)
+ WriteTilesetTile(writer, tilesetTile, externalReferenceRepository);
+
+ writer.WriteTiledMapProperties(tileset.Properties);
+ }
+
+ private static void WriteTilesetTile(ContentWriter writer, TiledMapTilesetTileContent tilesetTile,
+ IExternalReferenceRepository externalReferenceRepository)
+ {
+ var externalReference = externalReferenceRepository.GetExternalReference<Texture2DContent>(tilesetTile.Image?.Source);
+ writer.WriteExternalReference(externalReference);
+
+ writer.Write(tilesetTile.LocalIdentifier);
+ writer.Write(tilesetTile.Type);
+ writer.Write(tilesetTile.Frames.Count);
+ writer.Write(tilesetTile.Objects.Count);
+
+ foreach (var @object in tilesetTile.Objects)
+ WriteObject(writer, @object);
+
+ foreach (var frame in tilesetTile.Frames)
+ {
+ writer.Write(frame.TileIdentifier);
+ writer.Write(frame.Duration);
+ }
+
+ writer.WriteTiledMapProperties(tilesetTile.Properties);
+ }
+
+ private static void WriteObject(ContentWriter writer, TiledMapObjectContent @object)
+ {
+ var type = GetObjectType(@object);
+
+ writer.Write((byte)type);
+
+ writer.Write(@object.Identifier);
+ writer.Write(@object.Name ?? string.Empty);
+ writer.Write(@object.Class ?? @object.Type ?? string.Empty);
+ writer.Write(@object.X);
+ writer.Write(@object.Y);
+ writer.Write(@object.Width);
+ writer.Write(@object.Height);
+ writer.Write(@object.Rotation);
+ writer.Write(@object.Visible);
+
+ writer.WriteTiledMapProperties(@object.Properties);
+
+ switch (type)
+ {
+ case TiledMapObjectType.Rectangle:
+ case TiledMapObjectType.Ellipse:
+ break;
+ case TiledMapObjectType.Tile:
+ writer.Write(@object.GlobalIdentifier);
+ break;
+ case TiledMapObjectType.Polygon:
+ WritePolyPoints(writer, @object.Polygon.Points);
+ break;
+ case TiledMapObjectType.Polyline:
+ WritePolyPoints(writer, @object.Polyline.Points);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ // ReSharper disable once SuggestBaseTypeForParameter
+ private static void WritePolyPoints(ContentWriter writer, string @string)
+ {
+ var stringPoints = @string.Split(' ');
+
+ writer.Write(stringPoints.Length);
+
+ foreach (var stringPoint in stringPoints)
+ {
+ var xy = stringPoint.Split(',');
+ var x = float.Parse(xy[0], CultureInfo.InvariantCulture.NumberFormat);
+ writer.Write(x);
+ var y = float.Parse(xy[1], CultureInfo.InvariantCulture.NumberFormat);
+ writer.Write(y);
+ }
+ }
+
+ public static TiledMapObjectType GetObjectType(TiledMapObjectContent content)
+ {
+ if (content.GlobalIdentifier > 0)
+ return TiledMapObjectType.Tile;
+
+ if (content.Ellipse != null)
+ return TiledMapObjectType.Ellipse;
+
+ if (content.Polygon != null)
+ return TiledMapObjectType.Polygon;
+
+ // ReSharper disable once ConvertIfStatementToReturnStatement
+ if (content.Polyline != null)
+ return TiledMapObjectType.Polyline;
+
+ return TiledMapObjectType.Rectangle;
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapWriter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapWriter.cs
new file mode 100644
index 0000000..126debb
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/Tiled/TiledMapWriter.cs
@@ -0,0 +1,227 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
+using MonoGame.Extended.Tiled;
+using MonoGame.Extended.Tiled.Serialization;
+
+namespace MonoGame.Extended.Content.Pipeline.Tiled
+{
+ [ContentTypeWriter]
+ public class TiledMapWriter : ContentTypeWriter<TiledMapContentItem>
+ {
+ private TiledMapContentItem _contentItem;
+
+ protected override void Write(ContentWriter writer, TiledMapContentItem contentItem)
+ {
+ _contentItem = contentItem;
+
+ var map = contentItem.Data;
+
+ try
+ {
+ WriteMetaData(writer, map);
+ WriteTilesets(writer, map.Tilesets);
+ WriteLayers(writer, map.Layers);
+ }
+ catch (Exception ex)
+ {
+ ContentLogger.Logger.LogImportantMessage(ex.StackTrace);
+ throw;
+ }
+ }
+
+ private static void WriteMetaData(ContentWriter writer, TiledMapContent map)
+ {
+ writer.Write(map.Class ?? map.Type ?? string.Empty);
+ writer.Write(map.Width);
+ writer.Write(map.Height);
+ writer.Write(map.TileWidth);
+ writer.Write(map.TileHeight);
+ writer.Write(ColorHelper.FromHex(map.BackgroundColor));
+ writer.Write((byte)map.RenderOrder);
+ writer.Write((byte)map.Orientation);
+ writer.WriteTiledMapProperties(map.Properties);
+ }
+
+ private void WriteTilesets(ContentWriter writer, IReadOnlyCollection<TiledMapTilesetContent> tilesets)
+ {
+ writer.Write(tilesets.Count);
+
+ foreach (var tileset in tilesets)
+ WriteTileset(writer, tileset);
+ }
+
+ private void WriteTileset(ContentWriter writer, TiledMapTilesetContent tileset)
+ {
+ writer.Write(tileset.FirstGlobalIdentifier);
+
+ if (!string.IsNullOrWhiteSpace(tileset.Source))
+ {
+ writer.Write(true);
+ writer.WriteExternalReference(_contentItem.GetExternalReference<TiledMapTilesetContent>(tileset.Source));
+ }
+ else
+ {
+ writer.Write(false);
+ TiledMapTilesetWriter.WriteTileset(writer, tileset, _contentItem);
+ }
+ }
+
+ private void WriteLayers(ContentWriter writer, IReadOnlyCollection<TiledMapLayerContent> layers)
+ {
+ writer.Write(layers.Count);
+
+ foreach (var layer in layers)
+ WriteLayer(writer, layer);
+ }
+
+ private void WriteLayer(ContentWriter writer, TiledMapLayerContent layer)
+ {
+ writer.Write((byte)layer.LayerType);
+
+ writer.Write(layer.Name ?? string.Empty);
+ writer.Write(layer.Class ?? layer.Type ?? string.Empty);
+ writer.Write(layer.Visible);
+ writer.Write(layer.Opacity);
+ writer.Write(layer.OffsetX);
+ writer.Write(layer.OffsetY);
+ writer.Write(layer.ParallaxX);
+ writer.Write(layer.ParallaxY);
+
+ writer.WriteTiledMapProperties(layer.Properties);
+
+ switch (layer.LayerType)
+ {
+ case TiledMapLayerType.ImageLayer:
+ WriteImageLayer(writer, (TiledMapImageLayerContent)layer);
+ break;
+ case TiledMapLayerType.TileLayer:
+ WriteTileLayer(writer, (TiledMapTileLayerContent)layer);
+ break;
+ case TiledMapLayerType.ObjectLayer:
+ WriteObjectLayer(writer, (TiledMapObjectLayerContent)layer);
+ break;
+ case TiledMapLayerType.GroupLayer:
+ WriteLayers(writer, ((TiledMapGroupLayerContent)layer).Layers);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(layer.LayerType));
+ }
+ }
+
+ private void WriteImageLayer(ContentWriter writer, TiledMapImageLayerContent imageLayer)
+ {
+ var externalReference = _contentItem.GetExternalReference<Texture2DContent>(imageLayer.Image.Source);
+ writer.WriteExternalReference(externalReference);
+ writer.Write(new Vector2(imageLayer.X, imageLayer.Y));
+ }
+
+ // ReSharper disable once SuggestBaseTypeForParameter
+ private static void WriteTileLayer(ContentWriter writer, TiledMapTileLayerContent tileLayer)
+ {
+ writer.Write(tileLayer.Width);
+ writer.Write(tileLayer.Height);
+
+ writer.Write(tileLayer.Tiles.Length);
+
+ foreach (var tile in tileLayer.Tiles)
+ {
+ writer.Write(tile.GlobalTileIdentifierWithFlags);
+ writer.Write(tile.X);
+ writer.Write(tile.Y);
+ }
+ }
+
+ private static void WriteObjectLayer(ContentWriter writer, TiledMapObjectLayerContent layer)
+ {
+ writer.Write(ColorHelper.FromHex(layer.Color));
+ writer.Write((byte)layer.DrawOrder);
+
+ writer.Write(layer.Objects.Count);
+
+ foreach (var @object in layer.Objects)
+ WriteObject(writer, @object);
+ }
+
+
+ private static void WriteObject(ContentWriter writer, TiledMapObjectContent @object)
+ {
+ var type = GetObjectType(@object);
+
+ writer.Write((byte)type);
+
+ writer.Write(@object.Identifier);
+ writer.Write(@object.Name ?? string.Empty);
+ writer.Write(@object.Class ?? @object.Type ?? string.Empty);
+ writer.Write(@object.X);
+ writer.Write(@object.Y);
+ writer.Write(@object.Width);
+ writer.Write(@object.Height);
+ writer.Write(@object.Rotation);
+ writer.Write(@object.Visible);
+
+ writer.WriteTiledMapProperties(@object.Properties);
+
+ switch (type)
+ {
+ case TiledMapObjectType.Rectangle:
+ case TiledMapObjectType.Ellipse:
+ break;
+ case TiledMapObjectType.Tile:
+ writer.Write(@object.GlobalIdentifier);
+ break;
+ case TiledMapObjectType.Polygon:
+ WritePolyPoints(writer, @object.Polygon.Points);
+ break;
+ case TiledMapObjectType.Polyline:
+ WritePolyPoints(writer, @object.Polyline.Points);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ // ReSharper disable once SuggestBaseTypeForParameter
+ private static void WritePolyPoints(ContentWriter writer, string @string)
+ {
+ var stringPoints = @string.Split(' ');
+
+ writer.Write(stringPoints.Length);
+
+ foreach (var stringPoint in stringPoints)
+ {
+ var xy = stringPoint.Split(',');
+ var x = float.Parse(xy[0], CultureInfo.InvariantCulture.NumberFormat);
+ writer.Write(x);
+ var y = float.Parse(xy[1], CultureInfo.InvariantCulture.NumberFormat);
+ writer.Write(y);
+ }
+ }
+
+ public static TiledMapObjectType GetObjectType(TiledMapObjectContent content)
+ {
+ if (content.GlobalIdentifier > 0)
+ return TiledMapObjectType.Tile;
+
+ if (content.Ellipse != null)
+ return TiledMapObjectType.Ellipse;
+
+ if (content.Polygon != null)
+ return TiledMapObjectType.Polygon;
+
+ // ReSharper disable once ConvertIfStatementToReturnStatement
+ if (content.Polyline != null)
+ return TiledMapObjectType.Polyline;
+
+ return TiledMapObjectType.Rectangle;
+ }
+
+ public override string GetRuntimeType(TargetPlatform targetPlatform) => "MonoGame.Extended.Tiled.TiledMap, MonoGame.Extended.Tiled";
+
+ public override string GetRuntimeReader(TargetPlatform targetPlatform) => "MonoGame.Extended.Tiled.TiledMapReader, MonoGame.Extended.Tiled";
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/readme.txt b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/readme.txt
new file mode 100644
index 0000000..54f1cda
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Content.Pipeline/readme.txt
@@ -0,0 +1,15 @@
+# MonoGame.Extended.Content.Pipeline
+
+This NuGet package is intended to be used with the MonoGame Content Pipeline tool. You'll need to
+make some changes to your Content Pipline file (usually Content.mgcb) for everything to work
+properly.
+
+Add a reference to the `MonoGame.Extended.Content.Pipeline.dll` now installed in your `packages` folder
+to the [MonoGame Content Pipeline tool](http://www.monogame.net/documentation/?page=Pipeline).
+
+You can do this either with the Reference Editor in the GUI or by manually adding a reference line to
+your `Content.mgcb` file using a text editor.
+
+**Remember**: the versions need to match exactly for everything to work.
+
+For more information, take a look at the [installation guide](http://craftworkgames.github.io/MonoGame.Extended/installation/).