Oops! I originally called this article “Awake() and Sleep() differences.” It is actually about “Awake() and Start() differences.”
My bad.
Currently hacking my way through the new Unity3D game engine and encountered a problem I hadn’t run in to before.
For several days the game I am working on has been loading up just fine, no significant code changes in the parts of the code that was causing the problem.
Here are the events as I remember them. For the past four or five days I have had the Unity3D editor open constantly, never closed it down. The game runs fine. Last night I decide to play some quick games of Left 4 Dead at the office on the LAN. I started to suffer odd glitches with my network when running my workstation as the game server so decided to shut down all non-essential applications (everything except for L4D) to try and isolate the issue. This morning when I start up Unity 3D, my game is crashing for no apparent reason, and not only that, but bringing down the whole Unity 3D editor along with it.
Throwing in a few try/catch exception handlers around various bits of code I isolate it to some multi-threaded code in my game. This is the cause of the Unity 3D editor crash and is a well known issue. If you throw an exception on a thread other than the main thread, it will also break the Unity 3D application.
No big deal, put in some more try/catch handling on the multi-threaded part of the code and see what’s going on.
What was happening is that the other thread is attempting to access GameObjects that have not yet been instantiated. Which is weird because the day before I restarted the Unity editor, it all worked fine.
This the tricky part about Unity 3D. The Awake and Start functions are called in a “random order.” Awake acts like the constructor for the GameObject and attached scripts, and Start is called just at the point when a GameObject is about to become alive. Awake is always guaranteed to be called before Start, but only on a particular GameObject. You could have Awake invoked on object 2, then Start invoked on object 1 that was previously instantiated, and then Awake on object 3, and then Start on object 2, and finally Start on object 3. The order of Awake and Start for each object is guaranteed, but not for a group of objects.
If I have a GameObject and script that instantiates a whole bunch of other GameObjects in the Start function, when I instantiate those GameObjects, their Awake functions are called, but their Start functions may not be. When the Start functions are called on the newly created GameObjects is entirely up in the air.
Now enter the multi-threaded portion of the code. The newly created GameObjects exist, Awake has been called on each one of them, but each and every one of them may or may not have had their Start functions invoked. I got lucky before, everything ran correctly. But when I opened up the Unity 3D editor again, the order of execution I was relying on, and made an assumption about, had changed.
The multi-threaded code was relying on a piece of information that only got created inside of the Start function of the GameObject. But the Start function had not yet been called. Moving the part of the code that looks up a value from a table and stores it in the GameObject instance from the Start function to Awake function fixed the problem. A classic race-hazard problem.
This isn’t specifically about multi-threaded code, it is about the difference between Awake and Start. I had confused the two functions in how they worked. I imagined, and I do not know why, that Start was called immediately after Awake, not at some arbitrary point in the future that is unknowable.
This problem could easily be replicated if I had attempted, immediately after instantiating my objects, I had attempted in the same function to read off a value from the newly created object, which would not be set up until the Start function is invoked.
Lesson reinforced: Awake is called immediately upon instantiation of a GameObject, just like it says in the Unity 3D documentation, it is the constructor as far as Unity is concerned. Start is called whenever Unity 3D damn well feels like, in a random order (I suspect the underlying mechanism is a list of GameObjects that need to be started or a tree that emulates the scene hierarchy) that is not guaranteed from one execution of the game to the next.
I just got lucky for a week (should have bought a lottery ticket and raided in WoW for some sweet loot drops if I was that lucky) but then it all came crashing down when I restarted Unity 3D.
Posted in Software Development | No Comments »
Related posts:
Want to develop on your actual iPhone device from your Windows PC using the official Apple XCode tools running under VMWare?
If you’re a professional developer who has to develop for multiple operating systems, you often want to be able to debug on your target devices without having to have a separate machine to do it on.
I’ve been developing for iPhone and iPad for quite some time now, and whilst I have a Mac laptop, I don’t like using it all that much for development, primarily because my desk just isn’t big enough for yet another computer and peripherals and monitors. I would rather run Mac OS X on top of VMWare as a guest operating system of my Windows 7 workstation.
It’s trivial to get XCode installed and running to let you use the iPhone or iPad simulator, but what about downloading your code to a physical device and actual debugging?
That last bit is surprisingly easy so here’s how you do it.
I will assume you have your Mac OS X installed on VMWare, your XCode and iPhone SDK is all set up properly, and you can build and run projects successfully under the device simulator.
To get access to physical device debugging, you need to install iTunes on your Microsoft Windows host operating system as well as on the guest Apple Mac OS X. Obviously Mac OS X comes with iTunes installed by default but depending on which version of the OS you installed, you may need to update it. I know this works with 9.0.2 and 9.2, earlier versions I have yet to test.
You do not need to be running the same version of iTunes on both guest Mac OS X and Windows. Just so long as both operating systems have it installed.
Start up your Mac OS X virtual machine and once it is running, connect your iPhone or iPad to your Windows PC. Your device should make the “connected tone” and if you have iTunes on Windows to start synchronization automatically, that should proceed as normal.
Either wait for the sync to complete or cancel it, whichever is your pleasure.
Once you’re connected and synchronization is no longer taking place, switch back to your VMWare window, and in the lower right corner of the window, where all of the icons reside for the status of various devices you should see one for your iPhone or iPad device.
On my machine, it looks like this:
That’s the second icon from the right, that looks like a little digital camera.
Right click on the icon and you will see the following context menu will pop up.
Select the first option, “Connect (Disconnect from Host)” and your iPhone or iPad will disconnect from Windows and reconnect to Mac OS X. Pretty simple, but very few people talk about doing this obvious step, and most blogs just mention getting XCode installed under VMWare.
At this point, you’re now free to proceed with on-device debugging and testing as though the device were connected to a real Mac.
Now, for whatever reason I cannot get iTunes on the Mac OS X guest operating system to see my iPad, but XCode talks to it just fine, allowing me to browse the logs, restore the image, etc. C’est la vie.
I can confirm this little trick works for both jail broken devices and also devices that have been provisioned for development through the normal channels.
Next stop: SenseCam for the iPhone.
Posted in Software Development | No Comments »
Related posts:
I have been trying, unsuccessfully, for two days to download the latest iPhone SDK and XCode IDE from the Apple Developer Center with absolutely no luck.
I’ve recently moved in to a new house and the DSL connection we have, slow at the best of times, flakes out several dozen times per day. Connectivity problems aside, there had to be a way of reliably downloading large files from Apple’s Developer Center without using Firefox or Internet Explorer because neither of them would resume a failed download. Unfortunately, after having also messed about with a few different download managers, none them would continue a broken download either.
What to try next?
How about good old fashioned WGET?
WGET, originally for UNIX, and available as part of the GNUWin32 project for Windows, is an absolutely fantastic command line tool. WGET lets you retrieve web pages and files from both web servers and ftp servers anywhere on the internet. It’s robust, flexible, versatile, reliable and is a really handy tool to have in your tool box.
Back to the problem of reliably downloading XCode and the iPhone SDK, a two gigabyte disc image which means plenty of chances for crapping out before the download completes.
Apple’s Developer Center requires that you login, which means session state, and that is going to be in the form of a cookie. That’s easy then, we just need to get access to that cookie. One twist though, and I found this out after a little messing about is that when you download the iPhone SDK, or in fact any kind of secured download, it gives you another cookie that is valid for that download.
The job is to get those cookies out of Firefox, or whatever other web browser you use, and into a format suitable for WGET.
I will detail how to export your cookies in a while, but the first thing you have to do is get the cookies from Apple.
Load up Firefox or Internet Explorer , login to the Apple Developer Center website at http://developer.apple.com, then navigate to the file you want to download, in this case, XCode 3.2.3 with the iPhone 4 SDK.
The URL for that particular file is https://developer.apple.com/mac/scripts/downloader.php?path=/iphone/iphone_sdk_4__final/xcode_3.2.3_and_iphone_sdk_4__final.dmg.
Make sure you click to download the file via your web browser. That step is very important. After a few seconds of file transfer you can terminate the download.
The reason for this is that you need the download authorization cookie as well as the website user login cookie that are supplied. If you do not do this download and terminate step, you won’t get the proper cookies.
The version of Firefox that I am running stores the cookies in a SQLite database, not exactly human readable.
Firefox add-ons to the rescue!
I am currently running Firefox 3.6.4 so I used the Cookie Exporter 1.5 add-on to export my cookies in to a cookies.txt file that WGET can make use of.
Assuming you have Firefox open and are logged in to the Apple Developer Center.
Install Cookie Exporter 1.5 or similar add-on if you do not already have a cookie exporter add-on available.
Click Export Cookies from the Tools menu
Browse to the location where you want to export your cookies and click Save. I put mine in C:\temp.
Assuming you have Internet Explorer open and are logged in to the Apple Developer Center.
I saved my cookies.txt file in to C:\temp which is also where I will be downloading the iPhone SDK to.
If you are on Windows, and use Firefox, it may be easier, if you don’t want the hassle of installing an additional add-on to login in to the Apple Developer Center via Internet Explorer. Click the download link you want, and then export your cookies directly from Internet Explorer. It achieves the same result.
Once the cookies are exported in to a cookies.txt file, right click on the link and select “Copy Link Location.”
Right click “Copy Link Location” in Firefox to copy the URL location.
That puts the URL to the file on the clipboard and can be pasted into a command window at the appropriate time.
Okay, I’ve got the cookies, I’ve got the URL of the file. Time to open a command window and navigate to where the location where the cookies.txt file was saved.
Once that’s done, issue the following WGET command: WGET –server-response –continue –no-check-certificate –load-cookies=cookies.txt https://developer.apple.com/mac/scripts/downloader.php?path=/iphone/iphone_sdk_4__final/xcode_3.2.3_and_iphone_sdk_4__final.dmg
The full URL of the file to download is on the clipboard by now, if you have been following along, and so you can just paste it the URL in to the command prompt window.
Paste the download link in to the command prompt window.
Continue: Should you need to terminate the download for any reason, such as a reboot, or closing the command prompt, you can continue downloading where you left by using the –continue option.
No-Check-Certificate: Apple appears to use a self-signed certificate on their Developer website. This means that when WGET goes to check the certificate authority, it throws out an error because WGET cannot verify authenticity. The certificate in this case is not used to prove that Apple is Apple, but to enable a secure connection between your computer and the Apple Developer server. A self-signed certificate is nothing to concern yourself with in this case, your data transfer, including user-name and password are all encrypted between your computer and Apple’s servers.
Load-Cookies: The cookies we saved from our browser session need to be loaded up by WGET, this option allows that to happen. Some older WGET clients will require that the equals sign between –load-cookies and the filename be omitted, be aware of that.
Server-Response: The reason to use the “–server-response” option is to debug the transfer when something goes wrong. With this option you can figure out what the server is trying to tell you. Perhaps a 403 Forbidden error, in which case, make sure you logged in and clicked at least once on the download you want. Perhaps you are getting a 404 Page Not Found, in which case, check to make sure you entered the URL of the file correctly.
The last parameter that begins https://developer.apple.com is the actual URL of the file to download. Again, you can paste that in by copying the download link from your browser.
If everything is working correctly, you should see something like the following:
In that screenshot of the command prompt window, I issued the WGET command and relevant options, and WGET has begun the download of the latest version of XCode and the iPhone 4 SDK. I also threw in the option to limit the download rate to just five kilobytes a second so that it does not affect anybody else trying to use the internet connection.
When you first attempt the download, you may get a failure, just a few kilobytes of downloaded of binary data, and nothing more. If that’s the case, don’t worry, it’s one of two things. In my case it was an old version of WGET.
Firstly, simplest thing to check, you do not have the necessary cookies, in which case, start from the top. You can verify you have the correct cookies by looking in the cookies.txt file for the string ADCDownloadAuth. This is the cookie that Apple Developer Center sends you when you request a download from them.
You can easily search the cookies file by issuing the following command at the command prompt: find “ADCDownloadAuth” cookies.txt
Find the relevant cookie
Second thing to check: You might be like me and have a WGET client that just cannot handle a two gigabyte download. On my workstation I confusingly have two WGET clients, both by GNU. I have version 1.8.2 and version 1.11.4. I have to keep the older version around for a particular application that I am developing for a website that requires a specific version of the WGET client. Unfortunately in my case version 1.8.2 and version 1.11.4 were both on the path, but it found the older version first and decided to execute that.
You can find out which version of WGET you have installed, if any, by issuing the following command at the command prompt:
WGET –version
Make sure you are running an up to date version of WGET otherwise you may not be able to download properly.
These instructions work equally well if you are on a Mac or Linux, you just need to export the cookies from your browser by whatever means you use.
The great thing about using WGET for a big download like this is that the utility will just keep plugging away in the background, until the operation has completed, no matter how many times you have to cancel and continue the download.
If you have both CURL and WGET installed, you can also do the login and download directly from the command line without having to use your browser at all. Just three CURL commands followed by WGET. I’ll leave that solution as an exercise for the reader.
Posted in Articles, Software Development | No Comments »
Related posts: