private string SerializeValue(Type?propertyType, object?value, IEnumerable <ValidationAttribute?>?validationAttributes, PacketIndexAttribute?packetIndexAttribute = null)
        {
            if (propertyType == null && validationAttributes.All(a => a !.IsValid(value)))
            {
                return(string.Empty);
            }

            if (packetIndexAttribute?.IsOptional == true && string.IsNullOrEmpty(Convert.ToString(value)))
            {
                return(string.Empty);
            }

            // check for nullable without value or string
            if (propertyType == typeof(string) && string.IsNullOrEmpty(Convert.ToString(value)))
            {
                return($"{packetIndexAttribute?.SpecialSeparator}-");
            }

            if (propertyType != null && Nullable.GetUnderlyingType(propertyType) != null && string.IsNullOrEmpty(Convert.ToString(value)))
            {
                return($"{packetIndexAttribute?.SpecialSeparator}-1");
            }

            // enum should be casted to number
            if (propertyType !.BaseType?.Equals(typeof(Enum)) == true)
            {
                return($"{packetIndexAttribute?.SpecialSeparator}{Convert.ToInt16(value)}");
            }

            if (propertyType == typeof(bool))
            {
                // bool is 0 or 1 not True or False
                return(Convert.ToBoolean(value) ? $"{packetIndexAttribute?.SpecialSeparator}1" : $"{packetIndexAttribute?.SpecialSeparator}0");
            }

            if (value is IPacket)
            {
                PacketInformation subpacketSerializationInfo = GetSerializationInformation(value.GetType());
                return(SerializeSubpacket(value, subpacketSerializationInfo, packetIndexAttribute?.IsOptional ?? false));
            }

            if (propertyType.BaseType?.Equals(typeof(IPacket)) == true)
            {
                PacketInformation subpacketSerializationInfo = GetSerializationInformation(propertyType);
                return(SerializeSubpacket(value, subpacketSerializationInfo, packetIndexAttribute?.IsOptional ?? false));
            }

            if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition().IsAssignableFrom(typeof(List <>)) &&
                propertyType.GenericTypeArguments[0].BaseType == typeof(IPacket))
            {
                return(packetIndexAttribute?.SpecialSeparator + SerializeSubpackets((IList?)value, propertyType));
            }

            if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition().IsAssignableFrom(typeof(List <>))) //simple list
            {
                return(packetIndexAttribute?.SpecialSeparator + SerializeSimpleList((IList?)value, propertyType, packetIndexAttribute));
            }

            return($"{packetIndexAttribute?.SpecialSeparator}{value}");
        }
        public string Serialize(IPacket packet, Type type)
        {
            try
            {
                // load pregenerated serialization information
                PacketInformation serializationInformation = GetSerializationInformation(type);

                var builder = new StringBuilder();
                builder.Append(serializationInformation.Header);

                int lastIndex = 0;

                foreach (PacketPropertyContainer property in serializationInformation.PacketProps !)
                {
                    PacketIndexAttribute?packetIndex  = property.PacketIndex;
                    PropertyInfo?        propertyType = property.PropertyInfo;
                    IEnumerable <ValidationAttribute?>?validations = property.Validations;
                    // check if we need to add a non mapped values (pseudovalues)
                    if (packetIndex !.Index > lastIndex + 1)
                    {
                        int amountOfEmptyValuesToAdd = packetIndex.Index - (lastIndex + 1);

                        for (int j = 0; j < amountOfEmptyValuesToAdd; j++)
                        {
                            builder.Append(" 0");
                        }
                    }

                    // add value for current configuration
                    builder.Append(SerializeValue(propertyType !.PropertyType, propertyType.GetValue(packet), validations, packetIndex));

                    // check if the value should be serialized to end
                    if (packetIndex.Index > serializationInformation.PacketProps.Length)
                    {
                        // we reached the end
                        break;
                    }

                    // set new index
                    lastIndex = packetIndex.Index;
                }

                return(builder.ToString());
            }
            catch (Exception)
            {
                return(string.Empty);
            }
        }