Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[Unity Multiplayer] Subclass between MessageBase and specific messages

Discussion in 'Multiplayer' started by oneofmoo, Aug 30, 2016.

  1. oneofmoo

    oneofmoo

    Joined:
    Aug 18, 2016
    Posts:
    12
    Hello. I created a subclass of MessageBase called GameMessageBase that has a few fields that I want sent with every message.

    However, the automatically generated serialization doesn't serialize any of the fields in the base class and they are always a default value of 0.

    Code (csharp):
    1.  
    2. public class CharacterMoveMessage : GameMessageBase
    3. {
    4.  public Vector3 m_Position;
    5. }
    6.  
    7. public class GameMessageBase : MessageBase
    8. {
    9.  public int m_SourceConnectionId;
    10. }
    11.  
    Is there any way I can solve this without writing custom serialization code for every one of my message?
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    This doesn't directly address your question, but you may wish to note that you can already get the connection ID for an incoming message:
    Code (CSharp):
    1.         protected void OnClientJoined(NetworkMessage msg)
    2.         {
    3.             Debug.Log("Connection Id: " + msg.conn.connectionId);
    4.         }
    Ideally, you don't want to trust the client for information like that if you can help it.
     
  3. oneofmoo

    oneofmoo

    Joined:
    Aug 18, 2016
    Posts:
    12
    Thanks, Antistone.

    That'll save me sending those 4 bytes, but I was looking for a more general solution to the problem.

    I might end up just writing my own custom serialization for each message and some helper functions to do that, but was hoping to avoid it from a development speed perspective.
     
  4. Driiades

    Driiades

    Joined:
    Oct 27, 2015
    Posts:
    151
    It's like creating a command function/RpcClient with a generic serializable parameter : you can't pass an inherited class.

    And you can't because Unet create serialisation before the compiler (it's in the preprocessing).

    Unet doesn't understand (for the moment ?) inheritance.
     
  5. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    A thought: rather than using inheritance, have you considered putting your common parameters into a struct and then including a field of that struct's type in each message type?
    Code (CSharp):
    1. public struct CommonMessageProperties
    2. {
    3.     public int myInt;
    4.     public string myString;
    5. }
    6.  
    7. public class CharacterMoveMessage : MessageBase
    8. {
    9.     public CommonMessageProperties common;
    10.     public Vector3 m_Position;
    11. }
    12.  
    13. public class LevelUpMessage : MessageBase
    14. {
    15.     public CommonMessageProperties common;
    16.     public int newLevel;
    17. }
    (The Unity manual suggests on this page that you can't use custom classes as a member in a message class, but that you CAN use structs. I have not personally tried either one.)
     
  6. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
  7. oneofmoo

    oneofmoo

    Joined:
    Aug 18, 2016
    Posts:
    12
    Thanks, @Zuller. Good to know. :)

    @Antistone, I tried structs in a different situation and it didn't seem to work so I'm not optimistic about that as a solution.
     
  8. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    You could create a custom message OnSerialize/Deserialize. That may work, but I haven't tried it.
     
  9. oneofmoo

    oneofmoo

    Joined:
    Aug 18, 2016
    Posts:
    12
    Thanks, @Zuller, but that was what I was hoping to avoid. Just a bunch of boilerplate code where small bugs could easily creep in.
     
  10. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    If you do custom messages with complex serialization (where the data isn't fixed size) I'd recommend sending byte[] byteArray as the payload with packedUint32 size header. This costs a little overhead (1 byte typically) but prevents the NetworkReader from being de-synced if you mess anything up. Otherwise if there's an error it will cascade randomly into other messages and break everything and it's hard to know where the error started!