Forum C# Is PlayerIO contain analog for BinaryFormatter

Is PlayerIO contain analog for BinaryFormatter

Postby fair_wind_ » December 27th, 2017, 10:51 am

Hello! I have a problem with converting the list of keypair values to a byte array, but when I try to use BinaryFormatter class I got an error
has variable of the non-allowed type: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter

Is PlayerIO have an analog for this class or I should convert to any other type?
fair_wind_
 
Posts: 6
Joined: November 14th, 2017, 7:33 am

Re: Is PlayerIO contain analog for BinaryFormatter

Postby Henrik » January 1st, 2018, 8:41 pm

For what purpose do you want to serialize a dictionary? BigDB or Multiplayer Messages?
Henrik
.IO
 
Posts: 1880
Joined: January 4th, 2010, 1:53 pm

Re: Is PlayerIO contain analog for BinaryFormatter

Postby pasEnixan » March 26th, 2019, 12:57 pm

Henrik wrote:For what purpose do you want to serialize a dictionary? BigDB or Multiplayer Messages?

Multiplayer Messages for example.
In my case i am serialize object to byte[] on client side and trying deserialize it to a same object on server.
What is the best practic for send message data as serialize object?
Thanks.
pasEnixan
 
Posts: 1
Joined: March 26th, 2019, 10:21 am

Re: Is PlayerIO contain analog for BinaryFormatter

Postby jasonredhawk » March 22nd, 2020, 4:15 pm

I'm also looking to deserialize an object on the server. Did you ever get BinaryFormatter working server-side?

Here's my issue:

Basically I'm saving GIS map data into small chunks (into a DatabaseObject), specifically 2D array (128x128 size) of objects. Each object consists of 3 properties, elevation, fuelCode and vegetationCode, basically 3 integers (I use short instead of int to save space).

Anyway, this 2D array of objects is serialized client-side and saved to the PlayerIO Database. The game I'm building then loads the map data server-side to handle some calculations before broadcasting to all players.

My issue is after the server loads my BigDB Database object with my serialized GIS map data, I cannot deserialize that data. It would appear that BinaryFormatter is getting blocked by Playerio on the server.

My question is, how can I deserialize my DatabaseObject property server-side?
jasonredhawk
Paid Member
 
Posts: 25
Joined: April 4th, 2013, 9:15 pm

Re: Is PlayerIO contain analog for BinaryFormatter

Postby Henrik » March 23rd, 2020, 11:38 pm

How do you serialize it client-side?

If you just store the data straight into a BigDB object, PlayerIO takes care of all the serialization for you, and we generally do a better job than BinaryFormatter, but it all depends on the underlying data.

If your absolutely want to serialize it yourself, and since your data structure is so simple, you can always write your own serializer, and then base128-encode the resulting byte-array into a BigDB String?
Henrik
.IO
 
Posts: 1880
Joined: January 4th, 2010, 1:53 pm

Re: Is PlayerIO contain analog for BinaryFormatter

Postby jasonredhawk » March 24th, 2020, 2:16 pm

At first, I successfully saved my map data as multiple objects of 2D arrays. It looked like this in BigDB.
Code: Select all
{
  mapName: "MapName",
  size: 128,
  elevation: [
    0:[
      0: 407,
      1: 548,
      2: etc etc
    ]
    1:[
      0: 407,
      1: 548,
      2: etc etc
    ]
    2:[
      0: 407,
      1: 548,
      2: etc etc
    ]
  ],
  fuelCode: [
    0:[
      0: 99,
      1: 98,
      2: etc etc
    ]
    1:[
      0: 99,
      1: 98,
      2: etc etc
    ]
    2:[
      0: 99,
      1: 98,
      2: etc etc
    ]
  ], 
}


Though this works fine, it's costing me a lot in Web Traffic to retrieve that data from BigDB. Saving it in this way causes a single map to be between 5 to 8MB in size (that's just for the smaller maps). Each player downloads the map data once to their device and is then saved locally. One small map is 512x512 array is too big to save into one 500kb DatabaseObject, so I broke the map down into 16 smaller 128x128 data chunks that are saved to BigDB.

So far so good but my game is a multiplayer wildland firefighting game and there are fire spread calculations that I want to be handled server-side as a single source of truth. Yes, the client has a copy of the map data loaded locally but since the server is doing the fire spread calculations, it also needs a copy of that map data. Unfortunately, that map data is loaded once for each game room created. That's using up a lot of my Web Traffic data!

