Author Topic: DataNode serialization limitations  (Read 6130 times)

Bradamante3D

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 79
    • View Profile
DataNode serialization limitations
« on: April 26, 2016, 05:58:18 PM »
Sometimes here on the forum I read that TNet can serialize everything, but it seems I have run into a few limitations. I did only use text-mode though. Am I doing something wrong or is that TNet? Pseudo-code follows ...

(1)

When you add a child a la

  1. dn.AddChild ( "MyString", string.Empty )

the file creation on the server silently fails. Do

  1. dn.AddChild ( "MyString", "" )

and it works. Interestingly the log claims that the file was created, but it's just not there. I am not 100% sure of this though. Have to do more tests.

(2)

Dictionaries. This

  1. using System.Collections.Generic;
  2.  
  3. public static struct MySaveStruct () {
  4.  
  5. Dictionary<int,string> myCargo = new Dictionary<int,string>() {
  6. "Food" = 10 };

ends up as:

  1. Cargo = System.Collections.Generic.Dictionary`2[System.String,System.Int32]

Same thing for a Dictionary<int,int> which becomes

  1. Standings = System.Collections.Generic.Dictionary`2[System.Int32,System.Int32]

My guess is that you are not supposed to use Dicts? Instead add a lot of child nodes? Like, AddChild ( "Food", 10) ), AddChild ( "Industrial", 20 )? And then iterate through

  1. dn.GetChild<DataNode>("Cargo").children

right?

(3)

TNet has problems with namespaces? The MySaveStructs works if the props are just ints and strings etc. But

  1. namespace MyNameSpace {
  2.  
  3. public static struct MySaveStruct () {
  4.  
  5. List<WeapStruct> weapons = new List<WeapStruct>();
  6. }
  7.  
  8. public static struct WeapStruct () {
  9.  
  10. string name = "MyWeapon";
  11. }
  12. }
|

will result in a hard failure and an entry in Debug/TNetErrors.txt:

  1. [2016/04/27 00:04:05] ERROR: Unable to resolve type 'MyNameSpace.WeapSave'
  2. (... Error Stack ...)

Again, same resolution as above?

Or just throw my complex struct of structs into the BinaryFormatter and send that to the server?

( bonus round )

System.Collections.Generic.List vs TNet.List caught be off guard. And you can't do

  1. BetterList.AddRange ( anotherList );

and

  1. BetterList<string> myBetterList = new BetterList<string> { "First", "Second" };

and the error talks about IEnumerator?
Is there something I am not seeing here? Design decision you regret now?
« Last Edit: April 26, 2016, 06:03:41 PM by Bradamante3D »
#301224014, #301432336, #302399130

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: DataNode serialization limitations
« Reply #1 on: April 27, 2016, 12:13:33 AM »
Custom structs and classes need to be marked as [Serializable] for them to be exportable -- same as normal serialization.

Dictionaries are not serializable. If you want to serialize them, run through them using foreach and add elements one at a time, or add the list of keys and values separately.

To serialize structs properly you should also make this change: line 1034 of DataNode.cs reads:
  1.                                 else if (type.IsClass)
  2.                                 {
  3.                                         for (int i = 0; i < children.size; ++i)
  4.                                         {
  5.                                                 DataNode child = children[i];
  6.                                                 mValue.SetFieldOrPropertyValue(child.name, child.value);
  7.                                         }
  8.                                         return false;
  9.                                 }
  10. #if UNITY_EDITOR
  11.                                 else Debug.LogError("Unhandled type: " + type);
  12. #else
  13.                                 else Tools.LogError("Unhandled type: " + type);
  14. #endif
Needs to be:
  1.                                 else
  2.                                 {
  3.                                         for (int i = 0; i < children.size; ++i)
  4.                                         {
  5.                                                 DataNode child = children[i];
  6.                                                 mValue.SetFieldOrPropertyValue(child.name, child.value);
  7.                                         }
  8.                                         return false;
  9.                                 }
BetterList is NGUI, TNet.List is TNet. Similar, but TNet's list has more features. Don't use BetterList, use TNet.List or System's List.

harko12

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 8
    • View Profile
