Tuesday, September 18, 2012

The New Censorship

This time I will not write about technical topic but about my concerns about the impact of a few big companies controlling digital content.

Apple censoring political satire

On August 19th I submitted my new game LeaderFlip to the Apple Appstore. LeaderFlip is a satiric, political game where the player is flipping a caricature of Germany chancellor Merkel to the moon. The game play is similar to doodle jump, you have to make Merkel jump on floating platforms to get her as high as possible. The idea is derived from a German idiom, where shooting somebody to the moon means you want to get rid of somebody.
LeaderFlip is already available on the Windows Phone Marketplace since July and received only positive press coverage.
About ten days after the submission to the Appstore I got an email from Apple stating that LeaderFlip needs some more review time.
On September 11th I finally got notice that LeaderFlip is rejected because of:
-------------
16.1

We found that your app contains content that many audiences would find objectionable, which is not in compliance with theApp Store Review Guidelines.

Specifically, we noticed your app includes images of "German Chancellor 'Angie Make'" tied up, as well as that she is propelled by farts. 
-------------

You can have a look at the trailer to make your own judgment on this.
Rule 16.1 of the Appstore guidelines says:
"Apps that present excessively objectionable or crude content will be rejected"

In Germany political satire and caricature has a long history and is a crucial part of all printed media. Depicting a politician tied up in the way we did in the game is comparable soft to what you will find in reputable German newspapers and magazines. And nobody has regarded the game "excessively objectionable or crude" so far.

On the other hand, rule 14.2 of the guidelines say:
"Professional political satirists and humorists are exempt from the ban on offensive or mean-spirited commentary"


So, now who is to decide, what is "excessively objectionable or crude" or what is "Professional political satirists"? Of course it is Apple who is deciding according to their political and moral views.

Microsoft censoring "provocative imagery"

Just when I got angry about Apple driving me closer to my financial ruin because I cannot publish the game that I have been working on for the last months, I got a strange email from Microsoft:
--------

Dear Developer,

This is to notify you that we are updating the Windows Phone Marketplace algorithms in order to enhance discoverability of applications targeting the broadest set of customers. As such, your applications listed below may be less visible to the average customer in the catalog. Your applications still can be discovered through search on the Windows Phone Marketplace.

Additional applications of yours may be impacted, and it could take time before you see any changes to the Windows Phone Marketplace.

Applications impacted:
BulletBabs

More information regarding the changes can be found here.

We look forward to seeing your application updates and new applications on the Windows Phone Marketplace.

Windows Phone Marketplace Team


--------
In other words, they are throwing Bullet Babs out of the Marketplace, for reasons they are not even telling in the email. They just give a link to a blog post:
http://windowsteamblog.com/windows_phone/b/windowsphone/archive/2012/09/12/coming-soon-a-new-website-and-online-app-store.aspx

Only after asking back for the reasons I got the reply:
---------

Actions Required to Remove the Visibility Impact:
Update and resubmit your iconography with less provocative and suggestive imagery and content.


---------
In short, Microsoft decided to censor out games, that do not even infringe the marketplace rules. And they do not even have the guts to tell the developers directly, but hide it inside a blogpost about enhancing the marketplace. Now, let us have a look at my "provocative and suggestive imagery":
Well, it is a girl in a dress holding a gun... Skirt to short? Breasts to big? I don't know...

Moral and culture defined by companies

When looking at big companies we usually worry about cartels threatening the free markets. I think, it is also time to worry about big companies threatening our culture. If we have a look at the smartphone market, we see that there are three global players restricting the content:
- Apple
- Google
- Microsoft (well, WP7 is still not important)
If you look at online games or private digital data filtering you will also have to look at
- Facebook

All companies have in common that they define their own guidelines and restrict digital content according to their own moral, cultural as well as political views. As digital content becomes more and more important, their influence will become more dominant.

As a German citizen I see this even more crucial, as German cultural values and moral is different to North American ones. For example, in Germany violent content is regarded more critical then sexual content. Whereas the "Nipplegate" incident teach us how sensitive USA citizens react on sexual content.
Well, censorship on itself is a difficult topic and this is not what I want to discuss here. My point is, that the censorship is not done by an independent agency anymore, as we see this with games that are traditionally published. And the censorship rules are not according to the country's laws.
No, the rules are defined and applied by the companies that run the digital distribution shops or platforms. And by that, they impose their moral, cultural and political views to their customers.

For me, as an indie-developer, the arbitrary decisions are very annoying to handle. But besides the business concerns, I am also concerned about companies creating a moral and culture monopoly.
Will we in future only be able to see cute "angry" birds and "cute" zombies?

*** Update ***

After discussion with Apple they finally published LeaderFlip on the App Store without changes. It  took exactly one month from submission to publish. But at least I am happy that I did not have to change the content.

Friday, April 20, 2012

Localization with C# Extensions

In this short post I am going to describe how I handle localization for different platforms. Actually each mobile platform comes with its own approach to this topic. But when you develop cross platform you probably don't want to complicate things by using the native solutions.
Therefore I came up with a very simple implementation that is just enough for my needs. Basically, in my approach localization just means to replace a text string with a text string for the local language. I do this by using three things:
  • An xml file with the localized strings,
  • a singleton class to handle the strings and
  • an Extension to the C# String class.
Insinde the xml file I declare a Text node with a name attribute, which is the identifier for the text. For me the identifier already is the default text. If you work with a bigger project it might be better to use a pure placeholder text instead. Inside the Text node there are Item nodes. Each Item node has an attribute language and value. As language identifier I use the  ISO 639-1 two-letter code which you can obtain easily in dot Net. The value is obviously the translated text. This is an example of my xml file:
<?xml version="1.0" encoding="utf-8" ?>
<TgexLocalization>
  <Text name="Score">
    <Item language="de" value="Punkte"></Item>
  </Text>
  <Text name="Multiplier">
    <Item language="de" value="Multiplikator"></Item>
  </Text>
</TgexLocalization>
The localization file and data is then handled by a singleton class, the Localizer. Before using the Localizer the Initialize function has to be called once, giving the xml file filename as parameter. The Localizer just has a dictionary of a string as key and string as value. When it parses the xml file it will just add entries to the dictionary when a Text node with an Item of the current language ID is found. In the above example, the dictionary would only be filled if the local system is German. In this case the dictionary would get two entries.
To get a localized text, you can now simple call
Localizer.Instance.GetText("Score");
If your system is not German, it would just return the same string that you passed as paramater, "Score". But if your system is German it finds the entry in the dictionary and returns "Punkte".
The full Localizer.cs looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.Globalization;
using System.IO;

#if ANDROID
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
#endif

namespace Tgex
{
    public class Localizer
    {
        protected String m_tag;
        /// <summary>
        /// String tag that defines the languages (2 char)
        /// </summary>
        public String Tag
        {
            get { return m_tag; }
            set { m_tag = value; }
        }

        Dictionary<string, string> m_strings = new Dictionary<string, string>();

        // create singleton
        static readonly Localizer instance = new Localizer();
        /// <summary>
        /// Get instance of singleton.
        /// </summary>
        public static Localizer Instance
        {
            get
            {
                return instance;
            }
        }
        /// <summary>
        /// Explicit static constructor to tell C# compiler
        /// not to mark type as beforefieldinit
        /// </summary>
        static Localizer()
        {
        }
        /// <summary>
        /// Constructor
        /// </summary>
        Localizer()
        {
            m_tag = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
        }

        public void Initialize(string filename)
        {
#if ANDROID
   var reader = new StreamReader(Game.Activity.Assets.Open (filename));
            XDocument xmlFile = XDocument.Load(reader);
#else

            XDocument xmlFile = XDocument.Load(filename);
#endif
            XElement root = xmlFile.Element("TgexLocalization");

            // read strings
            var texts = root.Descendants("Text");
            if (texts != null)
            {
                texts.ForEach(text =>
                {
                    var items = text.Elements("Item");
                    if (items != null)
                    {
                        XElement locStringXml = items.FirstOrDefault(item => item.Attribute("language").Value.ToString() == m_tag);
                        if (locStringXml != null)
                        {
                            m_strings.Add(text.Attribute("name").Value.ToString(), locStringXml.Attribute("value").Value.ToString());
                        }
                    }
                });
            }
        }

        public String GetText(string name)
        {
            if (m_strings.ContainsKey(name))
            {
                return m_strings[name];
            }
            return name;
        }
    }
}

To make the access simpler I use C# Extensions. I love this feature of C# and my Extensions class is actually very huge - I will probably post some of my most useful code in other blog posts. For now, I just show an extension to the String class. I define an extension function Localize(), that makes the call to the Localizer class. By that, I can localize a string by writing:
"Score".Localize();
The Extensions.cs class for that looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Tgex
{
    public static class Extensions
    {
        public static String Localize(this String text)
        {
            return Localizer.Instance.GetText(text);
        }
        // helper so that you can use ForEach on any IEnumerable
        public static void ForEach<T>(this IEnumerable<T> values, Action<T> action)
        {
            foreach (var v in values)
            {
                action(v);
            }
        }
    }
}
Even though this only translates text, you can use it also for resource strings. I use it for texture names, so I can also easily localize buttons with text on it.
This is already all that I need for localization of my games. I hope this little and simple approach might be useful for some cross platform developers.

Tuesday, March 27, 2012

Using Amazon SimpleDB for Runtime App-Parameter Editing

When you develop an app, you probably have a few parameters that you need to adjust and tweak to find the desired value. The usual approach would be to change the parameter in the source code, recompile and deploy the app to your phone to test it. If you have a lot of parameters to tweak, you probably add a developer GUI  to your app that enables you to change the parameters at runtime.
In this blog post I present an easy to integrate alternative. Instead of reading the values from your source code or an in game GUI, the parameter values are stored and retrieved in a cloud database. The technology is build onto my former blog post about using Amazon SimpleDB, hence for this we use SimpleDB again. The idea of this approach is like this:
Store all parameters you want to edit in an own class, e.g. AppParameter. When running your app in edit mode you will retrieve the values for AppParameter from the database. On your PC you run a .NET application that allows you to edit the database parameters. Reread the values inside your app and test the changed parameters. No need to recompile or even restart you app and edit the parameters from any PC.
To make the integration easy I present a solution that uses C# reflections to automatically determine the fields of the AppParameter class. Saving and reading the parameter class to and from the SimpleDB uses generics. That means you can use the code for any class you define. Also the PC-Editor automatically creates the GUI for the class parameters. This is a picture of the Editor using some arbitrary game parameters:
The parameter class used here:
public class AppParamter
{
    public float JumpForce;
    public float Gravity;
    public float Height;
    public float Weight;
    public Vector2 StartPosition;
    public Vector2 LevelOffset;
    public int NumOfLives;
    public int MaxItems;
    public int MinItems;
}
If you want to use this with your app you only have to change the AppParameter class to contain the parameters you need. However, I currently only support the data format float, Vector2 and int. If you need other formats you need to extend the example.
The Editor provides buttons to read and write the values from and to the Amazon SimpleDB. With the Clear DB button you can delete the complete entry for this parameter class. This is recommendable every time you  change the structure of the parameter class. Copy Values creates a code snippet and copies it to the clipboard that sets the current values of your class. Use this once you finalized your parameters to set the values inside your app without the database. The code snippet created for this example is:
public void SetValues()
{
    JumpForce = 2.3f;
    Gravity = 7f;
    Height = 12f;
    Weight = 55f;
    StartPosition = new Vector2(12f, 25f);
    LevelOffset = new Vector2(-3f, -2f);
    NumOfLives = 7;
    MaxItems = 5;
    MinItems = 1;
}

Implementation

The core class of this project is the ParameterProcessor. It is realized as a singleton and provides the interface to the database. Furthermore it provides functions to create strings from values and the other way round. You will find a lot of similarities to my previous SimpleDB blog post.
The class is designed to be used from the PC-Editor as well as from the phone app. Therefore I did not use the Amazon AWS SDK for .NET for the SimpleDB access from Windows, but used the SDK designed for the Windows Phone. For that I needed to create Windows Library Project and add the SDK source files. Compiling and running it from Windows worked smooth with only one exception. In SimpleDBResponsce.cs line 39, the IsRequestSuccessful property for set is declared protected. This caused the XmlSerializer to throw an Exception. Removing the protected modifier solved the problem. Now let us take a look at the code. In the beginning the singleton is defined and in the constructor the amazon client is initialized. Don't forget to enter your SimpleDB keys there.
    public class ParameterProcessor
    {
        #region singleton
        // create singleton
        static readonly ParameterProcessor instance = new ParameterProcessor();
        /// <summary>
        /// Get instance of singleton.
        /// </summary>
        public static ParameterProcessor Instance
        {
            get
            {
                return instance;
            }
        }
        /// <summary>
        /// Explicit static constructor to tell C# compiler
        /// not to mark type as beforefieldinit
        /// </summary>
        static ParameterProcessor()
        {
        }
        #endregion

        // db
        AmazonSimpleDB m_sdb;

        /// <summary>
        /// Constructor
        /// </summary>
        ParameterProcessor()
        {
            // intitialize db
            // amazon cloud access
            m_sdb = AWSClientFactory.CreateAmazonSimpleDBClient("YourPublicKey", "YourPrivatKey");
        }
The function SaveToDB uses generics to pass the parameter class and instance of which values are stored in the database. The second function parameter is the name of the domain in SimpleDB. The domain needs to be created before. The response handler, which is called after the parameters have been stored in the database, currently does nothing. Using C# reflections the fields of the parameter class are easily iterated through an FieldInfo array provided by the function GetFields() from the Type class. The database then simply stores the field name as an attribute with the field value converted to a string. Additionally I save a time stamp that could be used to check if data has been updated without retrieving all attribute. This could make sense if the data you store is very huge. The complete class values are entered as one item into SimpleDB where the parameter class name is used as key value for the item. By that you could store multiple different parameter classes within one SimpleDB domain.
/// <summary>
/// Takes a class and enters its fields to an Amazon SimpleDB
/// </summary>
/// <typeparam name="T">Serializable Class to be saved into the database</typeparam>
/// <param name="data">Class instance that is saved into the database</param>
/// <param name="tableName">Name of domain in SimpleDB</param>
public void SaveToDB<T>(T data, string tableName)
{
    SimpleDBResponseEventHandler<object, ResponseEventArgs> handler = null;
    handler = delegate(object senderAmazon, ResponseEventArgs args)
    {
        //Unhook from event.
        m_sdb.OnSimpleDBResponse -= handler;
        PutAttributesResponse response = args.Response as PutAttributesResponse;
        if (null != response)
        {
        }
        else
        {
        }
    };

    m_sdb.OnSimpleDBResponse += handler;

    string structName = data.GetType().Name;
    PutAttributesRequest putAttributesRequest = new PutAttributesRequest { DomainName = tableName, ItemName = structName };
    List<ReplaceableAttribute> attributesOne = putAttributesRequest.Attribute;

    Type type = data.GetType();
    System.Reflection.FieldInfo[] fields = type.GetFields();
    foreach (System.Reflection.FieldInfo field in fields)
    {
        string valueString = FieldToString(field, data);
        attributesOne.Add(new ReplaceableAttribute().WithName(field.Name).WithValue(valueString).WithReplace(true));
    }
    attributesOne.Add(new ReplaceableAttribute().WithName("TimeStamp").WithValue(DateTime.Now.Ticks.ToString()).WithReplace(true));

    m_sdb.PutAttributes(putAttributesRequest);
}
The ReadFromDB function also uses generics and reads the values from the database into the passed parameter class instance. Additionally you can pass an Action delegate, that is called after the data is received. Remember that the database calls are asynchronous, so if you for example need to refresh your GUI after the new values are received, you can use this delegate.
The select request retrieves the SimpleDB item with the key value (itemName) of the parameter class name. The request handler then iterates through the retrieved attributes and using reflections sets the values into the fields of the parameter class instance.
/// <summary>
/// Reads values from a SimpleDB and writes it into a class instance.
/// </summary>
/// <typeparam name="T">Serializable Class that is read from the database</typeparam>
/// <param name="data">Class instance where the database values are written into</param>
/// <param name="tableName">Name of domain in SimpleDB</param>
/// <param name="readFinished">A delegate that is called when reading the values has finished. Set null if not needed.</param>
public void ReadFromDB<T>(T data, string tableName, Action readFinished)
{
    // create response handler and delegate
    SimpleDBResponseEventHandler<object, ResponseEventArgs> handler = null;

    handler = delegate(object sender, ResponseEventArgs args)
    {
        //Unhook from event.
        m_sdb.OnSimpleDBResponse -= handler;
        SelectResponse response = args.Response as SelectResponse;

        if (null != response)
        {
            Type type = data.GetType();
            System.Reflection.FieldInfo[] fields = type.GetFields();

            SelectResult selectResult = response.SelectResult;
            if (null != selectResult)
            {
                foreach (Item item in selectResult.Item)
                {
                    // actually should just be one item
                    foreach (Amazon.SimpleDB.Model.Attribute attribute in item.Attribute)
                    {
                        var field = fields.FirstOrDefault(f => f.Name == attribute.Name);
                        if (field != null)
                        {
                            StringToFieldValue(field, data, attribute.Value);
                        }
                    }
                }
            }
            if (readFinished != null)
            {
                readFinished.Invoke();
            }
        }
    };
    m_sdb.OnSimpleDBResponse += handler;

    string structName = data.GetType().Name;
    // create request
    string sql = "SELECT * FROM " + tableName + " WHERE itemName()='" + structName + "'";
    m_sdb.Select(new SelectRequest { SelectExpression = sql, ConsistentRead = true });
}
SimpleDB can only store string values, therefore the parameter class field have to be converted to a string. This is done by the FieldToString function. The current implementation explicitly only supports float, int and Vector2. You can add more types if you need them here.
/// <summary>
/// Using reflection to get a value string of a class field.
/// </summary>
/// <param name="field">The field of the class to get the value from</param>
/// <param name="data">Class instance with values</param>
/// <returns></returns>
public String FieldToString(System.Reflection.FieldInfo field, object data)
{
    string valueString;
    if (field.FieldType == typeof(float))
    {
        valueString = ((float)field.GetValue(data)).ToString(System.Globalization.CultureInfo.InvariantCulture.NumberFormat);
    }
    else if (field.FieldType == typeof(Vector2))
    {
        Vector2 vec = (Vector2)field.GetValue(data);

        System.Globalization.NumberFormatInfo nfi
                = System.Globalization.CultureInfo.InvariantCulture.NumberFormat;
        valueString = vec.X.ToString(nfi) + ", "
                    + vec.Y.ToString(nfi);
    }
    else
    {
        // just use the default ToString for all other field types
        // extend it if you need special handling like the types before
        valueString = field.GetValue(data).ToString();
    }
    return valueString;
}
The complement function to the above takes a string and writes the value into the field of the passed instance. Again only float, int and Vector2 is supported here.
/// <summary>
/// Using reflection to set a class field from a value string.
/// Currently only float, Vector2 and int is supported.
/// Extend for you needs.
/// </summary>
/// <param name="field">The field of the class for which the value will be set.</param>
/// <param name="data">Class instance where the value will be stored into</param>
/// <param name="valueString">A string containing a value for the field</param>
public void StringToFieldValue(System.Reflection.FieldInfo field, object data, string valueString)
{
    if (field.FieldType == typeof(float))
    {
        field.SetValue(data, float.Parse(valueString, System.Globalization.CultureInfo.InvariantCulture.NumberFormat));
    }
    else if (field.FieldType == typeof(Vector2))
    {
        System.Globalization.NumberFormatInfo nfi
            = System.Globalization.CultureInfo.InvariantCulture.NumberFormat;
        String[] values = valueString.Split(',');
        Vector2 point = new Vector2();
        try
        {
            point.X = float.Parse(values[0], nfi);
            point.Y = float.Parse(values[1], nfi);
        }
        catch
        {
            // oh no
        }
        field.SetValue(data, point);
    }
    if (field.FieldType == typeof(int))
    {
        field.SetValue(data, Int32.Parse(valueString, System.Globalization.CultureInfo.InvariantCulture.NumberFormat));
    }
    else
    {
        // unsupported type
    }
}
The Windows DB Parameter Editor uses the above class to read and write to and from the database. I will not go much into the details of the editor source code here. Worth mentioning is the dynamic creation of the parameter GUI. Therefore exists a base class ParameterControl, which is derived from UserControl. This base class also has a static function CreateParameterControl, which serves as a factory for the actual derived parameter controls. According to the type of the passed FieldInfo different controls can be generated. Anyhow, in this example I only implemented the TextBoxParameterControl, where you enter the values into a simple text box. Possible extensions could for example be a slider control for floats,  a checkbox control for a bool parameter or a color picker control for a color field. Inside the main form (Form1.cs) the controls are then created like this:
Type type = classData.GetType();
System.Reflection.FieldInfo[] fields = type.GetFields();
int offset = 15;
foreach (System.Reflection.FieldInfo field in fields)
{
    ParameterControl control = ParameterControl.CreateParameterControl(field, classData);
    control.Top = offset;
    control.Left = 5;
    offset += control.Height;
    this.parameterGroupBox.Controls.Add(control);
}
Using the ParameterProcessor class you can finally integrate the database access into your application. Just reread the parameter class values at your convenience. You could add an update button, or reread every time you restart a level or even poll at a certain time interval.

Download and Conclusion

The complete source code of the DB Parameter Editor can be downloaded from my homepage:
DBParameterEditor.zip
It is developed using Microsoft Visual Studio 2010 Express, but it should not be a problem to use it in MonoDevelop. I also included the AWSSDKWP7 (SDK for SimpleDB) as Windows binary, so that you can directly start testing.

In this post I presented an easy way to tweak app parameters from a PC using a cloud database. This scenario can be extended in multiple directions. For example you could extend the Editor to become a more flexible game level editor. By that your game and level designers can modify levels on the running application. You could also extend it to be usable with a release version of a game. By that you can make game play adjustments without the need of an update.

Thursday, March 15, 2012

Save and Read an Encrypted Data File

Your mobile game or app most probably has some data you want to store locally on the phone. Also there might be good reason why you don't want this saved data to be easily accessible and changeable from outside of your app. For the iPhone for example you can simply use iExplorer to read and change any files of an app - no jailbreak needed. If you develop a game you might want to avoid that a user can easily cheat points and achievements. If your app has in-app purchasable items you might even get financial loss if the user can easily cheat.
Luckily the .Net Framework comes with a lot of classes that make file encryption easy to implement. If you want to secure your data from manipulation you generally have two ways of achieving it:
  • Leave the data readable but add an authentication hash key. 
  • Encrypt the complete data file.
The first method is for example used by RESTful web services. In my previous post I talked about Amazon SimpleDB which uses a hash key for authentication of the database requests. Take a look inside the library source code if you are interested in a working cross-platform implementation example.
The second method encrypts the complete data file. People sneaking into your data files will not be even able to read it and might not be tempted to try to alter the values.
In this post I will give an example for the second method. I will give an implementation that works well with Windows Phone, MonoTouch and Mono for Android and can be easily added to any app.

Application Flow
In this implementation the data that should be stored is located inside a struct. Using XML serialization the struct is converted to XML which is then encrypted and finally stored as an isolated storage file.
struct -> XmlSerializer -> XmlWriter -> CryptoStream -> IsolatedStorageFileStream
When reading the encrypted file the flow is the other way round:
IsolatedStorageFileStream -> CryptoStream -> XmlSerializer -> struct

Implementation
Start by adding the following using statements to your source file:
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Security;
using System.Security.Cryptography;
using System.IO.IsolatedStorage;
In my example I use the following data structure, which is some simple game data.
public struct SaveGameStruct
{
    public string Name;
    public int HiScore;
    public int NumOfCoins;
    public DateTime Date;
    public string Guid;
}
Next store a password and a salt as member variable string:
string m_password = "7Sj)fjfdHf734Jjd";
string m_salt = "hHeh=j84";
The password is not the actual password that is used to encode your data file. Instead it is used to create a key that then is used for encryption. The key generator uses pseudo random numbers, hence the salt. Don't forget to change the password and salt values in your source code.
The function to save an encrypted file now looks like this:
public void DoSaveGame()
{
    //Generate a Key based on a Password and HMACSHA1 pseudo-random number generator
    //Salt must be at least 8 bytes long
    //Use an iteration count of at least 1000
    Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(m_password, Encoding.UTF8.GetBytes(m_salt), 1000);

    //Create AES algorithm
    AesManaged aes = new AesManaged();
    //Key derived from byte array with 32 pseudo-random key bytes
    aes.Key = rfc2898.GetBytes(32);
    //IV derived from byte array with 16 pseudo-random key bytes
    aes.IV = rfc2898.GetBytes(16);
            
    string SAVEFILENAME = "savegame.xml";

    IsolatedStorageFileStream storageStream = m_savegameStorage.OpenFile(SAVEFILENAME, FileMode.Create);
    XmlWriterSettings writerSettings =
    new XmlWriterSettings
    {
        Indent = true,
        IndentChars = "\t"
    };

    XmlSerializer serializer = new XmlSerializer(typeof(SaveGameStruct));

    CryptoStream cryptoStream = new CryptoStream(storageStream, aes.CreateEncryptor(), CryptoStreamMode.Write);

    using (XmlWriter xmlWriter = XmlWriter.Create(cryptoStream, writerSettings))
    {
        // m_saveGame is a member variable of the type SaveGameStruct which holds the data to be saved
        serializer.Serialize(xmlWriter, m_saveGame);
    }
    cryptoStream.FlushFinalBlock();
    cryptoStream.Close();
    storageStream.Close();
}
As you can see I use AesManaged, because this is an encryption class that I found to work with WP7, MonoTouch and Mono for Windows. That is all that is necessary to store a structure inside an encrypted file. The function to read the encrypted file is similar simple:
void LoadSaveGame()
{
    //Generate a Key based on a Password and HMACSHA1 pseudo-random number generator
    //Salt must be at least 8 bytes long
    //Use an iteration count of at least 1000
    Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(m_password, Encoding.UTF8.GetBytes(m_salt), 1000);

    //Create AES algorithm
    AesManaged aes = new AesManaged();
    //Key derived from byte array with 32 pseudo-random key bytes
    aes.Key = rfc2898.GetBytes(32);
    //IV derived from byte array with 16 pseudo-random key bytes
    aes.IV = rfc2898.GetBytes(16);

    string SAVEFILENAME = "savegame.xml";
    if (m_savegameStorage.FileExists(SAVEFILENAME))
    {
        IsolatedStorageFileStream fs = null;
        try
        {
            fs = m_savegameStorage.OpenFile(SAVEFILENAME, System.IO.FileMode.Open);
        }
        catch (IsolatedStorageException)
        {
            // The file couldn't be opened, even though it's there.
            // You can use this knowledge to display an error message
            // for the user (beyond the scope of this example).
        }

        if (fs != null)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(SaveGameStruct));
            CryptoStream cryptoStream = new CryptoStream(fs, aes.CreateDecryptor(), CryptoStreamMode.Read);
            m_saveGame = (SaveGameStruct)serializer.Deserialize(cryptoStream);
        }
    }
    else
    {
        // if file is not found it is probably the first time the app launched - handle it properly
    }
}
As you can see it is pretty much similar to the file save function, just the streams are the other way round.
And this already completes the code for saving and reading an encrypted data file. Please note, that I didn't handle exceptions at the stream reading and writing parts. So you still have to add a proper exception handling here.
My solution was heavily inspired (and partly copy and pasted) from this awesome blog post.
The encryption solution described here is not perfectly save against being hacked, as the password is saved in the source code and could be disassembled. If you have to encrypt critical data, like passwords, bank data or confidential company data, you should use a more save encryption method. But probably cross platform implementation will be not as easily be achieved then. You can read more about this topic and a solution for Windows Phone here.

