public static PropertyField[] GetProperties(object obj)
		{
			var fields = new List<PropertyField>();
			
			PropertyInfo[] infos = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
			
			foreach (PropertyInfo info in infos)
			{
				if (!(info.CanRead && info.CanWrite))
					continue;
				
				object[] attributes = info.GetCustomAttributes(true);
				
				bool isExposed = false;
				foreach (object o in attributes)
					if (o.GetType() == typeof(ExposePropertyAttribute))
				{
					isExposed = true;
					break;
				}
				if (!isExposed)
					continue;
				
				var type = SerializedPropertyType.Integer;
				if (PropertyField.GetPropertyType(info, out type))
				{
					var field = new PropertyField(obj, info, type);
					fields.Add(field);
				}
			}
			
			return fields.ToArray();
		}
		public static void Expose(PropertyField[] properties)
		{
			var emptyOptions = new GUILayoutOption[0];
			EditorGUILayout.BeginVertical(emptyOptions);
			foreach (PropertyField field in properties)
			{
				EditorGUILayout.BeginHorizontal(emptyOptions);
				if (field.Type == SerializedPropertyType.Integer)
				{
					var oldValue = (int)field.GetValue();
					var newValue = EditorGUILayout.IntField(field.Name, oldValue, emptyOptions);
					if (oldValue != newValue)
						field.SetValue(newValue);
				}
				else if (field.Type == SerializedPropertyType.Float)
				{
					var oldValue = (float)field.GetValue();
					var newValue = EditorGUILayout.FloatField(field.Name, oldValue, emptyOptions);
					if (oldValue != newValue)
						field.SetValue(newValue);
				}
				else if (field.Type == SerializedPropertyType.Boolean)
				{
					var oldValue = (bool)field.GetValue();
					var newValue = EditorGUILayout.Toggle(field.Name, oldValue, emptyOptions);
					if (oldValue != newValue)
						field.SetValue(newValue);
				}
				else if (field.Type == SerializedPropertyType.String)
				{
					var oldValue = (string)field.GetValue();
					var newValue = EditorGUILayout.TextField(field.Name, oldValue, emptyOptions);
					if (oldValue != newValue)
						field.SetValue(newValue);
				}
				else if (field.Type == SerializedPropertyType.Vector2)
				{
					var oldValue = (Vector2)field.GetValue();
					var newValue = EditorGUILayout.Vector2Field(field.Name, oldValue, emptyOptions);
					if (oldValue != newValue)
						field.SetValue(newValue);
				}
				else if (field.Type == SerializedPropertyType.Vector3)
				{
					var oldValue = (Vector3)field.GetValue();
					var newValue = EditorGUILayout.Vector3Field(field.Name, oldValue, emptyOptions);
					if (oldValue != newValue)
						field.SetValue(newValue);
				}
				else if (field.Type == SerializedPropertyType.Enum)
				{
					var oldValue = (Enum)field.GetValue();
					var newValue = EditorGUILayout.EnumPopup(field.Name, oldValue, emptyOptions);
					if (oldValue != newValue)
						field.SetValue(newValue);
				}
				else if (field.Type == SerializedPropertyType.Color)
				{
					var oldValue = (Color)field.GetValue();
					var newValue = EditorGUILayout.ColorField(field.Name, oldValue, emptyOptions);
					if (oldValue != newValue)
						field.SetValue(newValue);
				}
				EditorGUILayout.EndHorizontal();
			}
			EditorGUILayout.EndVertical();
		}