Angel \”Java\” Lopez on Blog

July 29, 2011

Social Online Games Programming (Part 3) Tankster, Blob Storage and JSONP

Filed under: .NET, AJAX, ASP.NET MVC, Azure, Game Development, HTML5, JavaScript, JQuery — ajlopez @ 10:59 am

Previous Post
Next Post

In my previous post I wrote about the Windows Azure Social Gaming Toolkit, and its example multi-player online game Tankster. See:

http://watgames.codeplex.com/
http://www.tankster.net/

There are two interesting posts by @ntotten about the inner guts of the game:

Architecture of Tankster – Introduction to Game Play (Part 1)
Architecture of Tankster– Scale (Part 2)

It’s worth to mention Nathan’s text here:

Before we begin with an explanation of the implementation, it is important to know what our goals where for this game. We had three primary goals when building this game.

  1. The game must scale to handle several hundred thousand concurrent users.*
  2. The architecture must be cost effective.
  3. The architecture must be flexible enough for different types of games.

* This is the goal, but there are still some known limitations in the current version that would prevent this. I will be writing more about that later.

Now, I want to write about the use and implementation of blob storage in Tankster.

Why to use blob storage? If you play Tankster in practice mode, the Javascript client doesn’t use the Azure backend. Javascript can access web role and blob storage via Ajax/JSON calls. But in multi-player game (there is one kind of game, named Skirmish), each player client code polls the blob storage to get the game status (tank shots, chat messages, other status). But again, why blob storage? There are money reasons (cost of each access to Web Role service API vs. cost of read a blob), but I don’t know about Azure prices (you know, MVPs don’t touch the money ;-). But there is another reason: to spread the workload, given some air to web role instances.

There is an AzureBlobContainer class in Tankster.Common library project:

public class AzureBlobContainer<T> : IAzureBlobContainer<T>
{
    private readonly CloudBlobContainer container;
    private readonly bool jsonpSupport;
    private static JavaScriptSerializer serializer;
    public AzureBlobContainer(CloudStorageAccount account)
        : this(account, typeof(T).Name.ToLowerInvariant(), false)
    {
    }
    public AzureBlobContainer(CloudStorageAccount account, bool jsonpSupport)
        : this(account, typeof(T).Name.ToLowerInvariant(), false)
    {
    }
    public AzureBlobContainer(CloudStorageAccount account, string containerName)
        : this(account, containerName.ToLowerInvariant(), false)
    {
    }
	//....

 

The class use generics. Type T could be a Game, GameQueue or another .NET type. You can reuse this class in other projects: it’s “game agnostic” code. The many constructors add flexibility for testing purpose.

This is the code to save a typed object to a blob:

public void Save(string objId, T obj)
{
    CloudBlob blob = this.container.GetBlobReference(objId);
    blob.Properties.ContentType = "application/json";
    var serialized = string.Empty;
    serialized = serializer.Serialize(obj);
    if (this.jsonpSupport)
    {
		serialized = this.container.Name + "Callback(" + serialized + ")";
    }
    blob.UploadText(serialized);
}

The object (type T) is serialized to JSON. AND not only JSON: note that a there is a Callback (you could remove this part if you don’t need this feature in your project). Then, a game object is saved as (I stolen …errr… borrowed 😉 this code from Nathan’s post):

gamesCallback(
    {"Id":"620f6257-83e6-4fdc-99e3-3109718934a6"
    ,"CreationTime":"\/Date(1311617527935)\/"
    ,"Seed":1157059416
    ,"Status":0
    ,"Users":[
        {"UserId":"MxAb1iZtey732BGsWsoMcwx3JbklW1xSnsxJX9+KanI="
        ,"UserName":"MxAb1iZtey732BGsWsoMcwx3JbklW1xSnsxJX9+KanI="
        ,"Weapons":[]
        },
        {"UserId":"ZXjeyzvw7WTdP8/Uio4P6cDZ8jmKvCXCDp7JjWolAOY="
        ,"UserName":"ZXjeyzvw7WTdP8/Uio4P6cDZ8jmKvCXCDp7JjWolAOY="
        ,"Weapons":[]
        }]
    ,"ActiveUser":"MxAb1iZtey732BGsWsoMcwx3JbklW1xSnsxJX9+KanI="
    ,"GameRules":[]
    ,"GameActions":[]
    })

Why the callback? To support JSONP:

http://en.wikipedia.org/wiki/JSONP

JSONP or “JSON with padding” is a complement to the base JSON data format, a pattern of usage that allows a page to request data from a server in a different domain. As a solution to this problem, JSONP is an alternative to a more recent method called Cross-Origin Resource Sharing.

Under the same origin policy, a web page served from server1.example.com cannot normally connect to or communicate with a server other than server1.example.com. An exception is the HTML <script> element. Taking advantage of the open policy for <script> elements, some pages use them to retrieve Javascript code that operates on dynamically-generated JSON-formatted data from other origins. This usage pattern is known as JSONP. Requests for JSONP retrieve not JSON, but arbitrary JavaScript code. They are evaluated by the JavaScript interpreter, not parsed by a JSON parser.

If you are a newbie to JSON and JSONP, this is a short tutorial/example using JQuery (the same library used by Tankster client code):

Cross-domain communications with JSONP, Part 1: Combine JSONP and jQuery to quickly build powerful mashup

But (you know, there is a “but” in every software project 😉 Azure blob storage doesn’t support the JSONP URL (that has a randomly generated callback id):

Query JSON data from Azure Blob Storage with jQuery

There is a proposed solution in that Stack Overflow thread. Agent Maxwell Smart would say: ah! the “old trick” of having the callback in the blob!

dataCallback({"Name":"Valeriano","Surname":"Tortola"})

You can read a more detailed description of problem/solution with example code at @woloski’s post (good practice Matthew! write a post!):

Ajax, Cross Domain, jQuery, WCF Web API or MVC, Windows Azure

One problem to point: note that the callback name is “hardcoded” in blob storage. The gamesCallback present in game status blob should be the name of a global function. But you can change the blob text to whatever valid Javascript code.

And the client code? You can study the gskinner code at Tankster.GamePlay web project, under src\ui\net\ServerDelegate.js:

(function (window) {
    goog.provide('net.ServerDelegate');
    goog.require('net.ServerRequest');

    var ServerDelegate = function () {
        throw new Error('ServerDelegate cannot be instantiated.');
    };

    var p = ServerDelegate;

    p.BASE_API_URL = "/";
    p.BASE_BLOB_URL = "http://tankster.blob.core.windows.net/";
    p.BASE_ASSETS_URL = "";
    p.load = function (type, data, loadNow) {
        var req;
        if (p.CLIENT_URL == null) {
            p.CLIENT_URL = window.location.toString();
        }
//....

There is an interesting switch:

switch (type) {
    //Local / config calls
    case 'strings':
        req = new ServerRequest('locale/en_US/strings.js',
		   null, 'jsonp', null, 'stringsCallback'); break;
    //Game calls
    case 'endTurn':
        req = new ServerRequest(apiURL+'Game/EndTurn/',
		    null, 'xml'); break;
    case 'leaveGame':
        req = new ServerRequest(apiURL+'Game/Leave/'+data.id,
		    {reason:data.reason}, 'xml', ServerRequest.POST); break;
    case 'playerDead':
        req = new ServerRequest(apiURL+'Game/PlayerDead/',
		    null, 'json'); break;
    case 'gameCreate':
        req = new ServerRequest(apiURL+'Game/Queue', data,
		    'xml', ServerRequest.POST); break;
    case 'usersGame':
        req = new ServerRequest(blobURL+'sessions/'+data,
		    null, 'jsonp', null, 'sessionsCallback'); break;
    case 'gameStatus':
        req = new ServerRequest(blobURL+'games/'+data,
		    null, 'jsonp', null, 'gamesCallback'); break;
    case 'gameQueueStatus':
        req = new ServerRequest(blobURL+'gamesqueues/'+data,
		    null, 'jsonp', null, 'gamesqueuesCallback'); break;
    case 'notifications':
        req = new ServerRequest(blobURL+'notifications/'+data,
		    null, 'jsonp'); break;

    //User calls
    case 'verifyUser':
//...

See the ‘gameStatus’ polling: it uses ‘jsonp’ as format. My guess: the ‘gamesCallback’ parameter is not needed: you can use any other name, the function to call resides in the blob content.

I think there are alternatives to game status. The blob reflects the Game entity (see Tankster.Core\Entities\Game.cs). But it could be implemented in two blobs by game:

– One, having the initial status (players, positions,etc…) and the list of ALL the history of the game (think about to implement a chess or go game, you need to save the history).

– Another one, having the “news” (last 10 seconds of game actions). So, the data to poll should be shorter.

The price to pay: web role service should update both. But that update only occurs when a player sends a move (shot, chat…). The poll of game status occurs in every client, triggered by a repeated timeout. Actually, the game blob keeps the last 10 seconds actions AND initial status, weapons, etc…. Each client polls that info. In case a client disconnects and reconnects, it could poll the “complete game” blob to be in sync again.

The separation of that info in two blobs should improve the scalability of the solution. But you know: premature optimization is the root of all evil ;-). If you take that way of store and retrieve games, you should run some stress or/and load tests to have a really measure of such decision impact.

More Tankster code analysis, patterns, and social game dev in general: coming soon.

Some links:

WAT is to Social Gaming, as Windows Azure is to… | Coding4Fun Blog | Channel 9

Thanks! They mention my post 😉

Episode 52 – Tankster and the Windows Azure Toolkit for Social Games | Cloud Cover | Channel 9

Microsoft tailors Azure cloud services to social game developers | VentureBeat

Windows Azure Toolkit for Social Games Released to CodePlex – ‘Tankster’ Social Game Built for Windows Azure

Tankster, a Social Game Built for Windows Azure | Social Gaming on Windows Azure | Channel 9

Social Gaming on Windows Azure | Channel 9

Build Your next Game with the Windows Azure Toolkit for Social Games

Microsoft delivers early build of Windows Azure toolkit for social-game developers | ZDNet

http://www.delicious.com/ajlopez/tankster

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

July 21, 2011

Social Online Games Programming (Part 2) Tankster and Windows Azure Toolkit For Social Games

Previous post
Next post

Yesterday, July 20th, Microsoft released a preview version of Windows Azure Toolkit for Social Games, and published a beta version (with code) of a first demo game.

You can download the code from Codeplex: http://watgames.codeplex.com/

You can play the game at: http://www.tankster.net/

The current solution main projects:

Tankster.GamePlay is a Web Role. The only worker role is Tankster.WorkerRole. Tankster.Core is a class library. There are interesting code at Tankster.Common: Azure utilities to access repositories, a job engine; all its code is game-agnostic.

These are my first short comments about the code and implemented features (remember, is a beta! Some of these features/implementations could change in the next release):

– Client technology: HTML5, Javascript, EaselJs (for canvas programming).
– Server technology: ASP.NET MVC 3, some Razor test views (interesting topic: how to test the game without the REAL game), WCF Web API (another interesting topic to discuss: alternative technologies to received the game activity)
– There is a client game model and entities in Javascript. See src/model, src/game.

– There is a server game model (see Tankster.Core class library project)

– You can play in single player mode, but you can choose multi-player online. Then, the game uses ACS Portal to login using Federated Authentication:

– The client code resides in a single page: index.html (with lot of referenced javascript files)
– Client code sends JSON data (commands) to WCF Web API endpoints, using Ajax/JQuery. There are services published, exposing a REST-like interface

routes.MapServiceRoute<GameService>("game");
routes.MapServiceRoute<AuthService>("auth");
routes.MapServiceRoute<UserService>("user");
routes.MapServiceRoute<TestService>("test");

– Most of the game activity is send to game/command service. The service updates the game status residing in a blob at Azure Storage. Code excerpt:

// Add gameAction
var gameAction = new GameAction
{
    Id = Guid.NewGuid(),
    Type = commandType,
    CommandData = commandData,
    UserId = this.CurrentUserId,
    Timestamp = DateTime.UtcNow
};
// Cleanup game actions lists
for (int i = 0; i < game.GameActions.Count(); i++)
{
    if (game.GameActions[i].Timestamp < DateTime.UtcNow.AddSeconds(-10))
    {
        game.GameActions.RemoveAt(i);
        i--;
    }
}
game.GameActions.Add(gameAction);
this.gameRepository.AddOrUpdateGame(game);

– The game status is polled by javascript clients from blob storage. In this way, the ASP.NET MVC web role has less workload.

– The blob resides in the same domain, so no cross-domain JSON call is needed. But the game is prepared to use cross-domain Ajax call, replacing the XmlHttpRequest object by a Flash component.

– The Skirmish game mode (five players in a game) is made queuing the new players in a Game Queue, managed at worker role.

– The Statistics are processed at worker role: some game actions are sent to Azure queue, so the statistics process doesn’t disturb the client game.

– User status, Game status, Skirmish Game Queue status are blobs.

– Statistics data uses SQL Azure.

– There only worker role use a Job Engine to process many tasks, example:

// Game Queue for Skirmish game
Task.TriggeredBy(Message.OfType<SkirmishGameQueueMessage>())
    .SetupContext((message, context) =>
    {
         context.Add("userId", message.UserId);
    })
    .Do(
        new SkirmishGameQueueCommand(userRepository,
            gameRepository, workerContext))
    .OnError(logException)
    .Start();

There are a lot of points to comment and discuss, feed for upcoming posts. Surely, the solution will evolve and new versions will be published (this week? next week?). But it is interesting to have a published game online AND the code to analyzes it.

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

June 17, 2007

Learning AJAX

Filed under: .NET, AJAX, ASP.NET, JavaScript, PHP — ajlopez @ 12:09 pm

A month ago, I gave an speech about AJAX, at Club de Programadores, here, in Buenos Aires, Argentina. I published the examples, presentation (in spanish) and resources that I used to prepare the speech. I hope that they will be useful as an introduction to AJAX:

Source: Adaptive Software

The initial post written by Jesse James Garret, from Adaptive creating the term AJAX, and explainint it:

Ajax: A New Approach to Web Applications

More about Garret at:

http://www.jjg.net
http://www.jjg.net/elements/ (his book about The Elements of User Experience)

Sites about AJAX

http://ajaxian.com/
http://www.ajaxlines.com
http://www.ajaxtutorial.net/
http://www.ajaxprojects.com/
http://www.ajaxresources.com/
http://blog.joshuaeichorn.com/ajax-resources/
http://ajax.solutoire.com/

http://www.deitel.com/ajax/AJAX_resourcecenter.html
http://www.oracle.com/technology/tech/java/ajax.html
http://developers.sun.com/ajax/

Technologies related to AJAX

JSON
http://www.json.org/
Standard ECMA JavaScript
http://www.ecma-international.org/publications/files/ecma-st/ECMA-262.pdf
The XMLHttpRequest Object
http://www.w3.org/TR/XMLHttpRequest/
http://www.fiftyfoureleven.com/resources/programming/xmlhttprequest/
http://www.fiftyfoureleven.com/resources/programming/xmlhttprequest/examples

JavaScript Libraries

Prototype
http://www.prototypejs.org/
http://www.sergiopereira.com/articles/prototype.js.html
http://www.prototypejs.org/learn/introduction-to-ajax

Scriptaculous
http://script.aculo.us/
http://swik.net/scriptacolous
http://24ways.org/2005/introduction-to-scriptaculous-effects
http://24ways.org/examples/introduction-to-scriptaculous-effects/
http://demo.script.aculo.us/shop
http://wiki.script.aculo.us/scriptaculous/show/Ajax.Autocompleter

OpenRico
http://www.openrico.org/

AdobeSpry
http://labs.adobe.com/technologies/spry/

Yahoo User Interface Library
http://developer.yahoo.com/yui/
http://developer.yahoo.com/yui/download/
http://yuiblog.com/

PHP Libraries

Sajax
http://www.modernmethod.com/sajax/
http://blog.joshuaeichorn.com/archives/2005/04/19/ajax-hello-world-with-sajax/

Xajax
http://www.xajaxproject.org/
http://wiki.xajaxproject.org/Tutorials:Learn_xajax_in_10_Minutes
http://wiki.xajaxproject.org/Tutorials:Processing_Forms_with_xajax
http://www.xajaxproject.org/examples/thewall/thewall.php
http://www.cyberdyne.org/~icebrkr/2007/05/03/xajax-php-live-datagrid-gridview/
http://www.cyberdyne.org/~icebrkr/files/xajax-Livedatagrid.tar.gz
Ejemplo en
http://dev.chkbox.com/gridview.php

Pajax
http://www.auberger.com/pajax/

Java Libraries

Google Web Toolkit
http://code.google.com/webtoolkit/
http://code.google.com/webtoolkit/gettingstarted.html
http://google-web-toolkit.googlecode.com/files/gwt-windows-1.3.3.zip
http://code.google.com/webtoolkit/documentation/examples/
AjaxTags
http://ajaxtags.sourceforge.net/

AjaxTags – AjaxTags Usage
http://ajaxtags.sourceforge.net/usage.html
AjaxTags – AjaxTags Quick Start
http://ajaxtags.sourceforge.net/quickstart.html

ExtJs
http://extjs.com/deploy/ext/examples/grid/xml-grid.html

Dynamic Faces
http://java.sun.com/developer/technicalArticles/J2EE/ajax_jsf/

BackBase
http://www.backbase.com

.NET Libraries

ASP.NET Ajax (Microsoft version for Net 2.x)
http://ajax.asp.net/

Ajax.NET
http://ajax.schwarz-interactive.de/CSharpSample/
MagicAjax
http://www.magicajax.net/

During the speech, I search some chat implementations using Ajax:

http://socket7.net/lace/
http://www.ajaxprojects.com/ajax/tutorialdetails.php?itemid=9
http://www.ajaxchat.org/
http://www.plasticshore.com/projects/chat/index.html
http://www.phpfreechat.net/
http://www.dynamicajax.com/fr/AJAX_Driven_Web_Chat-271_290_291.html

I visited some websites with AJAX:

http://www.egosurft.org
http://www.humanized.com/reader/

My del.icio.us links about AJAX:

http://del.icio.us/ajlopez/ajax

I read the excelent book from Francisco Minera, MP Ediciones:

http://www.redusers.com/noticias/lpcu109

An alternative, the new Microsoft baby, Silverlight:

http://silverlight.net/
http://tirania.org/blog/archive/2007/May-01.html
http://www.hanselman.com/blog/PuttingMixSilverlightTheCoreCLRAndTheDLRIntoContext.aspx
http://download.microsoft.com/download/f/2/e/f2ecc2ad-c498-4538-8a2c-15eb157c00a7/SL_Map_FinalNET.png
http://blogs.msdn.com/tims/archive/2007/04/30/silverlight-screencasts.aspx
Moonlight – Mono
http://del.icio.us/ajlopez/silverlight

Examples from the speech, presentation, at

http://www.ajlopez.net/ReferenciaVe.php?Id=191

Angel “Java” Lopez
http://www.ajlopez.com/

Create a free website or blog at WordPress.com.