Author Topic: Virtual Server Error  (Read 1335 times)

devomage

  • Sr. Member
  • ****
  • Thank You
  • -Given: 7
  • -Receive: 67
  • Posts: 250
    • View Profile
Virtual Server Error
« on: April 23, 2017, 05:51:20 PM »
I have the this code attached to a button click and it spits out the following error...

Any idea what could be causing it?  This does not happen with the same code in a fresh scene/script.  Deleting the server.dat file does nothing.




  1. TNServerInstance.Start("server.dat");
  2. TNManager.Connect();
  3.  


Failed to read past end of stream. at position 75
UnityEngine.Debug:LogError(Object)
TNet.Tools:LogError(String, String, Boolean) (at Assets/TNet/Common/TNTools.cs:1068)
TNet.Serialization:ReadObject(BinaryReader, Object, Int32, Type, Boolean) (at Assets/TNet/Common/TNSerializer.cs:2880)
TNet.Serialization:ReadObject(BinaryReader) (at Assets/TNet/Common/TNSerializer.cs:2500)
TNet.Serialization:ReadDataNode(BinaryReader) (at Assets/TNet/Common/TNSerializer.cs:2381)
TNet.TcpProtocol:VerifyRequestID(BinaryReader, Buffer, Boolean) (at Assets/TNet/Common/TNTcpProtocol.cs:947)
TNet.GameServer:ProcessPlayerPacket(Buffer, TcpPlayer, Boolean) (at Assets/TNet/Server/TNGameServer.cs:1254)
TNet.GameServer:ThreadFunction() (at Assets/TNet/Server/TNGameServer.cs:531)

devomage

  • Sr. Member
  • ****
  • Thank You
  • -Given: 7
  • -Receive: 67
  • Posts: 250
    • View Profile
Re: Virtual Server Error
« Reply #1 on: April 23, 2017, 07:37:46 PM »
In the same project/scene/script:  Starting a LAN server and then Connect - does not give the error.

  1. private void StartLANServer()
  2. {
  3.         int udpPort = UnityEngine.Random.Range(10000, 40000);
  4.  
  5.         TNLobbyClient lobby = GetComponent<TNLobbyClient>();
  6.  
  7.         if (lobby == null)
  8.         {
  9.                 TNServerInstance.Start(serverTcpPort, udpPort, "server.dat");
  10.         }
  11.         else
  12.         {
  13.                 TNServerInstance.Type type = (lobby is TNUdpLobbyClient) ? TNServerInstance.Type.Udp : TNServerInstance.Type.Tcp;
  14.  
  15.                 TNServerInstance.Start(serverTcpPort, udpPort, lobby.remotePort, "server.dat", type);
  16.         }
  17.  
  18. }
  19.  

  1. TNManager.Connect(selectedExternal, selectedInternal);
  2.  

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,154
  • Toronto, Canada
    • View Profile
Re: Virtual Server Error
« Reply #2 on: April 26, 2017, 07:11:39 AM »
Just delete the server.dat file and try again. It's trying to read your previously serialized data, and finding something it doesn't recognize. Usually happens when you change a class/struct after it has already been serialized into the save file. It will try to load it using the new version, and its size will be different.

mythikos

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 2
  • Posts: 18
    • View Profile
Re: Virtual Server Error
« Reply #3 on: April 26, 2017, 12:09:08 PM »
I don't know if this is the most elegant (or even correct) way, but it worked for me. Seeing I am in active development, where stuff can be changing constantly, I ended up making a static helper method in my network manager that deletes the file when the host closes the server. I wrote up a quick example below (sorry if it isn't 100% accurate, writing from what I remember of it, don't have access to my source at the moment):

  1. // Static method located somewhere
  2. public static CloseServer()
  3.     if (TNManager.isHosting)
  4.     {
  5.          // Stop the server.
  6.          TNServerInstance.Stop();
  7.  
  8.         // Remove the server data file as the server has been closed.
  9.         TNManager.DeleteFile(serverDataFileName);
  10.     }
  11.     else
  12.     {
  13.         // We arent the host, disconnect from the server
  14.         TNManager.Disconnect();
  15.     }
  16. }

devomage

  • Sr. Member
  • ****
  • Thank You
  • -Given: 7
  • -Receive: 67
  • Posts: 250
    • View Profile
Re: Virtual Server Error
« Reply #4 on: April 27, 2017, 06:36:49 PM »
Just delete the server.dat file and try again.

Of course I tried this several times and mentioned it in the original post.  I'll revisit this soon.  Appreciate the reply.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,154
  • Toronto, Canada
    • View Profile
Re: Virtual Server Error
« Reply #5 on: April 28, 2017, 10:36:17 AM »
My current project (Sightseer) is in a constant development, but the game server is active for weeks/months at a time. I make use of TNet's serialization with DataNodes for most data, and it doesn't break when elements are added/removed.

devomage

  • Sr. Member
  • ****
  • Thank You
  • -Given: 7
  • -Receive: 67
  • Posts: 250
    • View Profile
Re: Virtual Server Error
« Reply #6 on: April 28, 2017, 06:39:48 PM »
It error's out using a virtual server and NOT A LAN SERVER.  Odd, yes?  I have not modified *any* TNET files and am running the latest version.

I'll dig deeper into the server.dat angle when I have time - I was wanting any additional insight based from my two original posts.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Virtual Server Error
« Reply #7 on: April 29, 2017, 04:38:23 AM »
Shouldn't have anything to do with server.dat. I'm guessing ArenMook skimmed or misread your first post. From your stack trace it seems the issue originates from the TNManager.Connect() call (this then sends the RequestID packet in the socket OnConnect handler). The server receives the RequestID packet and attempts to read the supplied DataNode. At this point the DataNode provided by the client should be null unless you populate it somewhere else before your connect call? Since it's null it shouldn't even get to the try/catch block.

I can't help much further than that though as it seems our source code doesn't match up. Line 2381 in my TNSerializer.cs is empty space. Definitely seems to be an issue with the serialization, though. Particularly when the client sends its RequestID packet in TNTcpProtocol.cs::OnConnectResult(...) [~line 314 writes the dataNode].

Also, if your goal is a virtual server used for a strictly singleplayer game, I think there is a different way of doing it? The ExampleMenu class does it your way, but I don't think that's right. There's an overload for GameClient.Connect that accepts a GameServer. This isn't exposed to TNManager, though, so I dunno. There's also the localClient property on the GameServer, but I can't make sense of what purpose it serves. Maybe it's explained in the docs?


Just did a quick double-check before posting and I think I figured it out. Calling TNManager.Connect with no parameters while the TNServerInstance is active results in a different call chain. The GameClient.Connect overload that accepts the GameServer is the one that ends up getting called, and it sends the RequestID packet a bit differently than the usual way. Instead of writer.Write(dataNode) it uses writer.WriteObject(dataNode). Don't know why this messes up the serialization, but try changing it to use writer.Write instead.

File TNGameClient.cs, function public void Connect (GameServer server) [@ line ~544]:
  1. public void Connect (GameServer server)
  2. {
  3.         Disconnect();
  4.  
  5.         if (server != null)
  6.         {
  7.                 mLocalServer = server;
  8.                 server.localClient = this;
  9.  
  10.                 mTcp.stage = TcpProtocol.Stage.Verifying;
  11.                 BinaryWriter writer = BeginSend(Packet.RequestID);
  12.                 writer.Write(TcpProtocol.version);
  13. #if UNITY_EDITOR
  14.                 writer.Write(string.IsNullOrEmpty(mTcp.name) ? "Editor" : mTcp.name);
  15. #else
  16.                 writer.Write(string.IsNullOrEmpty(mTcp.name) ? "Guest" : mTcp.name);
  17. #endif
  18.                 writer.WriteObject(mTcp.dataNode);
  19.                 EndSend();
  20.         }
  21. }
  22.  

Change to:
  1. public void Connect (GameServer server)
  2. {
  3.         Disconnect();
  4.  
  5.         if (server != null)
  6.         {
  7.                 mLocalServer = server;
  8.                 server.localClient = this;
  9.  
  10.                 mTcp.stage = TcpProtocol.Stage.Verifying;
  11.                 BinaryWriter writer = BeginSend(Packet.RequestID);
  12.                 writer.Write(TcpProtocol.version);
  13. #if UNITY_EDITOR
  14.                 writer.Write(string.IsNullOrEmpty(mTcp.name) ? "Editor" : mTcp.name);
  15. #else
  16.                 writer.Write(string.IsNullOrEmpty(mTcp.name) ? "Guest" : mTcp.name);
  17. #endif
  18.                 writer.Write(mTcp.dataNode);
  19.                 EndSend();
  20.         }
  21. }
  22.  

devomage

  • Sr. Member
  • ****
  • Thank You
  • -Given: 7
  • -Receive: 67
  • Posts: 250
    • View Profile
Re: Virtual Server Error
« Reply #8 on: May 01, 2017, 05:40:05 PM »
Maybe it's explained in the docs?

I'll check the docs~  Appreciate your time spent on this cmifwdll.  Definitely helped out with an odd error.  I'm in the process of re-writing my login scripts and will post again if the problem doesnt clear up.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Virtual Server Error
« Reply #9 on: May 01, 2017, 09:39:41 PM »
Yeah, I think your way is the proper way of starting up a virtual server. When a local server instance is active then all that other stuff I mentioned is automatically set up and used. It's pretty interesting how well it works. From what I can see, nothing really major was re-written to support virtual servers: just a couple Queue<Buffer>'s. Incredible design skill.

To clarify the serialization bug:
When starting up a LAN server (using sockets), the OnConnect socket callback sends the TNet RequestID packet. In this function the client's DataNode is serialized using the serializer's Write(this BinaryWriter bw, DataNode node) function.
When starting a virtual server (no sockets used), the TNet RequestID packet is sent from a different function. In this function the client's DataNode is serialized using the serializer's WriteObject(object obj) function. The difference is that WriteObject writes the type info before calling bw.Write(node). In DataNode's case this is a single byte (type prefix of 14)

In either case, when the server processes the RequestID packet it attempts to deserialize the DataNode using the serializer's ReadDataNode(DataNode node) function. When using Write(...) this works as intended, but when using WriteObject(...) the unexpected type info causes the exception.

Always fun when a single byte causes a critical error :P

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,154
  • Toronto, Canada
    • View Profile
Re: Virtual Server Error
« Reply #10 on: May 04, 2017, 05:24:34 PM »
Ah.. interesting. Thanks, the WriteObject was from TNet 2 days I'm guessing. Just leftover code. I'll change it to Write(), and thanks for getting to the bottom of it!