Custom Inspector: Mixing custom drawer and default property drawers

I’ve been playing around with ScriptableObjects and using them to define parameters for my Dialog display gameobject.  In previous instances, I’d just use constant strings and pass them to the function that creates and displays the dialog.  After reading about ScriptableObjects, I decided to give them a shot to build strings for the dialogs.

Everything was great, except for the inspector displaying long strings.  They just get truncated of the right side of the display.  The behavior exhibited by the NGUI UILabel inspector is much better, as any text to long to be displayed in the inspector is wrapped and the field is extended vertically.

I found the NGUI code in UILabelInspector that handles the displaying of strings across multiple lines, and took a copy to use in my own inspector.  Then I realized, with a custom inspector I have to display all the properties myself, and I didn’t want to (a) write a custom display for each property type, and (b) remember to extend the inspector anytime I modified my ScriptableObject class.

The second problem was solved by iterating over the SerializedProperties contained in the SerializedObject, while the first problem was solved by calling EditorGui.PropertyField on SerializedProperties I didn’t want to display myself.

I then added an exception for the ‘Script’ property, to make it non-editable.

This resulted in the code below:

public override void OnInspectorGUI()
{
	serializedObject.Update();
	SerializedProperty sp = serializedObject.GetIterator();
	if (!sp.NextVisible(true))
		sp = null;
	while (sp!=null)
	{
		if (sp.type == "string")
			DrawMultiLineString(sp.name);
		else
		{
			Rect position = EditorGUILayout.GetControlRect(GUILayout.Height(EditorGUI.GetPropertyHeight(sp)));
			if (sp.name == "m_Script")
			{
				EditorGUI.BeginDisabledGroup(true);
				EditorGUI.PropertyField(position, sp, new GUIContent(sp.displayName), true);
				EditorGUI.EndDisabledGroup();
			}
			else
				EditorGUI.PropertyField(position, sp, new GUIContent(sp.displayName), true);
		}
		if (!sp.NextVisible(true))
			sp = null;
	}
	serializedObject.ApplyModifiedProperties();
}

The call to DrawMultiLineString uses code directly from NGUI’s UILabelInspector, and is not available unless you have NGUI for Unity.

Unity3D and OnValidate

So, I came across MonoBehaviour method earlier today that I’d previously missed:

void OnValidate()

This is called when a script is loaded, or (editor only) when a parameter is changed via the inspector.  I’m using this to allow me to set a property that has a getter/setter via the inspector by using an extra variable.   I set the extra copy in the inspector, and then use code in OnValidate to copy it to the setter method.

I’m also going to use it instead of the Update method for my editor scripts – Update is called every time something changes in the editor, OnValidate, only when something on that script changes – much more effective.

Sending Gmail from Java

Further to my java stuff from yesterday, I wanted to add the ability to send myself an email when the task completes successfully.  I poked around the web and found this solution:

https://www.mkyong.com/java/javamail-api-sending-email-via-gmail-smtp-example/

The first example worked for me, once I enabled the ‘less secure’ apps method for my Gmail account.

I modified the above code, using the snippet at this link.  This let me send an attachment with the email!

public class SendAttachmentInEmail {
   public static void main(String[] args) {
      // Recipient's email ID needs to be mentioned.
      String to = "destinationemail@gmail.com";

      // Sender's email ID needs to be mentioned
      String from = "fromemail@gmail.com";

      final String username = "username";//change accordingly
      final String password = "password";//change accordingly

      // Assuming you are sending email through relay.jangosmtp.net
      String host = "relay.jangosmtp.net";

      Properties props = new Properties();
      props.put("mail.smtp.auth", "true");
      props.put("mail.smtp.starttls.enable", "true");
      props.put("mail.smtp.host", "smtp.gmail.com");
      props.put("mail.smtp.port", "587");

      // Get the Session object.
      Session session = Session.getInstance(props,
         new javax.mail.Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
               return new PasswordAuthentication(username, password);
            }
         });

      try {
         // Create a default MimeMessage object.
         Message message = new MimeMessage(session);

         // Set From: header field of the header.
         message.setFrom(new InternetAddress(from));

         // Set To: header field of the header.
         message.setRecipients(Message.RecipientType.TO,
            InternetAddress.parse(to));

         // Set Subject: header field
         message.setSubject("Testing Subject");

         // Create the message part
         BodyPart messageBodyPart = new MimeBodyPart();

         // Now set the actual message
         messageBodyPart.setText("This is message body");

         // Create a multipar message
         Multipart multipart = new MimeMultipart();

         // Set text message part
         multipart.addBodyPart(messageBodyPart);

         // Part two is attachment
         messageBodyPart = new MimeBodyPart();
         String filename = "/home/cwg/file.txt"; //full path to file you want to attach
         DataSource source = new FileDataSource(filename);
         messageBodyPart.setDataHandler(new DataHandler(source));
         messageBodyPart.setFileName(filename); //attachment name in the email
         multipart.addBodyPart(messageBodyPart);

         // Send the complete message parts
         message.setContent(multipart);

         // Send message
         Transport.send(message);

         System.out.println("Sent message successfully....");
  
      } catch (MessagingException e) {
         throw new RuntimeException(e);
      }
   }
}

Running JAVA class from Mac OS CLI

I wrote a utility in Java that I want to eventually run as a cron job, which means I need to be able to specify the path that the code uses for its files.

There is a command line parameter that is passed to the java command that can be used to specify a particular directory, and then my java code can use that as the base path.

My command line to execute the java code is:

java -cp /Users/cwg/workspace/getInfo/bin -Duser.dir=/Users/cwg/workspace/getInfo com.cwgtech.getInfo

This will call the java code from any path, and the -Duser.dir sets the user variable to point to the path my data is stored in.

In the java code, I access the passed variable with the following code:

workingPath = System.getProperty("user.dir") + "/";

Then when I want to access a file or folder, I just pre-pend it with the workingPath String.

Node xml = loadXML(workingPath + XMLFILE);

Note: Don’t use ~ in the path for the java command, use the fully qualified path!

Also, I ended up using a couple of external Jars in my code, so I had to modify the -cp option to include the path to my lib folder as follows:

-cp /Users/cwg/workspace/getInfo/bin:/Users/cwg/workspace/getInfo/libs/*

The * at the end of the second path says to use all the jar (or zip) files in the specified folder when looking for classes.  The : is the separator if you need more than one path in -classpath (can be shortened to -cp)

Saving a PSD file with a .PNG extension 😫

I’ve been working on an update to one of our apps for iOS. Unfortunately as I was updating the launch screens, I inadvertently saved a version for the iPhone 5 as a PSD file, but using the .PNG extension.   I did this by clicking on the old PNG file in the file selector to make sure it was named correctly, but them omitted to clicking on the Save Type drop down list and selecting PNG.

Now, the Mac figured it out, and would display the image in Finder and XCode was happy to load and preview it.  Even the iOS emulator didn’t mind using a PSD file in this way.  However, the actual iPhone was less than happy.

I wasted 3 hours trying to figure out the problem before I spotted my mistake. Surely something on the Mac side should have flagged the file as having a problem – the iPhone can’t load PSD files, why the hell should the emulator!

Yes, I know I saved the file incorrectly, but if it was incorrect, then it should have spewed out some kind of error.  Hopefully I’ll not make this mistake again!