Friday, March 9, 2012

Cross-Platform Global High-Score using Amazon SimpleDB

In this post I am going to describe my solution for a simple global high score that works with WP7, iOS and Android. I wasn't really following the development of web technologies for more than 10 years. So when looking for a global high score solution for my new game I needed to catch up with the recent technologies and then had to decide which one to use. I don't know if what I came up with is the best solution, but it is powerful yet simple and easy.
The preconditions for me for the global high score where:
  • It should be easy and fast to implement and maintain.
  • It should use standard web technologies.
  • It should be scaleable.
  • It should use the standard web http protocol.
  • It should be secure,
  • and it should be as cross platform as possible.
When it came to a standard interface using http I soon was sure that web services are the way to go. From there I decided that a RESTful (Representational state transfer) web service using XML should be most suited for .NET applications.
The next decision was whether to use my own virtual root server and setup the appropriate interface to a data base or use a cloud service. Even though there are a lot of tools available that support you to develop server side web services, in the end it looked like it would really brake the precondition of easy and fast implementation. Also scaling might get a problem if the game becomes very popular. I found that Amazon and Microsoft both offer a cloud service to a simple nosql database that already comes with a complete RESTful web service interface:
I actually first wanted to try the Microsoft Azure Service, but just when I tried to open an account, the management service was down and kept being down for the whole afternoon. Not a good omen for a cloud service, so I decided to go for Amazon SimpleDB instead.
Microsoft(!) offers a SDK for Windows Phone (though still beta) for the Amazon cloud services and of course Amazon offers SDKs for iOS and Android. But the cool part is, that the Windows Phone SDK comes with source code and can therefore be easily used with MonoTouch and Mono for Android as well! Using the SDK there is no need to write low level client side RESTful web services yourself, instead you have an easy to use interface to the Amazon SimpleDB data base.

