Monogame XML serialization with Content pipeline - c#

I've been trying to implement an XML system for items in my game.. but I just cant get it to work.
I am using Monogame and the content pipeline that comes with it.
I've made an Inventory Class and an Item Class.
Here are the snippets from the Inventory Class (which would have the serialization):
public class Inventory
{
[XmlElement("Item")]
public static List<Item> itemList;
public Inventory (Vector2 _position)
{
itemList = new List<Item>();
}
public void LoadContent()
{
XmlSerializer deserializer = new XmlSerializer(typeof(Item));
TextReader reader = new StreamReader("Content/Items/itemEntities.xml");
object obj = deserializer.Deserialize(reader);
Inventory XmlData = (Inventory)obj;
reader.Close();
}
}
And then I creaded an XML file:
<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:ns="Microsoft.Xna.Framework">
<Asset Type="Game.Item[]">
<Item>
<itemType>Weapon</itemType>
<itemRarity>Rare</itemRarity>
<itemID>0001</itemID>
<positionID>
<X>1</X>
<Y>1</Y>
</positionID>
<name>The sword</name>
<description>Description</description>
</Item>
<Item>
<itemType>Equipment</itemType>
<itemRarity>Uncommon</itemRarity>
<itemID>0002</itemID>
<positionID>
<X>1</X>
<Y>1</Y>
</positionID>
<name>The Item</name>
<description>Description</description>
</Item>
<Item>
<itemType>Drone</itemType>
<itemRarity>Common</itemRarity>
<itemID>0003</itemID>
<positionID>
<X>1</X>
<Y>1</Y>
</positionID>
<name>The Drone</name>
<description>Description</description>
</Item>
</Asset>
</XnaContent>
The problem now is that I get the following error:
error: Importer 'XmlImporter' had unexpected failure!
Microsoft.Xna.Framework.Content.Pipeline.InvalidContentException: Could not resolve type 'Game.Item[]'.
I have read on some other questions here that I would have to make a reference, but I just can't find a way to make that. In the solution explorer I can see references, but when I click add, I dont see anything in Projects, only standard stuff like Frameworks etc. are there.
Oh and I have a constuctor with no arguments in Item class, so that should be fine.
One more thing. I have tried to write the list of items into an XML file and it worked perfectly..
Thanks in advance!

You need to add a reference to a compiled dll lib, which means, your types need to be defined in an external project.
Create another project that compiles into dll, define all your structs and classes there (at least those that need serialization), and add reference to the dll from the content manager by doing the following:
open content pipeline manager.
select root node ("Content").
On the properties tab click on "References".
Click on 'Add' and select the path to the dll file you generated from the other project.
I recently asked a similar question on the monogame community and currently its impossible to serialize types from your own project into / from xml without using another project that builds into a dll.

Related

Issue with xml to object c# using Xml.Serialization

I have an old xml response and I cannot map it to an object as I normally do.
Using paste special> xml
:When I deserialize it, it's throwing "The specified type was not recognized: name='Array'"
Using class from https://xmltocsharp.azurewebsites.net/
:I can map to object but there is nothing in return property
<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://uat.api.sample.uk">
<SOAP-ENV:Body>
<ns1:directReportResponse xmlns:ns1="urn:Direct">
<return xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="tns:DirectResult[1]">
<item xsi:type="tns:DirectResult">
<TMSReference xsi:type="xsd:string">sampleTMS</TMSReference>
<Postcode xsi:type="xsd:string">samplePostcode</Postcode>
<ExpectedDelivery xsi:type="xsd:string">2020-08-25</ExpectedDelivery>
</item>
</return>
</ns1:directReportResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
After follow andyrut, I can map it to custom type but still no value in an item obj
The generated class does not know that a "return" tag is an array of "item" elements. You simply need to make the following modifications to your C# class:
Delete the class definition for Return.
Mark the Return data member as a list/array of Item's. Change the Return data member in the DirectReportResponse to a list and decorate it like so:
[XmlArray(ElementName="return", Namespace="")]
[XmlArrayItem(ElementName="item", Namespace="")]
public List<Item> Return { get; set; }
There's a Type specified in the Item XML, so decorate your Item class by adding the following line above it:
[XmlType(Namespace="http://uat.api.sample.uk", TypeName="DirectResult")]
You may need to tweak your C# class for the other specified types in the XML file.

C# XML documentation '<include>' tag not appearing in intellisense?

I developing a C# class library in Visual Studio, and I have been making use of XML Documentation Comments primarily for their integration with Intellisense. However, the bulk of comments has become quite cluttered, so now I am endeavoring to use the <include> tag, and an external XML document to reduce the clutter.
My issue is that when using the <include> tag Intellisense seems to not update with the information, not show any of the <summary> and <param> tags that I've assigned to some of my classes and methods.
For Example I could have a class 'Test' documented as shown:
/// <include file="docs.xml" path='extradoc/class[#name="Test"]/*' />
class Test { string foo = "bar"; }
And have docs.xml:
<?xml version="1.0" encoding="utf-8" ?>
<extradoc>
<class name="Test">
<summary>
Contains some Foo.
</summary>
</class>
</extradoc>
And upon build the output XML populates correctly:
<?xml version="1.0"?>
<doc>
<assembly>
<name>Example Program</name>
</assembly>
<members>
<member name="T:Example_Program.Program.Test">
<summary>
Contains some Foo.
</summary>
</member>
</members>
</doc>
The only issue is that, try as I might, this documentation will not appear in the intellisense boxes while appending my code. Is there some Visual Studio configuration setting I'm missing? I've scoured the msn documentation to no avail.
My issue is that when using the tag Intellisense seems to
not update with the information, not show any of the and
tags that I've assigned to some of my classes and methods.
1.Avoid that your issue is being not able to see summary in Intellisense in current project A.
You can get help from this document, this technology is used to provide better reading experience. So assuming you have the Test class in current priject A, when you see the content in VS code editor, you'll see something like:
It's expected behavior that you won't see that rich comments in project A any more cause they have been moved to docs.xml.
2.If you mean when you create a new Project B(or share the assembly to other developers), the Intellisense can't recognize your Test class.
Two possible causes:
1.The output xx.dll and xx.xml from project A are not in the same folder, so when you reference that xx.dll in your new project, Intellisense won't display the documentation comments.
2.I guess there's something wrong with your docs.xml file. (I can't find any official document which indicates this technology supports user-defined nodes like extradoc and class in docs.xml, I used these two nodes and the Intellisense did not work, after changing them to normal docs and members, it works now)
Try using docs.xml and include in this way:
<?xml version="1.0" encoding="utf-8" ?>
<docs>
<members name="MyTests">
<Test>
<summary>
This class is public, but do nothing
</summary>
<remarks>
Just write something here to indicate this is remarks.
</remarks>
</Test>
</members>
</docs>
and
/// <include file="docs.xml" path='docs/members[#name="MyTests"]/Test/*' />
public class Test { }
I suggest you use a public class to test... After that create a new project and reference that xx.dll, when calling Test class you can see the summary:
And if we F12 we can see detailed comments:
Hope it helps :)

How do I get multiple namespaces in XML C#?

Following is the XML format:
<?xml version="1.0" encoding="UTF-8"?>
<package version="2.0" unique-identifier="isbn0000000000000" xmlns="http://www.idpf.org/2007/opf">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:title>Eltern Family</dc:title>
<dc:creator></dc:creator>
<dc:publisher></dc:publisher>
<dc:rights></dc:rights>
<dc:identifier id="isbn0000000000000">0000000000000</dc:identifier>
<dc:language>de</dc:language>
<dc:date opf:event="publication">2019-02-11</dc:date>
</metadata>
</package>
Here I got the default Namespace by XDocument.Root.GetDefaultNamespace();. But as you can see, there are multiple namespaces in the <metadata> XML node. The problem is that, they are variable i.e., each XML may have different values, so I cannot declare a variable with one fixed value.
How do I get the namespaces, so that I can add values to the descendant elements?
Please help.
Regards
Aman
If, as you say, you want to set the content of dc:rights, then you need to get hold of that element.
You can do this by name - the 'qualified name' is made of of the namespace and a local name. The namespace prefix dc is not actually important in and of itself, it's just used as a shorthand to refer to the namespace within the document.
Assuming you have parsed this XML to an XDocument called doc:
XNamespace dc = "http://purl.org/dc/elements/1.1/"
var rights = doc.Descendants(dc + "rights").Single();
rights.Value = "text";

Loading an XML file via the Monogame content pipeline?