Re: DataNode serialization limitations
« Reply #2 on: September 30, 2016, 03:57:02 PM »
I have marked my class as System.Serializable, but I'm still getting the Unable to resolve type error.  Does the standalone server need to have a reference to my client classes?  I wouldn't have thought so since it would all be seriialzed by the time the server gets it.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: DataNode serialization limitations
« Reply #3 on: September 30, 2016, 07:35:34 PM »
If you're putting them into a DataNode, then yes -- the server will need to have your client side classes to serialize them.

If you're just passing them as RFC parameters, then you don't need anything. The server will just forward them on as raw data.

phoenix

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 3
  • Posts: 49
    • View Profile
Re: DataNode serialization limitations
« Reply #4 on: September 30, 2016, 11:50:21 PM »
Vexe writes some amazing code
Here is his serializable-dictionary

https://forum.unity3d.com/threads/finally-a-serializable-dictionary-for-unity-extracted-from-system-collections-generic.335797/

And in his github project vfw he has a more robust framework for all kinds of serialization

https://github.com/vexe/VFW

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: DataNode serialization limitations
« Reply #5 on: October 01, 2016, 02:12:56 AM »
That's pretty cool. I did a similar system here, but for runtime. I simply add properties, fields and functions, mark them with certain attributes and when in-game I click on an object it collects all game options on the object and displays them via a UI window. Bool shows up as toggle, functions as buttons, enums as drop-downs, etc. Any field that doesn't have a logical element shows up as an input field that uses TNet's serialization to convert string to type and back. Works well.

I was debating adding it to TNet, but left it out as it's more game-centric than anything, and to display the options I use NGUI.

harko12

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 8
    • View Profile
Re: DataNode serialization limitations
« Reply #6 on: October 01, 2016, 08:21:22 AM »
If you're putting them into a DataNode, then yes -- the server will need to have your client side classes to serialize them.

If you're just passing them as RFC parameters, then you don't need anything. The server will just forward them on as raw data.
Any suggestions on the best way to get the server to know about my classes?  I tried running a server from inside my game with TNServerInstance.Start() thinking that would have access to the classes since it was in the same game.  But no, same problem.  Do I need to do the classes as a separate project, and then make sure the dll is in the same dir as my executable?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: DataNode serialization limitations
« Reply #7 on: October 01, 2016, 08:23:37 AM »
TNServerInstance.Start() will have access to your game classes as you're running it from within your game.

For stand-alone executable you would need to include the class files in the stand-alone server project that comes with TNet, then recompile the server's executable.

harko12

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 8
    • View Profile
Re: DataNode serialization limitations
« Reply #8 on: October 05, 2016, 10:28:42 AM »
Quote
TNServerInstance.Start() will have access to your game classes as you're running it from within your game.

I hadn't been able to get it to work within my game, I could only get it to work by putting the class file in the server.exe solution and rebuilding like you suggested.  Today I dug into why, and it turns out it wasn't that the class wasn't available, that was just the message sent back, the real problem came from UnityTools.GetTypeEx(string).  On line 294 it's doing an Application.IsPlaying check, and that is throwing an exception:
  1. get_isPlaying can only be called from the main thread.
  2. Constructors and field initializers will be executed from the loading thread when loading a scene.
  3. Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
  4. UnityEngine.Application:get_isPlaying()

By commenting out that if, I was able to get it to work.  Maybe that check shouldn't be there?
« Last Edit: October 05, 2016, 11:35:18 AM by harko12 »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: DataNode serialization limitations
« Reply #9 on: October 06, 2016, 06:12:26 AM »
Oh, good catch, thanks. It should be replaced with this:
  1. #if UNITY_EDITOR
  2.                 if (Application.isPlaying) mTypeCache[name] = t;
  3. #else
  4.                 mTypeCache[name] = t;
  5. #endif

sunriser

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 17
    • View Profile
Re: DataNode serialization limitations
« Reply #10 on: December 08, 2016, 05:13:40 PM »
I had the very same problem described here with a custom serialized object on the server instance start. As suggested, I commented out this line:

  1. #if UNITY_EDITOR
  2.                 //if (Application.isPlaying) mTypeCache[name] = t;
  3. #else
  4.                 mTypeCache[name] = t;
  5. #endif
  6.                 return t;
  7.         }

Does this still need work or should this be working without having to comment that line?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: DataNode serialization limitations
« Reply #11 on: December 08, 2016, 07:08:59 PM »
You can just keep only the "mTypeCache[name] = t;" part. Adding [System.NonSerialized] in front of the dictionary removes the need for an isPlaying check.