Articles Archive
Articles Search
Director Wiki
 

Preloading Xtras for Shockwave

April 11, 2000
by Doug Brown

I love life's little ironies. I had an article topic in mind and was mulling it over, and lo and behold a discussion broke out on Shocker-L which was directly related. A very generous individual offered that he was planning to write a 3D Lingo engine as an exercise, and would give it away to anyone interested when finished. Many on the list were totally in favor of this, with one of the supporting reasons being clients are reluctant to allow third party Xtras into Shockwave projects. Primarily, clients are concerned with the extra download time the additional components represent.

This particular point about Xtras in Shockwave was daunting to me for a while as well. I had mostly written off the concept, but came into a couple projects where Xtras offered significant enhancements to the experience. I started looking into a couple things, asking a couple of people questions, and came out with an interesting tidbit of information: downloadable Xtras for Shockwave can be preloaded.

Many Xtras not included with Shockwave by default can be marked as "Download When Needed" using the Modify->Movie->Xtras menu in Director. When Shockwave encounters a movie that uses such an Xtra, it is downloaded from the specified location before any media is loaded or displayed. This can lead to a user staring at a blank Shockwave app with a progress bar that doesn't move for a long, long time, especially if a larger Xtra is being downloaded. The only indication that a required download is taking place is the small text in the browser status line, which is just not really useful.

The trick then is to create a small loader movie. Many people already do this with Shockwave content, both for Director and even more frequently for Flash. (Macromedia actually hopes to see the majority of developers doing this, as it improves the overall user experience) A loader movie can provide a means of entertainment and information for the user. Consider how much more likely a user is to wait for a 1 meg Shockwave file to download if they can play a game of Space Invaders in the interim, as opposed to watching a slow progress meter.

The loader movie depends on one command: preLoadNetThing(). This command loads the file at the specified Internet address into the cache. Once the file is down, it is immediately available for use. This includes external graphics, sounds, cast files, movies, and Xtra download packages. When an Xtra is marked Download When Needed, it is downloaded from the address specified for the Xtra in the "xtrainfo" file, found in the Director folder. A given entry might appear like this:

