/// <summary> /// Calculates how many bytes can be stored in the given message. /// </summary> /// <param name="message">The message in which the bytes will be stored.</param> /// <returns>The number of bytes that can be stored until the message is too big to be sent.</returns> public static int GetFreeByteElementCount(MessageIncomingMessageParts message) { message.Content = new byte[1]; var xmlText = MyAPIGateway.Utilities.SerializeToXML <MessageContainer>(new MessageContainer() { Content = message }); var oneEntry = System.Text.Encoding.UTF8.GetBytes(xmlText).Length; message.Content = new byte[4]; xmlText = MyAPIGateway.Utilities.SerializeToXML <MessageContainer>(new MessageContainer() { Content = message }); var twoEntries = System.Text.Encoding.UTF8.GetBytes(xmlText).Length; // we calculate the difference between one and two entries in the array to get the count of bytes that describe one entry // we divide by 3 because 3 entries are stored in one block of the array var difference = (double)(twoEntries - oneEntry) / 3d; // get the size of the message without any entries var freeBytes = MAX_MESSAGE_SIZE - oneEntry - Math.Ceiling(difference); int count = (int)Math.Floor((double)freeBytes / difference); // finally we test if the calculation was right message.Content = new byte[count]; xmlText = MyAPIGateway.Utilities.SerializeToXML <MessageContainer>(new MessageContainer() { Content = message }); var finalLength = System.Text.Encoding.UTF8.GetBytes(xmlText).Length; Logger.Instance.LogDebug(string.Format("FinalLength: {0}", finalLength)); if (MAX_MESSAGE_SIZE >= finalLength) { return(count); } else { throw new Exception(string.Format("Calculation failed. OneEntry: {0}, TwoEntries: {1}, Difference: {2}, FreeBytes: {3}, Count: {4}, FinalLength: {5}", oneEntry, twoEntries, difference, freeBytes, count, finalLength)); } }
private static void SendMessageParts(byte[] byteData, MessageSide side, ulong receiver = 0) { Logger.Instance.LogDebug(string.Format("SendMessageParts {0} {1} {2}", byteData.Length, side, receiver)); var byteList = byteData.ToList(); while (byteList.Count > 0) { // we create an empty message part var messagePart = new MessageIncomingMessageParts() { Side = side, SenderSteamId = side == MessageSide.ServerSide ? MyAPIGateway.Session.Player.SteamUserId : 0, LastPart = false, }; try { // let's check how much we could store in the message int freeBytes = GetFreeByteElementCount(messagePart); int count = freeBytes; // we check if that might be the last message if (freeBytes > byteList.Count) { messagePart.LastPart = true; // since we changed LastPart, we should make sure that we are still able to send all the stuff if (GetFreeByteElementCount(messagePart) > byteList.Count) { count = byteList.Count; } else { throw new Exception("Failed to send message parts. The leftover could not be sent!"); } } // fill the message with content messagePart.Content = byteList.GetRange(0, count).ToArray(); var xmlPart = MyAPIGateway.Utilities.SerializeToXML <MessageContainer>(new MessageContainer() { Content = messagePart }); var bytes = System.Text.Encoding.UTF8.GetBytes(xmlPart); // and finally send the message switch (side) { case MessageSide.ClientSide: if (MyAPIGateway.Multiplayer.SendMessageTo(MessageId, bytes, receiver)) { byteList.RemoveRange(0, count); } else { throw new Exception("Failed to send message parts to client."); } break; case MessageSide.ServerSide: if (MyAPIGateway.Multiplayer.SendMessageToServer(MessageId, bytes)) { byteList.RemoveRange(0, count); } else { throw new Exception("Failed to send message parts to server."); } break; } } catch (Exception ex) { Logger.Instance.LogException(ex); return; } } }