Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by stulleman · Mar 03, 2016 at 03:15 PM · networkingmultiplayertransport

Sending structs over network (NetworkTransport API)

Hello,

I am developing a multiplayer game on top of the Low Level API (NetworkTransport API). I'm at the point where I want to send different information, structured in different structs. (e.g. SpawnInformation, PositionUpdate and so on)

So my idea is to convert the struct to a byte array, send the array and convert it back. But here is the problem. How does the receiver know what type of struct that is? One thing I noticed is that if I add a type byte at the start i can use this to cast it to different objects.

But I am interested in your ideas, since this is probably a pretty common task for network developing.

Thanks!

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by Bunny83 · Mar 03, 2016 at 07:08 PM

Of course you need to serialize the type of the struct in some way. Generally structs are a bad choice when the data should be serialized / deserialized because of their valuetype nature.

Also you usually don't want to just send the plain information but usually "messages". Well, that's what the HighLevelAPI actually does for you.

So if you want to roll your own, you have to define your own message format. A message usually contains a message type and often a variable amount of payload data. There are examples in the docs. Keep in mind that a packet is limited to the configured "MaxPacketSize". So larger data streams need to be split into several packets.

When dealing with binary streaming data the best solution is to use a BinaryReader with a MemoryStream. That way you can simply read your message component by component. I haven't use Unity's NetworkReader yet, but even they claim it's part of the high level API, it looks like it's just a standalone stream helper just like the BinaryReader but has support for most Unity types.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image stulleman · Mar 03, 2016 at 07:52 PM 1
Share

Why are structs a bad choice? Could you elaborate this a bit please?

Right now I'm converting my struct to bytes like this:

    public static byte[] GetBytes( object myStruct ) {
 
             int size = $$anonymous$$arshal.SizeOf(myStruct);
             byte[] buffer = new byte[size];
 
             IntPtr ptr = $$anonymous$$arshal.AllocHGlobal(size);
             $$anonymous$$arshal.StructureToPtr(myStruct, ptr, true);
             $$anonymous$$arshal.Copy(ptr, buffer, 0, size);
             $$anonymous$$arshal.FreeHGlobal(ptr);
             return buffer;
 
         }

Now when I try to get my struct back I do this:

   public static object FromBytes( byte[] buffer ) {
 
             object myStruct;
 
             switch(buffer[0]) {
 
                 case (int)PAC$$anonymous$$ET_TYP$$anonymous$$SPAWN_OBJECT:
 
                     myStruct = new SpawnObject();
                     break;
 
                 default:
 
                     myStruct = null;
                     break;
             }
 
             int size = $$anonymous$$arshal.SizeOf(myStruct);
             IntPtr ptr = $$anonymous$$arshal.AllocHGlobal(size);
 
             $$anonymous$$arshal.Copy(buffer, 0, ptr, size);
 
             myStruct = (object) $$anonymous$$arshal.PtrToStructure(ptr, myStruct.GetType());
             $$anonymous$$arshal.FreeHGlobal(ptr);
 
             return myStruct;
 
         }

This seems to be pretty ugly. One of my other concerns is the speed. What would you do?

avatar image Bunny83 stulleman · Mar 04, 2016 at 12:55 AM 1
Share

Because value types are difficult to handle when you pass them between methods. What you've done here is also extremely dangerous as you use pointers here. Also you treat your struct as "object". So you always box the struct on the heap and on every access you need to unbox it. That's why a class would be better. $$anonymous$$arshalling a struct into a byte array is an "evil hack" and might fail depending on the machines architecture and memory alignment. You would need at least a StructLayoutAttribute on it.

It's usually better to either use a BinaryFormatter and simply serialize a pure data class, or serialize the needed things manually using the above mentioned BinaryReader / Writer or NetworkReader / Writer.

How you prepare your data for network transfer won't be your bottleneck. That will be 10x or 100x faster than the actual transfer.

I'll add a small example to my answer.

avatar image stulleman Bunny83 · Mar 04, 2016 at 02:06 PM 0
Share

First of all thanks for your help.

What I have now is this:

 public static byte[] SerializeClass( object obj ) {
 
             $$anonymous$$emoryStream stream = new $$anonymous$$emoryStream();
             BinaryFormatter bf = new BinaryFormatter();
 
             bf.Serialize(stream, obj);
 
             return stream.GetBuffer();
 
         }
 
         public static object DeserializeClass( byte[] buffer ) {
 
             $$anonymous$$emoryStream stream = new $$anonymous$$emoryStream(buffer);
             BinaryFormatter bf = new BinaryFormatter();
 
             return bf.Deserialize(stream);
 
         }

Is this what you had in $$anonymous$$d? If yes, I still have the problem how to know what kind of data arrived at the receiver. I could add a byte identifying the packet. Or is there a better way?

EDIT:

Okay I just noticed I can check of what type my message is like this:

 SpawnInformation so = new SpawnInformation(10, 10, 1);
         byte[] buffer = SNProtocol.SerializeClass(so);
 
         object obj = SNProtocol.DeserializeClass(buffer);
 
         if(obj is SpawnInformation) {
             Debug.Log((SpawnInformation) obj);
         }
 
         PositionUpdate pu = new PositionUpdate(20, 20, "abcdefg");
         buffer = SNProtocol.SerializeClass(pu);
 
         obj = SNProtocol.DeserializeClass(buffer);
 
         if(obj is PositionUpdate) {
             Debug.Log((PositionUpdate) obj);
         }

I checked the size of the buffer, it is in both cases 256. Is this acceptable for just a position update?

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

70 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Unity networking tutorial? 6 Answers

What properties from a HLAPI connection can be used to create a LLAPI connection? 0 Answers

Networking Camera not attaching to instantiated object 2 Answers

Animation over network using rpcs 0 Answers

Frames Per Second Cost from Multiplayer? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges