Friday, May 27, 2011

Builtin Base64 Streaming

Months ago I’ve blogged on how to implement base64 streaming reader and writer. Just for the record – the same can be achieved using built-in classes:

class Program
{
    static void Main( string[] args )
    {
        string Original = "foo bar, this is an example";
        byte[] ToBase64;
        string Decoded;
 
        using ( MemoryStream ms = new MemoryStream() )
        using ( CryptoStream cs = new CryptoStream( ms, new ToBase64Transform(),
                                                        CryptoStreamMode.Write ) )
        using ( StreamWriter st = new StreamWriter( cs ) )
        {
            st.Write( Original );
            st.Flush();
 
            ToBase64 = ms.ToArray();
        }
 
        using ( MemoryStream ms = new MemoryStream( ToBase64 ) )
        using ( CryptoStream cs = new CryptoStream( ms, new FromBase64Transform(), 
                                                        CryptoStreamMode.Read ) )
        using ( StreamReader sr = new StreamReader( cs ) )
            Decoded = sr.ReadToEnd();
 
        Console.WriteLine( Original );
        Console.WriteLine( Encoding.Default.GetString( ToBase64 ) );
        Console.WriteLine( Decoded );
 
        Console.ReadLine();
    }
}

The output of above snippet is:

foo bar, this is an example
Zm9vIGJhciwgdGhpcyBpcyBhbiBleGFtcGxl
foo bar, this is an example

WIF, WS-Federation and Single sign-out for RP – R-STS – IP-STS scenario

There seems to be no strict specification on how Single sign-out should be implemented for WS-Federation. Not so long ago I’ve blogged about a simple scenario involving an IP-STS and a group of RPs.

A simple scenario

In such simple scenario, when the IP-STS receives a wsignout1.0 request from one of RPs (which is basically a request to sign out the whole party from current session), it returns a page to the browser which contains a list of images pointing back to all RPs that have signed using the IP-STS. Each single url to the image is of the form:

<img src="http://the.relyingparty.com/default.aspx?wa=wsignoutcleanup1.0" />

Thus, it’s not the IP-STS who signs out everyone but rather it’s the responsibility of the browser to tell everyone to log off.

Imagine that the browser is an office-boy who passes messages between the boss (IP-STS) and his workers (RPs). When one of workers says “I want everyone to log off”, the boy delivers the request to the boss and in return the boss gives a list of workers to the boy saying “go, tell everyone from this list to log off”.

What works like a charm in a simple scenario, seems to be problematic in a more complicated one.

A complicated hierarchy

Suppose that this time there are not only RPs and the IP-STS but also R-STSes in the middle (Relaying Security Token Services which pass sign in requests upwards). Each of such R-STSes acts just like a lower-level manager who’s now collecting requests from his workers and passes them to the boss.

Note that such hierarchy can be arbitrarily complicated, with a single IP-STS at the top, possibly multiple layers of R-STSes in the middle and RPs at the bottom.

Suppose now that, as previously, the office-boy (one of RPs) asks his manager (one of R-STSes) to log-off. This time however the manager would be torn between two conflicting needs:

  • he has to inform all his workers (RPs that are directly under him) to sign off (by sending links with wa=wsignoutcleanup1.0)
  • he has to ask his boss (the IP-STS) to log off everyone (all other possible R-STSes)

The office-boy (the browser) can unfortunately perform only one of above requests at a time. Either the R-STS will return images to log off all his child RPs or it will push the log-off request to the IP-STS.

The former is a bad choice – as the log off request should not be restricted to a subtree of such complicated hierarchy. The latter however raises a new issue – yes, the log-off request can be pushed to the IP-STS but if the IP-STS returns a list of images to log off is direct descendants (R-STSes), it will log off only R-STSes! None of RPs will log off, as the IP-STS has no idea of what happens two levels above him!

And just for the record: the difference in handling a sign-out request between an IP-STS and a R-STS is presented below:

...
else if ( action == WSFederationConstants.Actions.SignOut )
{
    // Process signout request.
    SignOutRequestMessage requestMessage = 
        (SignOutRequestMessage)WSFederationMessage.CreateFromUri( Request.Url );
 
    // IP-STS: answer to the signout request
    FederatedPassiveSecurityTokenServiceOperations.ProcessSignOutRequest( 
        requestMessage, 
        User, 
        requestMessage.Reply, 
        Response );
    
    // R-STS: push signout request upwards
    WSFederationAuthenticationModule.FederatedSignOut( 
        null, 
        new Uri( requestMessage.Reply ) );
}
Frames to the rescue

A solution to this issue can be easily inferred from the way ADFS 2.0 handles sign-out requests.

It seems that instead of returning a list of images containing signout requests to his direct descendants, a STS should return a list of invisible iframes of a form:

<iframe src="the.relyingparty.com/default.aspx?wa=wsignoutcleanup1.0" class="MakeItInvisible" />

This way, the browser deilvering such request to each of R-STSes expects a web page in a return.

But, in contrast “imaging approach”, a web page can contain further references which will make the browser go after them.

Each of R-STSes should then return a page containing a list of iframes containing links to log off his descendants and so on.

Note, that the structure of dependency tree in such approach can be arbitrarily complicated as each parent node returns iframes pointing to its descendants.

The only drawback of such approach is that if you’d like to have some visual feedback from consecutive STSes then you have to implement it on your own (embed some images inside returned iframes).

Saturday, May 21, 2011

Implementing a HeartLight clone in XNA, continued (3)

Download Torq314Dash 0.2 (binary and source)

My implementation of the HeartLight clone improves. Profile of the new version

  • implemented LEVELS.HL file reader which makes it possible to play all 70 levels from the original implementation (the file is included in the distribution, all credits go to Janusz Pelc, Maciej Miąsik and others from the team who brought HeartLight to life
  • implemented balloons and tunnels
  • bomb timing is slightly improved
  • new texture set

Most of 70 levels are playable now, with 13, 21 or 37 as exceptions which reveal further issues in timing (bombs/balloons).

Ballons were easy to implement. They fall down when two movable blocks are above them and an empty square below. They move up when none or a single movable block is above them and an empty square yet above.

Tunnels were tricky. In fact, I’ve implemented them in such way that the player block is marked to be processed by the physics engine and then it moves along the tunnel, eating a block ahead and leaving a new block behind. During the tunnel travel, the player block returns a different texture so that the effect of moving along the tunnel is clearly visible.

Feel free to comment. Please also take a look at the implementation of a BoulderDash clone by Fingus. It’s been a mutual challenge between us to first implement a tetris clone and then a BoulderDash clone. A possible next challenge would be a Super Mario clone.

Sunday, May 15, 2011

Implementing a HeartLight clone in XNA, continued (2)

One if the issues with my implementation I’ve been trying to resolve is the way HeartLight implements falling blocks. There are at least few levels to test this, my favourite is the level 20 which starts with several stones and hearts falling from the top to the bottom. The way they fall and interact during falling determines the way the board looks like when all the blocks finally fall and do not move anymore (and this is when player can start the level).

The level in HeartLight, after blocks finally fall down looks like this:

If you try this level in my original implementation you’ll however end up with following:

 

Most blocks completely miss their destination and although the physics I’ve implemented feels ok, it surely gives different output.

Unfortunately, I do not have the source code of HeartLight. The only way to “debug” the implementation was then to slow down both versions (mine and the original) and stone-by-stone, heart-by-heart try to find the difference in the way objects fall. I also tried to validate each single observation by slight changes in the implementation. It was then “reimplement – rethink – reimplement -rethink” cycle.

The first big difference I’ve found concerns the way blocks “bounce” when they fall down. I’ve mentioned this last time but when there’s an empty space to the left/right of the block, the block is supposed to move there (bounce). It turned out however that there’s a one frame delay in this move. This has a huge impact on the way blocks interact when they fall, as a free square not occupied by an object because of the delay can be occupied by another object.

Another very subtle difference I have found (and this was quite tricky) is the way HeartLight implements per-frame loops for X axis and Y axis. My first approach was to analyze rows from the lowest in the outer loop and then columns in the inner loop. HeartLight however has this inverted – the outer loop is for columns and the inner – for rows.

What’s important is that the final output of a fixed physics routine is now correct (below). Compare it with the first screenshot taken from the original version.

Next issue to fix is the way bombs explode. There’s also a great testing ground (below). In my implementation this level is currently completely unplayable.

Expect then to hear more on that in the future.

Friday, May 13, 2011

Implementing a BoulderDash/HeartLight Clone in XNA

Download the source code and binaries of the game (590kB)

I always wanted to have some spare time to write a BoulderDash / HeartLight Clone game. And just few days ago, I’ve finally made up my mind, launched VS 2010 with XNA and started to code.

No, this time it took more than 100 minutes, I think that I’ve put 7 or 8 hours into it. I am still not quite satisfied with the effect but the result is finally ready to be published so someone can pick up here and add features.

Dołączona grafika

I’ve started with textures, painted them myself in Paint.NET, they are simple 40x40 PNG images. Then the game engine. I’ve decided to take the object-oriented approach so the board is not represented as usuall 20x12 array of values but instead, I hold a list of objects of BaseBlock type and have a class hierarchy to represent different block types: StoneBlock, HeartBlock etc.

This way, I can build my logic on object’s methods and properties so the way to express the logic is more natural, like

BaseBlock block = ...;
 
block.GetNeighbour( Directions.S ).Explode();

or

public override bool ApplyPhysics()
 {
     base.ApplyPhysics();
 
     if ( 
         this.MustExplode ||
          (
            this.IsFalling &&
            this.GetNeighbour( Directions.S ) != null &&
            this.GetNeighbour( Directions.S ).TriggersExplosion 
           )
         )
     {
         this.Explode();
     }
 
     return false;
 }

Basically, some blocks can be eaten, some blocks explode, some blocks can be pushed and it’s all represented by virtual boolean properties on the base class. Refer to the source code for more details.

Caveat 1 – blocks do fall

To my surprise, I’ve lost an hour or two to implement a “gravity” in a proper way (to mimic the way objects fall in Heartlight). You see, it’s not that blocks just fall. It’s also that when a square near a block becomes empty, the stone (heart or bomb) can move sideways so it falls into the newly created hole in the just next frame. Of course also, blocks have to be analyzed bottom-top per frame to get correct results. And then, to avoid the risk of moving a block twice in a single frame, I mark blocks which were moved in that frame and clear the mark in the next frame.

The final version of the ApplyPhysics method is then as follows:

protected bool IsFalling = false;
 public virtual bool ApplyPhysics()
 {
     // czy pod spodem coś jest?
     BaseBlock block = this.GetNeighbour( Directions.S );
     if ( block == null )
     {
         // bezwarunkowe spadanie
         this.MoveTo( Directions.S );
         IsFalling = true;
 
         return false;
     }
     else
     {
         // spadł na gracza
         if ( block is PlayerBlock && this.IsFalling )
         {
             block.ExplodeNeighbour( Directions.None );
             SoundFactory.Instance.PlayEffect( SoundType.Stone );
         }
 
         // stoi na kamieniu
         if (
              ( block.DoesFall && !block.IsFalling ) ||
              ( block.OthersFallFrom ) 
             )
         {
             // może spaść w prawo - lewo?
             if ( this.GetNeighbour( Directions.E ) == null &&
                  this.GetNeighbour( Directions.SE ) == null &&
                  ( this.GetNeighbour( Directions.NE ) == null || 
                   !this.GetNeighbour( Directions.NE ).DoesFall )
                 )
             {
                 this.MoveTo( Directions.E );
                 IsFalling = true;
 
                 return false;
             }
             if ( this.GetNeighbour( Directions.W ) == null &&
                  this.GetNeighbour( Directions.SW ) == null &&
                  ( this.GetNeighbour( Directions.NW ) == null || 
                   !this.GetNeighbour( Directions.NW ).DoesFall )
                 )
             {
                 this.MoveTo( Directions.W );
                 IsFalling = true;
 
                 return false;
             }
         }
     }
 
     IsFalling = false;
     return true;
 }

Note that if there’s nothing below the block, it falls with no conditions. However, to be able to fall sideways, both the left/right and bottom-left/bottom-right squares have to be empty and then, there’s a condition to also check the top-left/top-right square to prevent the block from move sideways and collide with another block that is just falling down.

Caveat 2 – player moves

The other caveat I’ve encountered concerns the way the input has to be read. Although XNA calls Update/Draw 60 times per second, the game engine has to skip frames so that only every eighth frame is drawn to match the speed of the original game. And while it’s easy to read input in XNA, I have found that:

a) if I let the engine move the player as long as I read that the arrow is pressed, the player sometimes moves one square too far away. It just stems from the fact that humans cannot control the keyboard with such precision. Frames are drawn almost 8 times per second and if you hold the arrow key just a fraction of a second too long, the game doesn’t know that your intention was to stop a square earlier.

b) if I let the engine to reset the information of a move everytime I move the player, it’s possible to precisely control the game as long as you hold control keys to move two or more squares. It’s then however sometimes impossible to move just one square if you tap the key for a fraction of a second. This stems from the fact that it’s possible to tap the key exactly between two consecutive calls to the Update method, so that when Update is called, it doesn’t see the key has been pressed in between.

In other words, I was able to implement either the controls which allow the player to sometimes move too far away or the controls which allow the player to sometimes do not move at all.

I had to rethink the approach and finally came up with a solution where I read both long hold and short tap independently. Then, in a single Update I decide where I should move the player according to the long holding of the arrow key or according to the short tap of the arrow key:

protected override void Update( GameTime gameTime )
  {
      // Allows the game to exit
      KeyboardState state = Keyboard.GetState();
 
      playerDirection = BoardBlocks.Directions.None;
 
      // warunki na zakończenie gry lub planszy
      if ( board.MustRestart )
          this.ReloadBoard();
      if ( board.Completed )
          this.MoveToNextBoard();
      if ( state.IsKeyDown( Keys.Escape ) )
          board.ExplodePlayer();
 
      // obsługa klawiatury - pyk
      if ( !state.IsKeyDown( Keys.Space ) && !prevState.IsKeyDown( Keys.Left ) && state.IsKeyDown( Keys.Left ) )
          playerKnock = BoardBlocks.Directions.W;
      if ( !state.IsKeyDown( Keys.Space ) && !prevState.IsKeyDown( Keys.Right ) && state.IsKeyDown( Keys.Right ) )
          playerKnock = BoardBlocks.Directions.E;
      if ( !state.IsKeyDown( Keys.Space ) && !prevState.IsKeyDown( Keys.Up ) && state.IsKeyDown( Keys.Up ) )
          playerKnock = BoardBlocks.Directions.N;
      if ( !state.IsKeyDown( Keys.Space ) && !prevState.IsKeyDown( Keys.Down ) && state.IsKeyDown( Keys.Down ) )
          playerKnock = BoardBlocks.Directions.S;
 
      // obsługa klawiatury - player
      if ( state.IsKeyDown( Keys.F10 ) )
          this.Exit();
      if ( !prevState.IsKeyDown( Keys.Left ) &&
           state.IsKeyDown( Keys.Space ) && state.IsKeyDown( Keys.Left ) )
          this.MoveToPrevBoard();
      if ( !prevState.IsKeyDown( Keys.Right ) &&
           state.IsKeyDown( Keys.Space ) && state.IsKeyDown( Keys.Right ) )
          this.MoveToNextBoard();
      if ( state.IsKeyDown( Keys.F1 ) && !prevState.IsKeyDown( Keys.F1 ) )
          HelpVisible = !HelpVisible;
 
      // obsługa klawiatury - przejscia między levelami
      if ( !state.IsKeyDown( Keys.Space ) )
      {
          if ( state.IsKeyDown( Keys.Left ) )
              playerDirection = BoardBlocks.Directions.W;
          else
              if ( state.IsKeyDown( Keys.Right ) )
                  playerDirection = BoardBlocks.Directions.E;
              else
                  if ( state.IsKeyDown( Keys.Up ) )
                      playerDirection = BoardBlocks.Directions.N;
                  else
                      if ( state.IsKeyDown( Keys.Down ) )
                          playerDirection = BoardBlocks.Directions.S;
      }
 
      // update świata co 6 ramek
      FrameNumber++;
      if ( FrameNumber >= FrameSkip )
      {
          FrameNumber = 0;
 
          board.UpdateBoard( gameTime, state );
 
          if ( playerDirection != BoardBlocks.Directions.None )
          {
              board.UpdatePlayer( playerDirection );
              playerDirection = BoardBlocks.Directions.None;
              playerKnock = BoardBlocks.Directions.None;
          }
          else
              if ( playerKnock != BoardBlocks.Directions.None )
              {
                  board.UpdatePlayer( playerKnock );
                  playerKnock = BoardBlocks.Directions.None;
              }
      }
 
      base.Update( gameTime );
 
      prevState = state;
  }

The only issue I am not quite completely satisfied with is the way I implement bomb explosions. In HeartLight, bombs explode in such way that their explosions show up with short delay, thus a line of bombs explode slowly during consecutive frames. In my implementation, bombs lying side by side explode too quickly thus making one of the levels to behave different than in the original implementation (bombs explode and fall in a different way).

Profile of the game

Press F1 during the game for the in-game manual. Press F10 to exit.

Levels are stored in a XML file located in /Levels folder. The structure is self-explanatory, you can add your levels or modify included levels. I’ve included few levels from the HeartLight game and the full credit goes to Janusz Pelc for the design

Textures are stored in the /Textures folder and loaded in the run-time so please feel free to swap them with your own textures.

Sounds are stored in /Sounds folder, do not delete *.wav files (credit goes to C:/Windows/Media directory) but if you copy some *.mp3 files there, the game will play them shuffling one-by-one in consecutive levels.

Source code is written in C#. If you just want to play the game, navigate to /bin/x86/Debug folder and invoke XNADash.exe from the shell. Please do not forget to install .NET Framework 4 and XNA Redist first.

Any comments or remarks are welcome.