Hardware: none How TweetCraft works
Let’s quickly walk through the different things that TweetCraft does to bring Twitter into World of Warcraft.
Overview
World of Warcraft’s user interface is highly customizable and enables add-on developers to do almost anything in the game they can dream of. Add-ons can interact with the world, listen to events that happen in the game, alter the look of the default user interface or create brand new ones, but add-ons are seriously limited when it comes to talking to the world outside World of Warcraft. They cannot read or write files, call web services or do anything that could be potentially harmful. This is why TweetCraft comes with a Windows application that sits in the Notification Area (also known as the tray) and does the bulk of the work, giving the TweetCraft add-on only the data that it needs to display, such as tweets, replies and user pictures. All the Twitter web service calls, uploading of screenshots and housekeeping is done by this application. Let’s see how!
The TweetCraft Tray application
The TweetCraft Tray application is a WPF application that periodically checks for new tweets, dowloads and converts the user pictures of the tweets’ authors and writes it out to a file that World of Warcraft picks up and the add-on can use. It also picks up all outgoing tweets queued up for sending and sends them using Twitter one-by-one. It watches for screenshots taken by World of Warcraft and uploads them using TwitPic immediately.
To do all this, it has a couple of settings that need to be configured before it can work. For starters, it needs your Twitter credentials to be able to send tweets and post pictures on your behalf. It also needs to know which World of Warcraft account you are going to use to play and send and receive tweets with. Finally, you can opt out of automatically uploading screenshots you take during game. Figure 1 shows the TweetCraft Settings window that shows up when you first start TweetCraft after installation and is also available by right clicking the tray icon (Figure 2).
Figure 1. TweetCraft Settings Window
Figure 2. TweetCraft tray icon in the notification area
Getting data from Twitter
TweetCraft uses an open-source library called TwitterLib to send and receive tweets using Twitter’s API. TwitterLib is part of the open-source WPF Twitter Client WittyTwitter and wraps the web services provided by Twitter into an easy to use .NET class library. TweetCraft wraps this library into a simple class called TwitterClient that all the services in TweetCraft rely on. One of those services is the TwitterBackgroundService which polls Twitter periodically to check for new tweets. By default, this is set to five minutes. If new tweets or replies are available, an event is raised that other components of TweetCraft can handle and work with the new tweets, download user pictures, etc. Figure 3 shows the three classes that take part in downloading new tweets and replies and notifying other classes.
Figure 3. TwitterBackgroundService, TwitterClient and TwitterNet (TwitterLib)
Dynamically building TGA images
When it comes to visualizing images (or textures, in WoW parlance), World of Warcraft poses quite a few restrictions on what files can be used and where does files should be. First of all, World of Warcraft only supports the TGA and BLP file formats. TGA stands for the Truevision Targa format, whereas BLP is Blizzard’s own image format. The images must also have dimensions of two (32×32, 64×64 pixels and so on…), otherwise they won’t show up. On the other hand, Twitter user pictures are available as 48×48 or 75×75 pixels and in various well-known formats, such as JPG, PNG or even GIF. TweetCraft needs to convert these pictures to 64×64 TGA files if it wants to play nice with World of Warcraft. This is done for each tweet’s authors user picture that will show up in World of Warcraft. The converted pictures must be placed in the Interface folder of World of Warcraft where the add-ons themselves also reside. The TwitterUserPictureService can retrieve the user picture and convert it to a 64×64 TGA file that contains the 48×48 user picture in the middle and puts that file into the same directory where the TweetCraft add-on is installed. The files are named after each user’s screen name and if TwitterUserPictureService sees that a file is already there, it won’t convert it again, saving some time and computing power.
Figure 4 shows TwitterUserPictureService and two helper classes that take care of downloading and the actual conversion. The GetUserPicturePath method returns the path of the resulting World of Warcraft compatible TGA file for a single user.
Figure 4. TwitterUserPictureService and its helper classes
Serializing tweets into Lua
Until now, we were quite secretive about how we can avoid World of Warcraft’s restrictions and let TweetCraft be able to read the data and show it. We’ve said that add-ons cannot read or write files and that still hasn’t changed during the last few minutes, but add-ons must have a way somehow to save their settings and other information when I log out of the game and load that when I log back in, you sincerely ask and you’re right! Although add-ons cannot read or write to files, they can ask World of Warcraft to save and load some of their global variables whenever the user reloads the UI (by entering an instance or hearthing), logs in or logs out. These files are called the SavedVariables files. When TweetCraft finishes downloading tweets, converting user pictures and everything else, it saves them using the very same format and to the very same file World of Warcraft uses on behalf of the TweetCraft add-on. Neat, huh? Just wait a little bit more… :)
Those variables that an add-on asks to be saved between sessions are saved into a Lua file, which is the same programming language add-on developers can use to write their add-ons. So basically, World of Warcraft creates a file that contains code full of assignment statements (think a = 5) that it will just run whenever those values need to be set again. More complex data structures can also be expressed this way using Lua tables, the swiss army-knife of Lua.
It sounds like a great idea to put all the data we would like for TweetCraft to use, but all we have is .NET objects, arrays and dictionaries. Fortunately, all these data structures can be expressed with simple Lua types and tables and TweetCraft comes with a class called LuaSerializer that produces Lua code from any .NET object (with a few restrictions, of course), very similar to how XmlSerializer works.
To make this even more simple, TweetCraft contains the concept of a SavedVariablesChannel that you can just drop objects in, flush it and those object show up on the other side. In our case, as Lua variables. What’s even better, it works the other way around as well. The TweetCraft add-on stores all the tweets queued up and ready to be sent in a variable and triggers World of Warcraft to save them to the SavedVariables file. The SavedVariablesChannel detects this by watching for changes made to the SavedVariables file using FileSystemWatcher and notifies other components of the TweetCraft application that can pull out the information and send the tweets.
Figure 5 shows SavedVariablesChannel and its base class, ValueChannelBase which keeps track of all objects thrown into it until it is flushed.
Figure 5. SavedVariablesChannel and ValueChannelBase
Refreshing the data in World of Warcraft
There’s one last problem we face when trying to achieve this two-way communication between the TweetCraft add-on and the application. If World of Warcraft is running, we cannot just overwrite the SavedVariables file and expect World of Warcraft to pick it up as it does not watch for changes made to the file. If we were to overwrite the file and subsequently the user logs out, World of Warcraft will happily overwrite the information we placed there. There’s another trick we have to resort to: the TweetCraft add-on can trigger the reloading of the UI which will unload all add-ons, save their variables and then load them again. There’s a a little bit of time between the saving and loading of a particular add-ons SavedVariables file and that’s when TweetCraft can safely read the file for queued up tweets and overwrite it with the new data. This is what happens when the user clicks the Refresh button in TweetCraft’s frame.
Sending tweets and uploading screenshots
Whenever the user queues up tweets for sending, they are not immediately sent but kept in a data structure that will be saved out to the SavedVariables file by World of Warcraft. We’ve seen that his happens when either the user logs out or presses the Refresh button. The updated SavedVariables file gets detected by SavedVariablesChannel and the ChannelUpdated event is raised. When the TweetCraft application handles this event, it cannot immediately send the tweets as that would take a couple seconds and if you remember from the last section, we only have a tiny little window of time to process the values and save back all the data we would like to send back. For this reason, the tweets that are picked up from the SavedVariables file using the SavedVariablesChannel get quickly queued up in the TwitterDispatcherService that then goes ahead and starts sending them one by one in the background. To make sure that all the values we prepared to save into the file get flushed, the SavedVariablesChannel has a property called AutoFlush that is enabled by default.
One thing we have not mentioned is that TwitterDispatcherService can also upload and post pictures using TwitPic. It watches the Screenshots folder of World of Warcraft for new files and if AutoTweeting of screenshots is enabled, immediately queues up the picture for uploading and posting it. This also means that you don’t need to press the Refresh button or wait until you log off for screenshots to be posted. They will show up immediately in your Twitter feed.
The TwitterDispatcherService uses TwitterClient (and TwitterLib) to send the tweets but it does not interfere with the quick reading and writing of the SavedVariables file we discussed previously. It also uses TwitPicClient to upload and post pictures. Figure 6 shows TwitterDispatcherService, TwitterClient and TwitPicClient.
Figure 6. TwitterDispatcherService, TwitterClient and TwitPicClient
Bringing it all together
So far, we’ve looked at components of TweetCraft that implemented a particular part of the application. Retrieving and sending tweets, converting user pictures and making all this information available for the TweetCraft add-on, but there’s an important class that brings all this together and contains all the logic of how these components interact with each other. We also need to be able to detect World of Warcraft installations, figure out what accounts are available and where to look for files like the SavedVariables files and put the converted user pictures. The TweetCraft class implements the logic required and relies on the WorldOfWarcraft class for everything World of Warcraft related.
Figure 7 shows the TweetCraft and WorldOfWarcraft side by side.
Figure 7. TweetCraft and WorldOfWarcraft
Summary
While this is a high-level overview of TweetCraft only, it gives you a good idea of how it enables World of Warcraft players to use Twitter to send and receive tweets, upload the screenshots and share their achievements right inside the game. Make sure you try out TweetCraft if you have World of Warcraft installed and if you’re curious, download the source code and take a deeper look.
Gabor Ratky (Blog, Twitter), Senior Software Engineer and Coding4Fun Ninja at EPAM Systems
Gabor is the developer behind TweetCraft and has been working on Coding4Fun projects for almost two years. He also leads the development of AddOn Studio for World of Warcraft, a Visual Studio-based IDE for building World of Warcraft add-ons and he co-authored the chapter in the Coding4Fun book about it. He is a VSX Insider and was invited to speak at various events about Visual Studio Extensibility. When not working on Coding4Fun projects, Gabor works on large scale, enterprise solutions using exciting Microsoft technologies. He lives in Budapest, Hungary and loves traveling, good wine and Channel9 videos.