/// <summary>
        /// Draws an int slider belonging to the object with the specified field name.
        /// </summary>
        /// <param name="obj">The object being drawn.</param>
        /// <param name="name">The name of the field.</param>
        /// <param name="minValue">The minimum slider value.</param>
        /// <param name="maxValue">The maximum slider value.</param>
        public static void DrawFieldIntSlider(object obj, string name, int minValue, int maxValue)
        {
            var sliderValue = GetFieldValue <int>(obj, name);
            var value       = EditorGUILayout.IntSlider(new GUIContent(InspectorUtility.SplitCamelCase(name), GetFieldTooltip(obj, name)), sliderValue, minValue, maxValue);

            if (sliderValue != value)
            {
                SetFieldValue(obj, name, value);
            }
        }
        /// <summary>
        /// Draws all of the serialized fields.
        /// </summary>
        /// <param name="obj">The object to draw all of the fields of.</param>
        /// <param name="drawNoFieldsNotice">Should a notice be drawn if no fields can be drawn?</param>
        /// <param name="hashPrefix">The prefix of the hash from the parent class. This value will prevent collisions with similarly named objects.</param>
        /// <returns>The updated object value based on the drawn fields.</returns>
        private static object DrawFields(object obj, bool drawNoFieldsNotice, int hashPrefix)
        {
            if (obj == null)
            {
                return(null);
            }

            // Only the serialized objects need to be drawn.
            var objType     = obj.GetType();
            var fieldsDrawn = false;
            var hash        = hashPrefix + Serialization.StringHash(obj.GetType().FullName);
            var fields      = Serialization.GetSerializedFields(objType, MemberVisibility.Public);

            for (int i = 0; i < fields.Length; ++i)
            {
                // Do not draw HideInInspector fields.
                if (UnityEngineUtility.HasAttribute(fields[i], typeof(HideInInspector)))
                {
                    continue;
                }
                EditorGUI.BeginChangeCheck();
                // Fields can have tooltips assocaited with them. Tooltips are visible when hovering over the field label within the inspector.
                GUIContent guiContent;
                var        tooltip = InspectorUtility.GetTooltipAttribute(fields[i]);
                if (tooltip != null)
                {
                    guiContent = new GUIContent(InspectorUtility.SplitCamelCase(fields[i].Name), tooltip.tooltip);
                }
                else
                {
                    guiContent = new GUIContent(InspectorUtility.SplitCamelCase(fields[i].Name));
                }
                var value = fields[i].GetValue(obj);
                value = DrawObject(guiContent, fields[i].FieldType, value, fields[i].Name, hash, null, null, fields[i], true);
                // Update the object if the value was changed.
                if (EditorGUI.EndChangeCheck())
                {
                    fields[i].SetValue(obj, value);
                }
                fieldsDrawn = true;
            }
            // Draw a notice if no fields were drawn.
            if (drawNoFieldsNotice && !fieldsDrawn)
            {
                EditorGUILayout.LabelField("(No Visible Fields)");
            }

            return(obj);
        }
        /// <summary>
        /// Draws all of the serialized properties.
        /// </summary>
        /// <param name="type">The type of object to draw.</param>
        /// <param name="obj">The drawn object. This value can be null (such as if it hasn't been serialized).</param>
        /// <param name="hashPrefix">The prefix of the hash from the parent class. This value will prevent collisions with similarly named objects.</param>
        /// <param name="valuePositionMap">A map between the value hash and the position within the positions array.</param>
        /// <param name="serialization">The serialized data.</param>
        /// <param name="visibility">Specifies the visibility of the properties that should be drawn.</param>
        /// <param name="startDrawElementCallback">Callback issued before the elements are drawn.</param>
        /// <param name="endDrawElementCallback">Callback issued after the elemts are drawn.</param>
        /// <returns>The updated object value based on the drawn properties.</returns>
        public static object DrawProperties(Type type, object obj, int hashPrefix, Dictionary <int, int> valuePositionMap, Serialization serialization, MemberVisibility visibility, Action startDrawElementCallback, Func <int, List <int>, bool> endDrawElementCallback)
        {
            // Only the serialized properties need to be drawn.
            var properties = Serialization.GetSerializedProperties(type, visibility);

            for (int i = 0; i < properties.Length; ++i)
            {
                var bitwiseHash = new Version(serialization.Version).CompareTo(new Version("3.1")) >= 0;
                int hash;
                if (bitwiseHash)
                {
                    hash = (hashPrefix * Serialization.HashMultiplier) ^ (Serialization.StringHash(properties[i].PropertyType.FullName) + Serialization.StringHash(properties[i].Name));
                }
                else
                {
                    hash = hashPrefix + Serialization.StringHash(properties[i].PropertyType.FullName) + Serialization.StringHash(properties[i].Name);
                }
                int position;
                // The value may not be serialized.
                if (!valuePositionMap.TryGetValue(hash, out position))
                {
                    continue;
                }

                // Issue the start callback before the value is drawn.
                if (startDrawElementCallback != null)
                {
                    startDrawElementCallback();
                }
                var value = Serializer.BytesToValue(properties[i].PropertyType, properties[i].Name, valuePositionMap, hashPrefix, serialization.Values,
                                                    serialization.ValuePositions, serialization.UnityObjects, false, visibility, bitwiseHash);

                EditorGUI.BeginChangeCheck();

                // Get a list of Unity Objects before the property is drawn. This will be used if the property is deleted and the Unity Object array needs to be cleaned up.
                var unityObjectIndexes = new List <int>();
                Serialization.GetUnityObjectIndexes(ref unityObjectIndexes, properties[i].PropertyType, properties[i].Name, hashPrefix, valuePositionMap, serialization.ValueHashes, serialization.ValuePositions,
                                                    serialization.Values, false, visibility, bitwiseHash);

                // Draw the property.
                value = DrawObject(new GUIContent(InspectorUtility.SplitCamelCase(properties[i].Name)), properties[i].PropertyType, value, properties[i].Name, hashPrefix, valuePositionMap, serialization, properties[i], false);

                // Issue the end callback after the value is drawn.
                if (endDrawElementCallback != null)
                {
                    var elementRemoved = endDrawElementCallback(i, unityObjectIndexes);
                    if (elementRemoved)
                    {
                        return(obj);
                    }
                }

                if (EditorGUI.EndChangeCheck())
                {
                    // If the hash prefix isn't zero then the object shouldn't be serialized immediately because it isn't a base property. Set the value of the parent object and mark the GUI as changed
                    // so it'll be serialized by the base property. For example, if ClassA exists and has properties One and Two. If the One value is changed the serializer should serialize the ClassA object
                    // rather then the One object.
                    if (hashPrefix != 0)
                    {
                        GUI.changed = true;
                        var setMethod = properties[i].GetSetMethod();
                        if (setMethod != null)
                        {
                            setMethod.Invoke(obj, new object[] { value });
                        }
                        return(obj);
                    }

                    // Remove the current element and then add it back at the end. The order of the values doesn't matter and this prevents each subsequent element from needing to be modified because the current
                    // value could have changed sizes.
                    Serialization.RemoveProperty(i, unityObjectIndexes, serialization, visibility, bitwiseHash);

                    // Add the property to the Serialization data.
                    Serialization.AddProperty(properties[i], value, unityObjectIndexes, serialization, visibility);

                    break;
                }
            }
            return(obj);
        }