1

I am currently writing an object oriented game with a multiplayer. Player inherits from entity and when I send my current players properties via

NetOutgoingMessage outmsg = Server.CreateMessage(); [...] outmsg.WriteAllProperties(p);

where p is my player object, my clients only receive properties which are declared in my players class and not from the entity class. Therefore my clients can't update the player positions etc.

Any advice?

edit:

It recognizes the inherited objects, but it doesn't send them properly. I think I might need to use some Bindingflags as there is an option to it and it should be possible to send objects which are allocated to a player too. I am using a Vector2 class to specify the position and velocity of my player, but my client either can't receive a Vector2 class or the server can't send it. If I use integers, strings, booleans or anything it works, but not with custom classes.

besplash
  • 346
  • 1
  • 5
  • 17
  • Lidgren is still a pretty low-level networking library. It's not something you just plug into your game and it makes your game multiplayer (unlike, say, Unity 3D's networking). Define your own messages. Be as specific as possible, never send something you don't need to send. Networking is very hard, and while Lidgren saves you from a lot of those issues, it doesn't help you all that much with making a multiplayer game. Realtime games in particular are very tricky to do right, especially if they're twitch based. Do work with primitives - send those vectors as two `float`s etc. – Luaan May 06 '15 at 12:56
  • Right before I saw your comment, I thought exactly the same. I will write my own writer now, thanks for the reply. – besplash May 06 '15 at 13:00
  • It really boils down to performance, mostly. Game messages usually aren't self descriptive (unlike, say, WCF SOAP messages), because that's wasting space and latency. If you want something to help you with building the message protocols, `protobuf` is pretty useful - it allows you to use "higher level" constructs like lists, optional parameters, strings etc. It does have some overhead (naturally), but isn't too hard to use. You can serialize the protobuf struct to a byte array, and send that directly using Lidgren. But you'd still send messages like "update position of player 1 to (1, 1)". – Luaan May 06 '15 at 13:05
  • @Luaan Currently I cast an enum in front of my data to "flag" it. I don't see the performance issue in converting my values to byte and send them with the flag. Do you mean, that I can send whole lists like my playerslist efficiently with protobuf? And protobuf was that library where you had to put [Serialize stuff] above all classes etc, right? – besplash May 06 '15 at 13:20
  • Yeah, that's the very basic stuff. But you also have to have enough information to reconstruct the full type you're sending (primitives are a lot easier). Inheritance makes this even harder. And protobuf is a bit more complicated - you define the structures in separate files and then generate the (de)serialization code for C#. But you'll still need to manually build those structures from your game state before you send them. – Luaan May 06 '15 at 14:24

2 Answers2

2

This should (have not tried this myself) be possible since you can serialize anything into bytes but not straight out the box. There are 3 primary conditions:

  • objects that need to be sent should be exactly the same on client and server.
  • You need to send the type of data along with the data at a expected position.
  • And most probably need to sent the amount of bytes send since NetIncomingMessage does not have read till end.

One way to send data type info is to send a enum as the first byte

enum PacketTypes
{
    LOGIN,
    MOVEMENT,
    SHOOTING,
}

out.Write((byte)PacketTypes.Login);

NetOutgoingMessage.Write can take a bytes or byte array. So you can use any method to serialize your object to bytes. Before you write it as a out message first determine the amount of bytes and write that after the packet info. Then write the data.

On the receiving end you need to determine what kind of data you received and handle that properly. if (inc.ReadByte() == (byte)PacketTypes.Login), now we know how to handle this custom package. Now read out the integer that specifies how much bytes the data is, read out that amount and deserialize it.

There are plenty of sources that explain serializing and deserialzing data so I won't go into depth here. And since you can send and receive bytes with Lidgren this really should just work. However, you should always send as little data as possible and in practice a couple of primitives are often enough. For example, the name of the player does not need to be send each time you want a position. The abilities of that player are probably even less interesting. You need to break it down in pieces, if a player moves send 2 floats. If a player gets hit send a int. For a ability being used you often only need an integer as ID.

Madmenyo
  • 8,389
  • 7
  • 52
  • 99
  • 1
    Nowadays I'm also very sure, that your approach works and if I had to send a whole object that could be the best solution to it. However I don't think, that sending a whole object in that case is optimal. I will accept this as the most helpful solution anyway as it should solve my mentioned problem. Hopefully that helps someone out there! – besplash Oct 07 '16 at 09:07
0

I just (finally) read, that Lidgren is not able to send or read custom objects.

https://groups.google.com/forum/#!topic/lidgren-network-gen3/sdj6LFMdKAY

besplash
  • 346
  • 1
  • 5
  • 17