Setting up the Amazon SDK
The source code for the AWS-SDK for Windows Phone is available from a GIT-Hub repository. So first check out the source code to a local directory. It comes with a complete set of samples for different Amazon cloud services. Inside the directory AWSWP7SDK you find the actual sdk. For WP7 you just have to include the project file AWSSDKWP7.csproj to your game solution and add the project as reference to your game.
For MonoTouch and Mono for Android you have to create a new project file for each. Just create a new MonoTouch and Mono for Android library and add all the SDK files. Then you need to make small changes in two files:
  • Amazon.Runtime\AWSCredentials.cs
  • Amazon.Runtime\ConfigurationManager.cs
In both files you should make a #if WINDOWS_PHONE ... #endif around all using statement to the System.Windows domain and sub domains. Inside the ConfigurationManager.cs you also should to this to the body of the LoadConfigFile() function, because we cannot read Windows config files with Mono. To initialize the database we therefore have to set the database key and security key in code instead of the config file, which is the the better way to do anyhow.
Now the SDK should compile with MonoTouch and Mono for Android and you can add the projects to your game solutions.

Getting started with Amazon SimpleDB
Before you can start developing you need to sign up for Amazon AWS here. There is a good setup guide from Amazon here. Unfortunately Amazon does not include SimpleDB within their web based management console. Therefore it is a good idea to setup a management software like the Scratchpad from the setup guide.

Simple Global High Score implementation
Amazon itself has an article for a global high score using the iOS and Android SDK on their web page. The sample I provide here is not very different from that. 
First you should create a domain for your game in the database using a management tool like the Scratchpad. Then start implementing by creating a SimpleDB client object:
// add at beginning of your file
// Amazon db
using Amazon;
using Amazon.SimpleDB;
using Amazon.SimpleDB.Util;
using Amazon.SimpleDB.Model;

// make this a member variable
AmazonSimpleDB m_sdb;

// and create the client inside the constructor
m_sdb = AWSClientFactory.CreateAmazonSimpleDBClient("your_access_key", "your_secrete_access_key");
The SimpleDB is a nosql database and therefore a table does not have a fixed structure. Anyhow, when you store and read high score data from the database you still have to decide on which attributes a high score entry inside your domain table should have. The table I use has the following attributes:

  • Category - this is always "HighScore" for high score entries
  • Player - name of the player to display in high score list
  • Score - score of the entry
  • OS - I also store "Windows Phone", "iOS" or "Android" for statistics.
Using these attributes the function to store a high score entry now looks like this:
void WriteGlobalHighscore()
{
    SimpleDBResponseEventHandler<object, ResponseEventArgs> handler = null;
    handler = delegate(object senderAmazon, ResponseEventArgs args)
    {
        //Unhook from event.
        m_sdb.OnSimpleDBResponse -= handler;
        PutAttributesResponse response = args.Response as PutAttributesResponse;
        if (null != response)
        {
           // we could do something when we get a success response from the server
        }
    };

    m_sdb.OnSimpleDBResponse += handler;
    string uniqueID = "UNIQUE_ID";
    string playerName = "PLAYER_NAME";
    string domainName = "YOUR_DOMAIN_NAME";
    string operationSystem = "Windows Phone"; // change for other os
    PutAttributesRequest putAttributesRequest = new PutAttributesRequest { DomainName = domainName, ItemName = uniqueID };
    List<ReplaceableAttribute> attributesOne = putAttributesRequest.Attribute;

    attributesOne.Add(new ReplaceableAttribute().WithName("Category").WithValue("HighScore").WithReplace(true));
    attributesOne.Add(new ReplaceableAttribute().WithName("Player").WithValue(playerName).WithReplace(true));
    // zero pad highscore string - necessary for sorting in select request because all value types are strings
    string number = AmazonSimpleDBUtil.EncodeZeroPadding(m_saveGame.HiScore, 10);
    attributesOne.Add(new ReplaceableAttribute().WithName("Score").WithValue(number).WithReplace(true));
    attributesOne.Add(new ReplaceableAttribute().WithName("OS").WithValue(operationSystem).WithReplace(true));

    m_sdb.PutAttributes(putAttributesRequest);
}
As you can see, the call to the database is asynchronous. When the operation is completed the response handler is called. Out of laziness the handler is directly declared as delegate inside this function.
The variables uniqueID, playerName and domainName have to be assigned with proper values. The uniqueID is the key value of the database table. I follow the example from Amazon and use an ID that is unique for each phone. I do this by creating a GUID the first time the game is started and store this GUID in a file. To get the player name you have to implement a dialog to let the player enter a name. The name should also be stored inside a file, so that you don't have to ask the player each time again.

You should now use the Scratchpad to verify if your entry really is stored at your SimpleDB. To do that you use the Select function and enter the Select Expression "select * from <your_domain_name>".

If you confirmed your successful storage of your high score you are ready to implement the function to request the entry from your game:
void RequestGlobalHighscore()
{
    // create response handler and delegate
    SimpleDBResponseEventHandler<object, ResponseEventArgs> handler = null;

    handler = delegate(object sender, ResponseEventArgs args)
    {
        int globlaHighscore;
        string playerName;
        string operationSystem;
        //Unhook from event.
        m_sdb.OnSimpleDBResponse -= handler;
        SelectResponse response = args.Response as SelectResponse;

        if (null != response)
        {
            SelectResult selectResult = response.SelectResult;
            if (null != selectResult)
            {
                foreach (Item item in selectResult.Item)
                {
                    // actually should just be one item
                    foreach (Amazon.SimpleDB.Model.Attribute attribute in item.Attribute)
                    {
                        switch (attribute.Name)
                        {
                            case "Score":
                                globlaHighscore = Int32.Parse(attribute.Value);
                                break;
                            case "Player":
                                playerName = attribute.Value;
                                break;
                            case "OS":
                                operationSystem = attribute.Value;
                                break;
                        }
                    }
                }
            }
            // now store the attributes to some member variables
            // ....
        }
    };
    m_sdb.OnSimpleDBResponse += handler;

    // create request
    string domainName = "YOUR_DOMAIN_NAME";
    string sql = "SELECT * FROM " + domainName + " WHERE Category='HighScore' INTERSECTION Score IS NOT null ORDER BY Score DESC LIMIT 1";
    m_sdb.Select(new SelectRequest { SelectExpression = sql, ConsistentRead = true });
}
This database request again is asynchronous and the handler, that is called when the answer arrived, is directly defined as delegate inside this function. In this example the result attributes are just stored inside local variables. Of course you need to copy them to some global structure or member variables.

This ends the post about my solution for a simple global high score implementation that works with WP7, iOS and Android. I think it is very elegant as the actual game code is shared along all platforms without any special modifications for a platform necessary. Also the SDK for the Amazon AWS cloud services is very easy to use. Following this example adding a global high score to your game can be done in just a few hours.

Thursday, February 23, 2012

MonoGame: Getting Started 3/3

Now let us create an Android project for the game. To start the project the following files are need:
  • Activity class file
  • Manifest file
  • Project file
  • Solution file
  • Icon file
In Android each app needs to have at least one Activity class. Therefore create a file inside your Android directory with the name Activity1.cs and the following content:
using Android.App;
using Android.OS;
using Android.Util;
using Android.Views;
using Android.Widget;
using Android.Content.PM;

namespace MyNamespace
{
    [Activity(Label = "MyGame Label", 
       MainLauncher = true, 
       Icon = "@drawable/icon", 
       ScreenOrientation = ScreenOrientation.Portrait,
       ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, 
       LaunchMode=LaunchMode.SingleInstance
    )]
    public class Activity1 : Microsoft.Xna.Framework.AndroidGameActivity
    {
        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);
     
            MyGame.Activity = this;
            var game = new MyGame ();
            
            FrameLayout fl = new FrameLayout(this);
            fl.AddView(game.Window);                               
            SetContentView (fl);            

            game.Run ();            
        }
    }
}
Inside this source change the MyNamespace and MyGame to fit your project. Next we need a manifest file. For that create a directory Properties and inside create the file AndroidManifest.xml with this content:

Before saving it you have to change the package tag to your game name and application label. The manifest file is the configuration file for your Android app. E.g. the minSdkVersion 8 means the Android API 8, which is Android 2.2. So this manifest file supports devices from version 2.2 upwards. Also the permissions of what features your application uses are defined in this file. Please read the Android docs to find out more about the manifest file:
http://developer.android.com/guide/topics/fundamentals.