I am currently trying to port a game I am working on from XNA to Monogame, but I am having some trouble getting the content pipeline to cooperate. My game uses a number of XML files as XNB assets to represent objects in the game, which I created following the instructions here. However, trying to move this across word-for-word into Monogame produces the following error:
An unhandled exception of type 'Microsoft.Xna.Framework.Content.ContentLoadException' occurred in MonoGame.Framework.dll
Additional information: Could not load Parts\Window.xnb asset as a non-content file!
Here is the class I have been using to define the content of the XML files:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace FileTypes
{
public class PartFile
{
public struct State
{
public Rectangle[] frames;
public int[] collision;
}
public Vector2 size;
public string image;
public string defaultState = "default";
public bool fillBG;
public int ticksPerFrame;
public Dictionary<string, State> states;
public string[] modules;
}
}
Here is one of the XML files in the project:
<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
<Asset Type="FileTypes.PartFile">
<size>2 3</size>
<image>Computer</image>
<defaultState>default</defaultState>
<fillBG>false</fillBG>
<ticksPerFrame>7</ticksPerFrame>
<states>
<Item>
<Key>default</Key>
<Value>
<frames>
0 0 40 60
40 0 40 60
</frames>
<collision>
0 0
0 0
0 0
</collision>
</Value>
</Item>
<Item>
<Key>active</Key>
<Value>
<frames>
80 0 40 60
120 0 40 60
</frames>
<collision>
0 0
0 0
0 0
</collision>
</Value>
</Item>
</states>
<modules>
<Item>testModule</Item>
</modules>
</Asset>
</XnaContent>
And finally here is a sample of the code I use to load the file:
FileTypes.PartFile srcPart = content.Load<FileTypes.PartFile>("Parts\\" + name);
Does anybody know what I need to do in order to get my code working in Monogame? I've been looking around the internet for a fair while, but so far I've yet to find a solution to my issue. Alternatively, if I've been going about the entire system wrong all this time and there's a far easier way to handle what I want to do, I'd love to hear it.
Thanks in advance!
I wrote a rather long tutorial about loading custom content with the MonoGame Pipeline. Here's the summary
Create a new project to hold your content importer, processor and writer
Create the content importer
Create the content processor
Create the content type writer
Create the content type reader
Reference the DLL from the Pipeline tool
Read the content into your game
Creating the importer, processor, reader and writer is the same as XNA. You can refer to the MSDN documentation for that.
The tricky part is getting your DLL to work with the Pipeline tool. To add it as a reference look for the the References property of the root tree node.
Unless I'm mistaken, you need to set the build action of the file to "Content" and the copy to output directory to "copy if newer" in the properties tab for the file
Content.Load<T> uses Microsoft.Xna.Framework.Content.Pipeline.IntermediateSerializer for an xml. Monogame doesn't support Microsoft.Xna.Framework.Content.Pipeline. It means you cannot deserialize an intermediate xml.
Monogame comes with content processors for XML. Open up the content pipeline app and add an XML file; you will see it has the importer XmlImporter and processor PassThroughProcessor.
Take a look at #craftworkgames excellent tutorials for how to extend the behaviour.

Set interface to public by default in C#

Is there any way for Visual Studio to create my interface 'public'? For example, right click on folder -> create new item -> code -> interface.
Whenever the file is created there are no access modifiers.
interface IMyInterface
{
}
Is there any way to default it to make it public?
public interface IMyInterface
{
}
I'm always forgetting to manually change them to public (when they need to be).
Open your project with the public IMyInterface interface shown above.
Go to File > Export Template.
Follow the steps (make sure you choose item template rather than Project template) and save it under a name of your choice.
When you restart visual studio and have a project open it will be available from the add item dialog. You will be able to set the name of the interface from the dialog just like you can with the other items.
Note that this does not overwrite the default interface template installed with Visual Studio so you can still just as easily make a private interface when required.
You can also create a code snippet for public interfaces like this :
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets
xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>public interface</Title>
</Header>
<Snippet>
<Code Language="csharp">
<![CDATA[
public interface IMyInterface
{
}
]]>
</Code>
</Snippet>
</CodeSnippet>
and save it as publicinterfacecsharp.snippet.
Then go to Tools -> Code Snippets Manager...
Select language as C# and My Code Snippets folder, then click Import.. and point to location where you saved the snippet. Now in any new project, you can right click in the editor window and select Insert Code Snippet -> My Code Snippets -> publicinterfacecsharp.

Categories

Resources