How to Serialize HTuple in C#? - c#

Define the class:
[Serializable]
public class HalconConfig
{
public HTuple mNumber;
public HObject mImage;
public HalconConfig()
{
mNumber = 6;
HalconFunction.BitmapToHObject(Resources.TestImage, out mImage);
}
}
And I want to save the HalconConfig object to a local file that can be read later
HalconConfig _config1 = new HalconConfig();
string _path = "./test.bin";
BinaryFormatter _formatter = new BinaryFormatter();
using (FileStream s = File.Create(_path))
{
_formatter.Serialize(s, _config1);
}
using (FileStream s = File.OpenRead(_path))
{
HalconConfig _config2 = (HalconConfig)_formatter.Deserialize(s);
BaseFunction.SendLog($"{_config2.mNumber}", LogLevel.Debug);
}
But I failed。HTuple cannot be used after deserialization。
enter image description here
I tried binary serialization and Json serialization,but both failed。

This problem has been solved. Essentially the reason was because I was using Halcon 18.11 and the provided dll was buggy and could not be serialized. I replaced it with Halcon 21.05 and the serialization function was implemented.

Please check halcon documentation
https://www.mvtec.com/doc/halcon/13/en/serialize_tuple.html
you can serialize any tuple: HoperatorSet.serialize_tuple
and write the tuple to a file:
HoperatorSet.write_tuple

Related

Issues with Save/Load System in a Text Based Adventure game made with ScriptableObjects in Unity