So I then proceeded to serialize the map data into a byte[], using shorts instead of ints to save space, then I save that byte[] into BigDB. That was able to reduce the file size from 5 to 8mb to only 1.5mb! I can load 1.5mb map data 66,000 times for my $25/mo plan. That's acceptable I think.

But my issue is that I used BinaryFormatter to serialize my data client-side, save it to BigDB, then the server loads that data from BigDB, deserialize it and done. Hence my issue, I cannot deserialize my map data server-side using BinaryFormatter.

Now is there a way for me to save the map data mentioned above in a serialized way and be able to deserialize that map data server-side without using BinaryFormatter?

Thanks for helping me Henrik! This is a pretty big roadblock for me atm!
jasonredhawk
Paid Member
 
Posts: 25
Joined: April 4th, 2013, 9:15 pm

Re: Is PlayerIO contain analog for BinaryFormatter

Postby Henrik » March 27th, 2020, 6:18 am

BinaryFormatter is a general purpose versioned .Net whole-object-graph serializer, which can serialize everything within certain constraints.

But you already know exactly what data you have, and what it looks like, so write your own serializer instead! It's very little code, actually.

You have a 128-length array of 3-length arrays of shorts. You can use BinaryWriter and BinaryReader in multiplayer code, so something like this to serialize your short[][] elevations into byte[] result:

Code: Select all
byte[] result;
using (var ms = new MemoryStream(128*3*2)) { //128 items, three shorts in each, each short is 2 bytes.
   using (var bw = new BinaryWriter(ms)) {
      foreach (var el in elevations) {
         bw.Write(el[0]);
         bw.Write(el[1]);
         bw.Write(el[2]);
      }
   }
   result = ms.ToArray();
}

And to deserialize back your byte[] input into an array of arrays of shorts:

Code: Select all
var result = new short[128][]; //128 items
using (var br = new BinaryReader(new MemoryStream(input))) {
   for (int i = 0; i < 128; i++) {
      result[i] = new short[3]; //3 shorts in each
      for (int j = 0; j < 3; j++)   {
         result[i][j] = br.ReadInt16(); //Read each short
      }
   }
}
Henrik
.IO
 
Posts: 1880
Joined: January 4th, 2010, 1:53 pm

Re: Is PlayerIO contain analog for BinaryFormatter

Postby jasonredhawk » March 28th, 2020, 8:39 pm

Thanks Henrik for your solution! It worked great!

I had to update your code a little as it didn't quite fit my model but the use of BinaryWriter and BinaryReader was exactly what I needed! Now I can serialize my data client-side, save it to BigDB, and deserialize it server-side. And it's wonderfully small and compressed, so this should do nicely!

I've attached part of the code I used in case others are looking for a similar solution.

Code: Select all

    [Serializable]
    public class MapSection{
        public short[,] elevation;
        public short[,] fuelCode;
        public short[,] vegetationCode;
    }
   
    public static byte[] MapSectionToByteArray(MapSection mapSection)
    {
        byte[] result;

        using (var ms = new MemoryStream(128*128*3*2)) {
            using (var bw = new BinaryWriter(ms)) {
                for (var i = 0; i < 128; i++) {
                    for (var j = 0; j < 128; j++) {
                        bw.Write(mapSection.elevation[i,j]);
                        bw.Write(mapSection.fuelCode[i,j]);
                        bw.Write(mapSection.vegetationCode[i,j]);
                    }
                }
            }
            result = ms.ToArray();
        }

        return result;
    }

    public static MapSection ByteArrayToMapSection(byte[] arrBytes)
    {
        MapSection mapSection = new MapSection();
        mapSection.elevation = new short[128,128];
        mapSection.fuelCode = new short[128,128];
        mapSection.vegetationCode = new short[128,128];

        using (var br = new BinaryReader(new MemoryStream(arrBytes))) {
            for (int i = 0; i < 128; i++) {
                for (int j = 0; j < 128; j++) {
                    mapSection.elevation[i,j] = br.ReadInt16(); //Read each short
                    mapSection.fuelCode[i,j] = br.ReadInt16(); //Read each short
                    mapSection.vegetationCode[i,j] = br.ReadInt16(); //Read each short
                }
            }
        }

        return mapSection;
    }


Thanks again for your solution!
jasonredhawk
Paid Member
 
Posts: 25
Joined: April 4th, 2013, 9:15 pm


Return to C#