; Beatnik Xtra by Beatnik Inc.
; http://www.beatnik.com/
[#namePPC:"Beatnik Xtra", #nameW32:"Beatnik.x32",
#package:"http://download.beatnik.com/bxp/BeatnikXtra",
#info:"http://www.beatnik.com/to/?xtra-lite-shockwave"]

Sure, there are lots of other Xtras to choose here, but I'm going to plug Beatnik because it's such a cool technology, and Ian Chia is such a great guy. It was a Beatnik project that tuned me into Xtra preloading, and Ian gave me several pointers on getting it working.

So anyway, let's review what this information tells us. The lines beginning with semicolons are comments, and have no effect on anything. The third line, a property list, contains all the information about the Xtra download. The #namePPC and #nameW32 entries are the full names of the installed Xtras for each platform. The #info property is the Web page opened when the Info... button is clicked in the Modify->Movie->Xtras dialog. The #package property is where the Xtra is going to come from, and this is the information to be concerned with for preloading.

The confusing part about the #package property is that it looks like a path with no file name at the end. This actually isn't the case. The last part of the path name (in this case "BeatnikXtra") is the file name, but without a file extension. Downloadable Xtra packages always have a ".w32" extension for Windows and a ".ppc" extension for Mac. So, if a loader movie were to preload the Beatnik Xtra, the Windows file would be located at "http://download.beatnik.com/bxp/BeatnikXtra.w32". Just preload the file like you would any other, and it will be immediately available when the movie that needs it starts. The Xtra is then instantly installed into the Shockwave Xtras folder on the user's hard drive with no waiting.

There is a catch, of course. When you're ready to leave the loader and go to the movie that needs your preloaded Xtra, you need to do it with goToNetMovie(), and not goToNetPage(). There's a ghost in the machine (sometimes, but not always) where the preloaded Xtra may not be available as expected if you don't.

The Xtra doesn't need to be preloaded every time of course. Once it's installed into Shockwave it's done. So checking to see if the user has the Xtra before issuing the preLoadNetThing() is important. I've included a couple handlers here for doing just that. The first checks to see if a version of the Xtra is present on the system:

on checkXtraInstalled xtraString, versionDelim, xtraVersion
  
  isInstalled = FALSE
  tDelim = the itemDelimiter
  
  repeat with tXtra in the xtraList
    
    if tXtra.name contains xtraString then
      
      the itemDelimiter = versionDelim
      verList = xtraVersion
      tVer = tXtra.version
      numItems = the number of items in tVer
      
      isInstalled = compareVersion(verList, tVer, 1)
    end if
    
  end repeat
  
  the itemDelimiter = tDelim
  return isInstalled
  
end

This first handler steps through the xtraList looking for any Xtra containing the target string. If one is found the version is checked against the target version number by means of this handler:

on compareVersion verList, tVer, iNum
  
  if iNum > count(verList) then
    return TRUE
  else if tVer.item[iNum] > verList[iNum] then
    return TRUE
  else if tVer.item[iNum] < verList[iNum] then
    return FALSE
  else
    return compareVersion(verList, tVer, iNum + 1)
  end if
  
end

The items in the version number from the xtraList are recursively compared to the items in the target version number. As long as the version in the xtraList is at least as new as the number provided, a success is returned. Version numbers for Xtras typically appear in one of two formats: "1, 1, 0" or "1.1.0". Thus the need for the versionDelim parameter in the checkXtraInstalled() handler.

An important point about version checking is that some Xtras, like Beatnik, returned a four-item version number in the xtraList in Director 7. In Director 8, only three items are returned in the version number, regardless of what the Xtra is programmed to return. Apparently, Shockwave never checks beyond the third digit in the version number when making comparisons for its auto-updating feature. To keep things consistent, Macromedia has built Director 8 to behave the same way.

So now that Xtras are preloading all over the place, how about making a coherent progress bar for them? Here are some significant points from a full behavior for making a progress bar that can preloading any number of files.

Download the behavior and code samples in Director 7 format for Mac or Windows.

The behavior is attached to any sprite, and collapses the sprite width to zero when it initializes. Then, as the download progresses, the sprite gradually stretches out to its original width as defined in the score.

on startPreloading me, pList
  
  me.preloadList = pList
  me.startingCount = me.preloadList.count
  me.percentChunk = 1.0/me.startingCount
  
  sendAllSprites(#displayLoaderText, me.preloadList.getPropAt(1))
  me.netID = preloadNetThing(me.preloadList.getAt(1))
  
  add(the actorList, me)
  
end

The startPreloading() handler accepts a property list defining which files to preload. The list is of the format ["Some descriptive string": "http://www.domain.com/filename"]. This allows for the possibility of displaying the name or description of the file currently being downloaded. All this requires is a text sprite with a simple behavior to handle a #displayLoaderText message.

This particular handler is also built to deal with preloading many files in Shockwave. The accepted safe maximum for the number of simultaneous network actions is four. Using the getStreamStatus information, one could determine the total number of bytes to be downloaded if the number of files being retrieved is four or less. If more than that is required however, the numbers will change as soon as one of the first-round operations completes and another is begun. This would radically change the targets for the progress bar, and would even cause the displayed percent complete to drop each time an additional preload operation started.

Solving this problem is accomplished here by declaring each file to be worth an even "chunk" of the overall download size. If you preload four files, each file will be worth 25% of the complete progress bar, regardless of each file's size in relation to the overall download size. This works reasonably well, but from a experience standpoint can be irritating if the small files are loaded first and the larger files are last. This creates the perception that the download is gradually going slower and slower. If the preload is arranged in order of largest to smallest files, the perception will be that the download is gaining speed as it goes along, and will be much less frustrating.

on stepFrame me
  
  if netDone(me.netID) then
    
    me.preloadList.deleteAt(1)
    if me.preloadList.count = 0 then
      deleteOne(the actorList, me)
      me.mySprite.rect = me.origRect
      sendAllSprites(#displayLoaderText, "Ready to play")
      exit
    else
      sendAllSprites(#displayLoaderText, me.preloadList.getPropAt(1))
      me.netID = preloadNetThing(me.preloadList.getAt(1))
    end if
  end if
  
  tByteCount = 0
  tByteTotal = 0
  
  tByteCount = getStreamStatus(me.netID).bytesSoFar
  tByteTotal = getStreamStatus(me.netID).bytesTotal
  
  if tByteTotal > 0 then
    tPercentage = tByteCount / float(tByteTotal)
    tWidth = me.origWidth * (me.percentChunk * (me.startingCount - me.preloadList.count) + (tPercentage * me.percentChunk))
    me.mySprite.rect = rect(me.origRect[1], me.origRect[2], me.origRect[1] + tWidth, me.origRect[4])
  end if
  
end

The stepFrame() handler checks the status of the file currently being preloaded. If the preload is done, that file is removed from the list and the next preload operation begins. This continues until the list is exhausted. The bytes received and total bytes for the current file are also checked, and some math is done to create the overall percentage number for the progress bar. For instance, if four files are to be preloaded and the third is currently in progress, the overall percentage will be 25% + 25% + the percentage received for the third file.

Again, the ideal would be for the preload operations to happen in parallel, and all the byte information for each file to be immediately available. This would enable a true progress indication. The method used here does provide good feedback however, and makes for an informative experience, which is really all that is needed to allow for using downloadable Xtras in Shockwave.

Here is my best personal example to illustrate why downloadable Xtras can be so truly useful. I recently programmed a piece with a one-minute background audio loop, and ten varying sound events.

Each of these sounds played back at 16/44 stereo. Excluding the Beatnik Xtra, all files came to a total of ~200K (the audio was only 40K by the way), including the loader movie to preload Beatnik. And once the user has Beatnik, they can be flooded by all sorts of complex sound and music with extremely minimal downloads.

The project has been up for a few months now, and like always we have received comments on ways to improve UI, etc. from the thousands of people that have visited. But among the various feedback we've received, no one has commented negatively on the download time. Despite the common misperception, downloading Xtras is a viable opportunity in Shockwave development.

Having left his day job and striking out on his own, Doug is now the man behind the name 'Finite Monkey'. He's worked on numerous Director CD and Shockwave titles, and currently finds himself specializing in multiuser environments and games. Check out http://www.finitemonkey.com or mail at dougb@finitemonkey.com

Copyright 1997-2024, Director Online. Article content copyright by respective authors.