Now go back to your Android source directory and create the project file MyGame.android.csproj with the following content:
You have to change the RootNamespace and AssemblyName tag to match your project. Also check if the ProjectReference tag of MonoGame and Lidgren point to your local installation path.
Now create the solution file for this project MyGame.sln and copy this content:
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lidgren.Network.Android", "..\..\MonoGame\ThirdParty\Lidgren.Network\Lidgren.Network.Android.csproj", "{565129E0-4EE5-4F6F-B403-C3484C9740BE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Framework.Android", "..\..\MonoGame\MonoGame.Framework\MonoGame.Framework.Android.csproj", "{BA9476CF-99BA-4D03-92F2-73D2C5E58883}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9C06E528-B9C7-4115-81C1-0E572103B242}"
EndProject
Global
 GlobalSection(SolutionConfigurationPlatforms) = preSolution
  Debug|Any CPU = Debug|Any CPU
  Release|Any CPU = Release|Any CPU
 EndGlobalSection
 GlobalSection(ProjectConfigurationPlatforms) = postSolution
  {565129E0-4EE5-4F6F-B403-C3484C9740BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  {565129E0-4EE5-4F6F-B403-C3484C9740BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
  {565129E0-4EE5-4F6F-B403-C3484C9740BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
  {565129E0-4EE5-4F6F-B403-C3484C9740BE}.Release|Any CPU.Build.0 = Release|Any CPU
  {BA9476CF-99BA-4D03-92F2-73D2C5E58883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  {BA9476CF-99BA-4D03-92F2-73D2C5E58883}.Debug|Any CPU.Build.0 = Debug|Any CPU
  {BA9476CF-99BA-4D03-92F2-73D2C5E58883}.Release|Any CPU.ActiveCfg = Release|Any CPU
  {BA9476CF-99BA-4D03-92F2-73D2C5E58883}.Release|Any CPU.Build.0 = Release|Any CPU
  {C04E8EB0-46A8-431F-9C16-E5DA58C1D705}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  {C04E8EB0-46A8-431F-9C16-E5DA58C1D705}.Debug|Any CPU.Build.0 = Debug|Any CPU
  {C04E8EB0-46A8-431F-9C16-E5DA58C1D705}.Release|Any CPU.ActiveCfg = Release|Any CPU
  {C04E8EB0-46A8-431F-9C16-E5DA58C1D705}.Release|Any CPU.Build.0 = Release|Any CPU
  {F10C1F14-64AF-4957-847E-E60490371E84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  {F10C1F14-64AF-4957-847E-E60490371E84}.Debug|Any CPU.Build.0 = Debug|Any CPU
  {F10C1F14-64AF-4957-847E-E60490371E84}.Release|Any CPU.ActiveCfg = Release|Any CPU
  {F10C1F14-64AF-4957-847E-E60490371E84}.Release|Any CPU.Build.0 = Release|Any CPU
  {1C3FA898-56B3-4135-8A92-C876CECB5C60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  {1C3FA898-56B3-4135-8A92-C876CECB5C60}.Debug|Any CPU.Build.0 = Debug|Any CPU
  {1C3FA898-56B3-4135-8A92-C876CECB5C60}.Release|Any CPU.ActiveCfg = Release|Any CPU
  {1C3FA898-56B3-4135-8A92-C876CECB5C60}.Release|Any CPU.Build.0 = Release|Any CPU
 EndGlobalSection
 GlobalSection(NestedProjects) = preSolution
 EndGlobalSection
 GlobalSection(MonoDevelopProperties) = preSolution
  StartupItem = BulletBabs.Android.csproj
  Policies = $0
  $0.DotNetNamingPolicy = $1
  $1.DirectoryNamespaceAssociation = None
  $1.ResourceNamePolicy = FileFormatDefault
 EndGlobalSection
EndGlobal
Here again check if the path to the MonoGame and Lidgren project files point to your local MonoGame installation.
The one file remaining now is an icon for your game. For that you should create the folders Resources/drawable and place a png image file with the name Icon.png inside. Make the resolution of this file 96x96 pixel.

Now you are ready to open the solution file in either Visual Studio or MonoGame, depending on your installation option of Mono for Android. First check if the references to the MonoGame and Lidgren project are correct. Then add your game by using add project to add the project file we created before.
If you created and placed all files correctly you should now see all files inside your project map. Again please the if the references to MonoGame are correct.
Now you have to proceed similar as with the iOS project. First you add all your game source files as link to your project. At this point you should then already be able to compile your game. If not, try to find and fix the errors.
Once your game compiles you are ready to add the content files. If you haven't, please read the remarks to that in the iOS part before. On Android all content goes into an Assets folder. Therefore you need to add your content files in a folder Assets/Content. Change the options of each file to "Build Type: AndroidAsset".

Now you are ready to deploy and run your game on the Android emulator. However, the Android emulator is so slow - at least on my computer - that running and debugging is cumbersome. For a first test it should be fine though.
Unfortunately, if you are seriously porting your game to Android, you are not finished her yet. Unlike WP7 and iOS, Android does not take care about your application when it gets suspended and resumed. On Android you have to handle it yourself. The magic word here is Lifecycle Management, you can start getting the idea be reading the official Android docs:
http://developer.android.com/reference/android/app/Activity.html
To make things worse, your application's OpenGL context will get invalid once your app is resumed, resulting in broken textures. Hopefully in later versions Mono for Android or MonoGame will take care of that. By the time of writing however, you will have to take care about this yourself. You should check the discussion board of MonoGame on how you could handle it. I am not very satisfied with the hack I am using for my games so far myself.

I hope this blog post is useful to show how fast you can get your XNA game running on iOS and Android. However, if you seriously planning to publish your game on these platforms, you also need to read about and understand their special technical differences and issues.

Tuesday, February 21, 2012

MonoGame: Getting Started 2/3

Next we set up the iOS project. Inside the iOS directory create a file called AppDelegate.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;

using Microsoft.Xna.Framework;

namespace MyNamespace
{
 // The UIApplicationDelegate for the application. This class is responsible for launching the 
 // User Interface of the application, as well as listening (and optionally responding) to 
 // application events from iOS.
 [Register ("AppDelegate")]
 class Program : MonoGameProgram 
 {
  private MyGame game;

  public override bool FinishedLaunching (UIApplication app, NSDictionary options)
  {
   // Fun begins..
   game = new MyGame();
   MonoGameGame = game;
   game.Run();
   return true;
  }

  static void Main (string [] args)
  {
   UIApplication.Main (args,null,"AppDelegate");
  }
 }
}

Change MyNamespace to your namespace and MyGame to your game class name.
The second file we need is Info.plist. If you are new to Apple, a plist file is a configuration file for the application. Create the file like this:


 MinimumOSVersion
 4.1
 UIDeviceFamily
 
  2
 
 UISupportedInterfaceOrientations
 
  UIInterfaceOrientationPortrait
 



Now we only need a solution and a project file. For the project file, create a text file with the name of your game dot ios dot csproj, e.g. MyGame.ios.csproj and copy this content:


  
    Debug
    iPhoneSimulator
    10.0.0
    2.0
    {6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
    Exe
    MyGame.ios
    MyGameios
  
  
    true
    full
    false
    bin\iPhoneSimulator\Debug
    DEBUG; IOS;
    prompt
    4
    false
    None
    true
  
  
    none
    false
    bin\iPhoneSimulator\Release
    prompt
    4
    false
    None
  
  
    true
    full
    false
    bin\iPhone\Debug
    DEBUG;
    prompt
    4
    false
    true
    iPhone Developer
    
    
  
  
    none
    false
    bin\iPhone\Release
    prompt
    4
    false
    iPhone Developer
  
  
    
    
    
    
    
  
  
    
  
  
    
  
  
  
    
      {DB8508BB-9849-4CC2-BC0F-8EB5DACB3C47}
      MonoGame.Framework.iOS
    
  
  
    
  

Change the tag RootNamespace and AssemblyName to meet your game name and check the tag ProjectReference for the path to MonoGame project file to point on your disk.
Finally create a solution file e.g. MyGame.ios.sln with this content:
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lidgren.Network.iOS", "..\..\MonoGame\ThirdParty\Lidgren.Network\Lidgren.Network.iOS.csproj", "{734EAA48-F1CA-481A-B391-0285BC0E8B40}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Framework.iOS", "..\..\MonoGame\MonoGame.Framework\MonoGame.Framework.iOS.csproj", "{DB8508BB-9849-4CC2-BC0F-8EB5DACB3C47}"
EndProject
Global
 GlobalSection(SolutionConfigurationPlatforms) = preSolution
  Debug|iPhoneSimulator = Debug|iPhoneSimulator
  Release|iPhoneSimulator = Release|iPhoneSimulator
  Debug|iPhone = Debug|iPhone
  Release|iPhone = Release|iPhone
 EndGlobalSection
 GlobalSection(ProjectConfigurationPlatforms) = postSolution
  {734EAA48-F1CA-481A-B391-0285BC0E8B40}.Debug|iPhone.ActiveCfg = Debug|Any CPU
  {734EAA48-F1CA-481A-B391-0285BC0E8B40}.Debug|iPhone.Build.0 = Debug|Any CPU
  {734EAA48-F1CA-481A-B391-0285BC0E8B40}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
  {734EAA48-F1CA-481A-B391-0285BC0E8B40}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
  {734EAA48-F1CA-481A-B391-0285BC0E8B40}.Release|iPhone.ActiveCfg = Release|Any CPU
  {734EAA48-F1CA-481A-B391-0285BC0E8B40}.Release|iPhone.Build.0 = Release|Any CPU
  {734EAA48-F1CA-481A-B391-0285BC0E8B40}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
  {734EAA48-F1CA-481A-B391-0285BC0E8B40}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
  {77FF5112-1227-4929-A04C-5B36E87A93D5}.Debug|iPhone.ActiveCfg = Debug|Any CPU
  {77FF5112-1227-4929-A04C-5B36E87A93D5}.Debug|iPhone.Build.0 = Debug|Any CPU
  {77FF5112-1227-4929-A04C-5B36E87A93D5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
  {77FF5112-1227-4929-A04C-5B36E87A93D5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
  {77FF5112-1227-4929-A04C-5B36E87A93D5}.Release|iPhone.ActiveCfg = Release|Any CPU
  {77FF5112-1227-4929-A04C-5B36E87A93D5}.Release|iPhone.Build.0 = Release|Any CPU
  {77FF5112-1227-4929-A04C-5B36E87A93D5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
  {77FF5112-1227-4929-A04C-5B36E87A93D5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
  {9D1AD899-582E-407D-A504-AB36062BCA1F}.Debug|iPhone.ActiveCfg = Debug|iPhone
  {9D1AD899-582E-407D-A504-AB36062BCA1F}.Debug|iPhone.Build.0 = Debug|iPhone
  {9D1AD899-582E-407D-A504-AB36062BCA1F}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
  {9D1AD899-582E-407D-A504-AB36062BCA1F}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
  {9D1AD899-582E-407D-A504-AB36062BCA1F}.Release|iPhone.ActiveCfg = Release|iPhone
  {9D1AD899-582E-407D-A504-AB36062BCA1F}.Release|iPhone.Build.0 = Release|iPhone
  {9D1AD899-582E-407D-A504-AB36062BCA1F}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
  {9D1AD899-582E-407D-A504-AB36062BCA1F}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
  {DB8508BB-9849-4CC2-BC0F-8EB5DACB3C47}.Debug|iPhone.ActiveCfg = Debug|iPhone
  {DB8508BB-9849-4CC2-BC0F-8EB5DACB3C47}.Debug|iPhone.Build.0 = Debug|iPhone
  {DB8508BB-9849-4CC2-BC0F-8EB5DACB3C47}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
  {DB8508BB-9849-4CC2-BC0F-8EB5DACB3C47}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
  {DB8508BB-9849-4CC2-BC0F-8EB5DACB3C47}.Release|iPhone.ActiveCfg = Release|iPhone
  {DB8508BB-9849-4CC2-BC0F-8EB5DACB3C47}.Release|iPhone.Build.0 = Release|iPhone
  {DB8508BB-9849-4CC2-BC0F-8EB5DACB3C47}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
  {DB8508BB-9849-4CC2-BC0F-8EB5DACB3C47}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
 EndGlobalSection
EndGlobal

Again change the path of the MonoGame project and the Lidgren.Network project to match your local installation.
Next open the solution with MonoDevelop. If you edited the path correctly you should have the MonoGame and Lidgren project there. If you entered the path wrong than just add them with add project.
Now use add project to add the project file of your game that you created before. Here also check that the reference to MonoGame is correct. So far you should only have two files in the project. The AppDelegate.cs and the Info.plist.
Now add the source code of your game to the project. Add each of your source files, except for the Program.cs. Add the source files as link, so you will use the same files for all platforms and not copies.
If everything worked fine, you should now be able to compile the source code. If you run across code that won't compile with MonoGame, you should use defines for each platform as work around.
The last step that remains is adding your content to the project. Obviously you don't have the content pipeline from the original XNA in MonoGame. But that is no problem as most content types can be read by MonoGame directly without being pre-processed. If you created the project file as described before, you already should have a Content folder inside your project. Now add all your content from the WP7 content folder there. As with the source code, you should add them as link to prevent them from being copied.
The only content file I ran across so far that is not supported, is .spritefont. To add this type of content, you have to take the compiled file from the bin/Content directory of your WP7 folder. The compiled file has the ending .xnb. Just copy the fontname.xnb to your MyGame.ios/Content folder and add this in the project instead of the original spritefont file.
For each content file in your project you have to set the option "Build action Content". Also be aware, that iOS, unlike Windows, is case sensitive to your content file names. For example, if your Content folder is upper case but in your source code you reference to lower case, you will end up in an exception at runtime.
Now you should be able to compile your game and test it on the emulator. On my MacMini the emulator runs rather slow. With an actual device, deploying, debugging and running is much better.