I am almost done with my Text Based Adventure Game and am trying to setup a Save/Load system that works. I can't seem to accomplish this.
I have viewed multiple tutorials and I feel that Json may be what I need. Unfortunately I can't seem to get Json code correct for the 'Load' part. I am also concerned that the amount of data I am trying to save is too much for a simple Serialization process OR I am over-complicating this and there is a simpler solution.
This is the data I am tryin to Save/Load. As you can see I have Dictionaries and Lists, as well as a 'Room' ScriptableObject that I am trying to save, namely, the currentRoom the Player is in when the game is saved. The currentRoom is tracked in the GameController.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class SaveData
{
public Room saveRoomNavigation;
public List<string> saveNounsInInventory = new List<string>();
public List<InteractableObject> saveUseableItemList = new
List<InteractableObject>();
public Dictionary<string, string> saveExamineDictionary = new
Dictionary<string, string>();
public Dictionary<string, string> saveTakeDictionary = new
Dictionary<string, string>();
public List<string> saveNounsInRoom = new List<string>();
public Dictionary<string, ActionResponse> saveUseDictionary = new
Dictionary<string, ActionResponse>();
public SaveData (GameController controller, InteractableItems
interactableItems)
{
saveRoomNavigation = controller.roomNavigation.currentRoom;
saveNounsInInventory = interactableItems.nounsInInventory;
saveUseableItemList = interactableItems.useableItemList;
saveExamineDictionary = interactableItems.examineDictionary;
saveTakeDictionary = interactableItems.takeDictionary;
saveNounsInRoom = interactableItems.nounsInRoom;
saveUseDictionary = interactableItems.useDictionary;
}
}
Then this is my Save System code where I am trying to implement the Serialization with Json and binary.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
public static class SaveSystem
{
public static void SaveGame (GameController controller,
InteractableItems interactableItems)
{
BinaryFormatter formatter = new BinaryFormatter();
string path = Application.persistentDataPath + "/savegame.rta";
FileStream stream = new FileStream(path, FileMode.Create);
SaveData data = new SaveData(controller, interactableItems);
var json = JsonUtility.ToJson(data);
formatter.Serialize(stream, json);
stream.Close();
}
public static SaveData LoadGame()
{
string path = Application.persistentDataPath + "/savegame.rta";
if (File.Exists(path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(path, FileMode.Open);
SaveData data =
JsonUtility.FromJsonOverwrite((string)formatter.Deserialize(stream,
????));
//SaveData data = formatter.Deserialize(stream) as
SaveData;
stream.Close();
return data;
}
else
{
Debug.LogError("Save file not found in " + path);
return null;
}
}
}
Where I put the '????' above is where I can't seem to get it to accept the Object I am trying to overwrite, which I thought was 'SaveData' since that is where I pull the information to put into the game when the Player clicks the 'Load' button. It tell me "'SaveData' is a type, which is not valid in the given context"
Here is the code I call when the 'Save' and 'Load' buttons are used, it is within my GameController Class where most everything is tracked during Game Play.
public void SaveGame()
{
SaveSystem.SaveGame(this, interactableItems);
}
public void LoadGame()
{
SaveData data = SaveSystem.LoadGame();
roomNavigation.currentRoom = data.saveRoomNavigation;
interactableItems.nounsInInventory = data.saveNounsInInventory;
interactableItems.useDictionary = data.saveUseDictionary;
interactableItems.takeDictionary = data.saveTakeDictionary;
interactableItems.examineDictionary =
data.saveExamineDictionary;
interactableItems.useableItemList = data.saveUseableItemList;
interactableItems.nounsInRoom = data.saveNounsInRoom;
DisplayRoomText();
DisplayLoggedText();
}
When used in game, I get "SerializationException" errors, so that is when I attempted to try Json. I read where it can serialize a lot more than the basic Unity Serializer. The errors went away and it seems to save OK with Json, but now I am unable to get the Load syntax correct.
I am a novice so maybe I am making this harder then it has to be... I also looked into Userprefs, but I don't think I can convert the Scriptable Object, Room, into a type String.
Thanks in advance!
[UPDATE] Here is what I am able to have it save in .txt format. This proves that it is saving, just not sure "instanceIDs" will give me the Load that I need.
ˇˇˇˇö{"saveRoomNavigation":
{"instanceID":11496},"saveNounsInInventory": ["sword"],"saveUseableItemList":[{"instanceID":11212}, {"instanceID":11588},{"instanceID":10710},{"instanceID":11578}, {"instanceID":10718},{"instanceID":11388}, {"instanceID":11276}],"saveNounsInRoom":["rocks","hole"]}
Take a look at the documentation for Unity's built-in JsonUtility:
https://docs.unity3d.com/Manual/JSONSerialization.html
It says types such as "Dictionaries" are not supported. Seeing as though you have several Dictionaries in your SaveData example, might I suggest using a more robust JSON library such as JSON.NET, which is free on the asset store:
https://assetstore.unity.com/packages/tools/input-management/json-net-for-unity-11347

Serializing a custom class to a file

I'm writing a save method for my Player class, I can serialize most fields using a binary writer however my custom class fields are not able to be serialized (i have a Race field for custom races)
Since I am going to have a lot of different custom classes - like Race - I really need a good reliable way of saving this information.
So, am I using the wrong kind of formatter? And if so, what is the one I should be using?
Alternatively, how do I write the method to serialize it? I have used the [Serializable()] attribute and implemented ISerializable interface where needed already.
Here is the code:
public void Save()
{
Stream stream = File.Open(SaveSlot, FileMode.Create);
BinaryWriter writer = new BinaryWriter(stream);
PlayerData saveData = new PlayerData();
writer.Write(saveData.Name = PlayerData.player.Name);
writer.Write(saveData.Race = PlayerData.player.Race);
writer.Write(saveData.PlayClass = PlayerData.player.PlayClass);
writer.Write(saveData.Level = PlayerData.player.Level);
writer.Write(saveData.Experience = PlayerData.player.Experience);
writer.Write(saveData.Strength = PlayerData.player.Strength);
writer.Write(saveData.Dexterity = PlayerData.player.Dexterity);
writer.Write(saveData.Constitution = PlayerData.player.Constitution);
writer.Write(saveData.Intelligence = PlayerData.player.Intelligence);
writer.Write(saveData.Wisdom = PlayerData.player.Wisdom);
writer.Write(saveData.Charisma = PlayerData.player.Charisma);
writer.Write(saveData.Wounds = PlayerData.player.Wounds);
writer.Write(saveData.MaxWounds = PlayerData.player.MaxWounds);
writer.Write(saveData.Attackbonus = PlayerData.player.Attackbonus);
writer.Write(saveData.Defensebonus = PlayerData.player.Defensebonus);
writer.Close();
Console.WriteLine("Data Saved Successfully");
}
Like I said in my comment you can use the json format for this.
Sample class
public class MyObject
{
public string MyProperty { get; set; }
}
Sample data
List<MyObject> objects = new List<MyObject>
{
new MyObject{MyProperty = "test 1"},
new MyObject{MyProperty = "test 2"},
new MyObject{MyProperty = "test 3"}
};
Sample code
Then you can use this code for serialize your data (using Newtonsoft).
string json = JsonConvert.SerializeObject(objects);
The content of json will be
[{"MyProperty":"test 1"},{"MyProperty":"test 2"},{"MyProperty":"test
3"}]
If you want to deserialize the string use this.
List<MyObject> deserialzed = JsonConvert.DeserializeObject<List<MyObject>>(json);
More info
You can save the json string to a file and load and deserialize it when you need it. This works with every type of a property including list and custom objects.
Have a read at the JSON format for more information.

C# XmlSerializer bug when serializing root tag

I'm currently serializing HighScoreData from a C# application to an XML file using the XmlSerializer namespace. This is producing an inconsistent result regarding the outputted XML file.
The object I'm serializing is the following struct:
namespace GameProjectTomNijs.GameComponents
{
[Serializable]
public struct HighScoreData
{
public string[] PlayerName;
public int[] Score;
public int Count;
public readonly string HighScoresFilename;
public HighScoreData(int count)
{
PlayerName = new string[count];
Score = new int[count];
Count = count;
HighScoresFilename = "highscores.lst";
}
}
}
Questionable variable accessibility levels aside, it contains an array of string, an array of integers and an integer containing the total objects. This is the data that is being serialized. The output of this usually is :
<?xml version="1.0"?>
<HighScoreData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PlayerName>
<string />
<string>MISTERT</string>
<string>TESTER</string>
<string>PAULA</string>
<string>JENS</string>
</PlayerName>
<Score>
<int>554</int>
<int>362</int>
<int>332</int>
<int>324</int>
<int>218</int>
</Score>
<Count>5</Count>
</HighScoreData>
However, about 20-30% of the time it is writing to the XML file in a peculiar manner, the ending root tag would look as follows: </HighScoreData>oreData>
It seems the method writing to the XML file is appending the values rather than overwriting I guess?
The following code is the method actually writing to the XML file:
public static void SaveHighScores(HighScoreData data, string fullpath)
{
// Open the file, creating it if necessary
FileStream stream = File.Open(fullpath, FileMode.OpenOrCreate);
try
{
// Convert the object to XML data and put it in the stream
XmlSerializer serializer = new XmlSerializer(typeof(HighScoreData));
serializer.Serialize(stream, data);
}
finally
{
// Close the file
stream.Close();
}
}`
Is there anything I'm currently overlooking? I've used this method in a large number of projects to great success.
Any help would be greatly appreciated !
This is the problem:
FileStream stream = File.Open(fullpath, FileMode.OpenOrCreate);
That doesn't truncate the file if it already exists - it just overwrites the data that it writes, but if the original file is longer than the data written by the serializer, the "old" data is left at the end.
Just use
using (var stream = File.Create(fullPath))
{
...
}
(Then you don't need try/finally either - always use a using statement for resources...)

c# Export Object Into New A Type Of Files

i will explain by an example, a PSD file is a file where photoshop save a project, a DOC file is a file where Office Save a Document...
I am making an application where i work with object and i want to export my object into a new type of files (for exemple TQA : Test Question Answer), and i want my application to be the only program that can open that file.
static class TestQuestionAnswer
{
public string Question;
public string Answer;
//...initiating of the Question and Answer
//...Exporting the object to a TQA file..??
}
any ideas ?
You can use a Binary Formatter
using System;
using System.IO;
using System.Collections;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
public class App
{
[STAThread]
static void Main()
{
Serialize();
Deserialize();
}
static void Serialize()
{
// Create a hashtable of values that will eventually be serialized.
Hashtable addresses = new Hashtable();
addresses.Add("Jeff", "123 Main Street, Redmond, WA 98052");
addresses.Add("Fred", "987 Pine Road, Phila., PA 19116");
addresses.Add("Mary", "PO Box 112233, Palo Alto, CA 94301");
// To serialize the hashtable and its key/value pairs,
// you must first open a stream for writing.
// In this case, use a file stream.
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
// Construct a BinaryFormatter and use it to serialize the data to the stream.
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(fs, addresses);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
static void Deserialize()
{
// Declare the hashtable reference.
Hashtable addresses = null;
// Open the file containing the data that you want to deserialize.
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
try
{
BinaryFormatter formatter = new BinaryFormatter();
// Deserialize the hashtable from the file and
// assign the reference to the local variable.
addresses = (Hashtable) formatter.Deserialize(fs);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
// To prove that the table deserialized correctly,
// display the key/value pairs.
foreach (DictionaryEntry de in addresses)
{
Console.WriteLine("{0} lives at {1}.", de.Key, de.Value);
}
}
}
Example taken from
http://msdn.microsoft.com/en-us/library/c5sbs8z9.aspx
Refer thru below codeproject article.
http://www.codeproject.com/Articles/17468/BizDraw-framework-for-NET
You might get the better reference for your application from the above link.
Hope it'll help you out.

Why is XmlSerializer's Deserialize() spitting out a child object which is a XmlNode[]?

I'm using XmlSerializer to serialize and then deserialize a simple object. When I deserialize the object to my surprise I find a child object was not properly deserialized but instead turned into XmlNode[].
Here is very nearly the structure I've got:
// This line I put in here as a way of sneaking into the XML the
// root node's C# namespace, since it's not the same as the
// deserializing code and the deserializing code seemed unable to
// deserialize properly without knowing the Type (see my code below).
// So I basically just use this fake construct to get the namespace
// and make a Type of it to feed the XmlSerializer() instantiation.
[XmlRoot(Namespace = "http://foo.com/CSharpNamespace/Foo.Bar")]
// This is because QueuedFile can be given to the Argument array.
[XmlInclude(typeof(QueuedFile))]
// This class is Foo.Bar.CommandAndArguments
public class CommandAndArguments {
public String Command;
public object[] Arguments;
}
// I don't think this matters to XmlSerialize, but just in case...
[Serializable()]
// I added this line just thinking maybe it would help, but it doesn't
// do anything. I tried it without the XmlType first, and that
// didn't work.
[XmlType("Foo.Baz.Bat.QueuedFile")]
// This class is Foo.Baz.Bat.QueuedFile (in a different c#
// namespace than CommandAndArguments and the deserializing code)
public QueuedFile {
public String FileName;
public String DirectoryName;
}
And the code which deserializes it looks like:
public static object DeserializeXml(String objectToDeserialize)
{
String rootNodeName = "";
String rootNodeNamespace = "";
using (XmlReader xmlReader = XmlReader.Create(new StringReader(objectToDeserialize)))
{
if (xmlReader.MoveToContent() == XmlNodeType.Element)
{
rootNodeName = xmlReader.Name;
rootNodeNamespace = xmlReader.NamespaceURI;
if (rootNodeNamespace.StartsWith("http://foo.com/CSharpNamespace/"))
{
rootNodeName = rootNodeNamespace.Substring("http://foo.com/CSharpNamespace/".Length) + "." +
rootNodeName;
}
}
}
//MessageBox.Show(rootNodeName);
try
{
Type t = DetermineTypeFromName(rootNodeName);
if (t == null)
{
throw new Exception("Could not determine type of serialized string. Type listed as: "+rootNodeName);
}
var s = new XmlSerializer(t);
return s.Deserialize(new StringReader(objectToDeserialize));
// object o = new object();
// MethodInfo castMethod = o.GetType().GetMethod("Cast").MakeGenericMethod(t);
// return castMethod.Invoke(null, new object[] { s.Deserialize(new StringReader(objectToDeserialize)) });
}
catch (InvalidOperationException)
{
return null;
}
}
And here is the XML when the CommandAndArguments is serialized:
<?xml version="1.0" encoding="utf-16"?>
<CommandAndArguments xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://foo.com/CSharpNamespace/Foo.Bar">
<Command>I am a command</Command>
<Arguments>
<anyType xsi:type="Foo.Baz.Bat.QueuedFile">
<FileName xmlns="">HelloWorld.txt</FileName>
<DirectoryName xmlns="">C:\foo\bar</DirectoryName>
</anyType>
</Arguments>
</CommandAndArguments>
But when I deserialize I am given a CommandAndArguments object where Arguments is XmlNode[] with the first item being the attribute giving the QueuedFile as the type and the other indices being elements of the properties. But why wasn't the QueuedFile object recreated?
I suspect this might somehow have do with C# namespaces and the engine doing the deserializing not being able to find or work with QueuedFile... But I don't see why since when I forgot the XmlInclude() it made sure to tell me it didn't expect QueuedFile and now that I've added the XmlInclude() I get no error, just an incomplete deserialization.
Help? I've read everything I can find to read and Googled everything I know to Google and am stuck. I certainly have a lot to learn about XML serialization but I'm not sure how I'm failing at something which should be pretty simple (I actually did something almost exactly like this before without any problem, the only difference then was that everything was in the same C# namespace).
Are you able to change the XML format or is it fixed? I don't know what the problem you are having is, but I use the DataContractSerializer classes extensively with no problems.
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx
public static void WriteObject(string fileName)
{
Console.WriteLine(
"Creating a Person object and serializing it.");
Person p1 = new Person("Zighetti", "Barbara", 101);
FileStream writer = new FileStream(fileName, FileMode.Create);
DataContractSerializer ser =
new DataContractSerializer(typeof(Person));
ser.WriteObject(writer, p1);
writer.Close();
}
public static void ReadObject(string fileName)
{
Console.WriteLine("Deserializing an instance of the object.");
FileStream fs = new FileStream(fileName,
FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
DataContractSerializer ser = new DataContractSerializer(typeof(Person));
// Deserialize the data and read it from the instance.
Person deserializedPerson =
(Person)ser.ReadObject(reader, true);
reader.Close();
fs.Close();
Console.WriteLine(String.Format("{0} {1}, ID: {2}",
deserializedPerson.FirstName, deserializedPerson.LastName,
deserializedPerson.ID));
}
To anyone coming along with a similar problem, depending on your situation you're probably better off with NetDataContractSerializer. It is an alternative to DataContractSerializer which records the .Net types in the XML making deserialization a breeze, since it knows exactly what types are involved and thus you do not need to tell it what type the root object is with the deserialize command. And it can produce output in XML or binary form (I prefer XML for easier debugging).
Here is some sample code for easily serializing and deserializing an object to and from a string:
private static object Deserialize(string xml)
{
object toReturn = null;
using (Stream stream = new MemoryStream())
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
stream.Write(data, 0, data.Length);
stream.Position = 0;
var netDataContractSerializer = new NetDataContractSerializer();
toReturn = netDataContractSerializer.Deserialize(stream);
}
return toReturn;
}
private static string Serialize(object obj)
{
using (var memoryStream = new MemoryStream())
using (var reader = new StreamReader(memoryStream))
{
var netDataContractSerializer = new NetDataContractSerializer();
netDataContractSerializer.Serialize(memoryStream, obj);
memoryStream.Position = 0;
return reader.ReadToEnd();
}
}
Easy as pie!

Categories

Resources