Wednesday, December 15, 2010

Unity3D SmartFoxConnection and Connection Handler

Last time we left off, we put together our base extension and installed it into SmartFoxServer. This time we will be building our initial classes for Unity3D. So lets start by opening up the project we created earlier.

We'll start by making a few folders in the project view. We are going to create 4 base folders, Scenes, Common, Plugins, and Lobby. Under Common and Lobby we will create a folder called Scripts.

Now that our initial folder structure is created lets go ahead and save our scene to the scenes directory. I just call it Lobby to keep it simple.

Before we start working with SmartFoxServer we need to include the Unity3D SmartFox2.dll. Open an explorer window to [SFSInstallDir]\Client\Unity. You will see a file called SmartFox2.dll. Drag this file into Unity and put it in the Plugins directory you created.

Next we will create our SmartFoxConnection. This will be a singleton that will hold our connection no matter what scene we are on. Go ahead and create a C Sharp Script under Common\Scripts and call it SmartFoxConnection. It will contain the following:

using UnityEngine;
using Sfs2X;


// Statics for holding the connection to the SFS server end
// Can then be queried from the entire game to get the connection


public class SmartFoxConnection : MonoBehaviour
{
    private bool debug = true;
    private static SmartFox smartFox;


    public static SmartFox GetInstance()
    {
        if(smartFox == null)
        {
           smartFox = new SmartFox(debug);
        }
        return smartFox;
    }
}

So this sets up our singleton. For more information on the singleton pattern, go here.


Now, here is where i have a personal pet peeve. I hate reading tutorials where people don't take the time to make objects. They create a class that isn't reusable. They figure that by providing people with a chunk of code that they will just naturally learn to use patterns. So instead of just giving you the code we are going to go through some initial design to make our lives easier in the future.

Next we want to create another C Sharp Script in Common\Scripts and we will call it ConnectionHandler. Open it up in your editor and replace everything with the following:


using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using Sfs2X.Core;
using Sfs2X.Entities.Data;
using UnityEngine;
using Sfs2X;


public class ConnectionHandler : MonoBehaviour
{
}
We are starting with it empty so that I can discuss each piece as we run across it. To start, you will see a ton of references. These will be explained as we use them.

Between the braces go ahead and add :

    protected SmartFox smartFox;
    public bool debug = true;
This gives us a reference to SmartFox which is how we send our messages. Next we need to code our standard messages and functions for those messages - add the following below the 2 variables we added:
    protected void Awake()
    {
        Application.runInBackground = true;
        smartFox = SmartFoxConnection.GetInstance();
    }
This code tells the application that this script will be running the background. This means that even when you have your application minimized that this script will run. This is necessary so that we don't get a backlog of messages while our application doesn't have focus. Secondly we check to see if SmartFox is initialized and if so it gets the SmartFox connection. If it doesn't, it creates a new instance of it and puts it into debug mode. Realistically it will always get a connection.

Next we add our update function. Normally if you are used to using unity3d we use Update(). In this case we are going to use FixedUpdate(). The difference is that no matter what our frame rate it will always call FixedUpdate() at a fixed interval so it isn't dependent on graphics rendering. Again this is a necessity when dealing with messages.
    protected void FixedUpdate()
    {
        smartFox.ProcessEvents();
    }

Next we will create a function that will be used when switching scenes or when logging off or being disconnected.

    protected void UnregisterSFSSceneCallbacks()
    {
        // This should be called when switching scenes, so callbacks from the backend do not trigger code in this scene
        smartFox.RemoveAllEventListeners();
    }

Next we want to create a function that will be called any time we are quitting. A forum post comments that unless you disconnect the client on the application close it will error out if you instantly try running again.
    protected void OnApplicationQuit()
    {
        if (smartFox.IsConnected)
        {
            UnregisterSFSSceneCallbacks();
            smartFox.Disconnect();
        }
    }

With me so far? Good. For now we are done with ConnectionHandler. It doesn't look like much, just your typical setup. But the nice thing is that now we don't every have to write this code ever again. This post is getting long so I'll put a break in here. Next post I'll cover our LobbyGUI which will present our user with an initial login screen we will be using.

SmartFoxServer Game Extension

So now we have the basis for our server and client from end to end. We have our dev environment which encompasses Unity3D, NetBeans, and either Visual Studio or Mono Develop. We are now to the point where we need to create our extension. This part starts easy and is quickly expandable.

Open NetBeans and head over to your [GameName]Extension project. First create your package. In my last post I said it should be created as domain.domainname.gamename.entities. For our extension I create a base package called domain.domainname.gamename and this is where we will put our extension class.So:

  1. Right click on Source Packages and hit New -> Java Package.
  2. Type in the full name. Again I am using com.cjrgaming.aegisborn for my game.
  3. Click Finish.
  4. In the new package, right click and New -> Java Class...
  5. Give it the name of your game. For example [GameName]Extension.
  6. Click Finish.
This gives you your new class where we will put in the functions and handlers to deal with our new game. The first thing you want to do is append extends SFSExtension between the classname and the {.

Next we will create the init function:
@Override
public void init()
{
}
Thats all there is to it. Just an empty init function. We will fill this in later with our handlers and entity manager. Now is the time to make note of our package structure and extension name. We will be filling it into the Smart Fox Server information in just a bit.


First we need to right click our [GameName]Extension project and hit Build. Then we need to go to our project's folder, go into the dist folder and copy out the [GameName]Extension.jar file.


Go to [SFSInstallDir]\SFS2X\extensions and create a new directory called [GameName]Extension and place the [GameName]Extension.jar file in it.


Next log into the SmartFoxServer web management page (normally located at http://localhost:8080/admin ). Log into the server and go to Zone Configurator. Below the Zone section click the little green circle with the + and the second half of the window will appear.

  1. Enter [GameName] for the zone
  2. Click the Zone extension tab.
  3. In name put [GameName]Extension - this is the name of the folder containing your jar file.
  4. In File put domain.domainname.gamename.[GameName]Extension - i.e. com.cjrgaming.aegisborn.AegisBornExtension
  5. Click Submit at the bottom
There, now we have our extension with our java file loaded. Lets go ahead and create a general chat area.

  1. Select the zone [GameName]
  2. click the green button with the + sign under Rooms
  3. Give it a room name, i.e. General
  4. Leave everything else alone except the drop down for Auto-remove mode use NEVER_REMOVE.
  5. Click Submit
We now have a room called General under our new zone. The room is permanent and won't go away, this is good for general chat rooms that will be accessible to everyone for things like system messages or if you want a world wide chat in your game.

Now you need to restart the server to get the changes to take effect. Thats all for this tutorial. We now have our server ready and waiting for any connections to be made to it. Next up, Login and joining a room from unity3d.

SmartFoxServer Entity Library

If you've been with me so far we have installed our dev environment, created our projects, started our server and created our database and web application to allow users to be created. The next step is important as we are going to create our entities in [GameName]Entities. This is the last step before we begin messages between the client and the server.

So we need to open NetBeans and go to our [GameName]Entities project and get started. First we need to connect NetBeans with our database.

  1. Click the tab that says Services
  2. Right click on Databases and click New Connection.
  3. A new window will appear. Click in the drop down and select MySQL (Connector/J Driver)
  4. Hit Next
  5. leave the host as localhost
  6. Update the database to be your database name
  7. Update the user and password to the user and password you created in part 6.
  8. Click Next then finish.
That gives us our database connection we will need to create the entities in our project. Up next is the actual creation of those entities.

  1. Right click on source packages and select New... -> Entity Classes from Database
  2. If Entity Classes from Database is unavailable click Other...
  3. Under the selection Persistence is Entity Classes from Database. select it.
  4. A new window will appear and will have a drop down. If it doesn't already contain your database, click it and select your database connection you created.
  5. The window will load all the tables in your database. For now you only need to add the classes [game_name]_account and sf_guard_user. 
  6. click Next
  7. Update the Package. The standard package convention is to list it as domain.domainname.gamename.entities. So for mine i did com.cjrgaming.aegisborn.entities.
  8. Leave the rest of the default selections and Click finish.
This will have created 2 packages, one called META-INF and another which is your package above like mine.

Now you can right click on the [GameName]Entities project and click Build which will build a jar file. Now we can put that into our SmartFoxServer. Navigate in an explorer window to your project. In the dist folder is a jar file called [GameName]Entities.jar. Copy this file into [SFSInstallDir]\SFS2X\lib. And lastly you will want to go to your [GameName]Entities\src folder and copy the META-INF folder into [SFSInstallDir]\SFS2X.

This concludes this tutorial. We are now completely set up and ready for the messaging between the server and client.

Tuesday, December 14, 2010

Symfony Guard and myUser

Last time we left off with the registration and login pages, but our application would die because we didn't have our database set up. So this time around we are going to add our account class, put together all the database tables and register our first user.

Editing the myUser class

So before we begin, we need to first update our myUser. So we will begin in NetBeans.

  1. Open apps\frontend\lib\myUser.class.php
  2. Update extends to be extends sfGuardSecurityUser
Simple enough. Now we need to update our settings to state that we can use the User plugin.

  1. Open apps\frontend\config\settings.yml
  2. Your .all section should have an enabled_modules. Within the [] add sfGuardAuth, sfGuardRegister, sfGuardForgotPassword
  3. under all of .settings, at the end of the file add the following:
    .actions:
      login_module:    sfGuardAuth
      login_action:    signin


      secure_module:   sfGuardAuth
      secure_action:   secure
YAML files are sensitive to spacing, so make sure the .actions is lined up with .settings and that the modules/actions are spaced in to the same distance.


Creating the Account Table

The biggest reason I use symfony can be demonstrated here with the creation of tables. You modify one file and run a command and you get tables, objects, and accessors for those objects. It complements the DRY principle I strive to uphold. This same functionality lends itself well to the [GameName]Entities project as we will see after we finish this session.

So in NetBeans in the [GameName] project we want to open the config\doctrine\schema.yml for now we will add a single table, again, mind the spacing in the code submitted as it greatly affects how your tables will turn out.

[GameName]UserProfile:
  actAs: { Timestampable: ~ }
  columns:
    user_id: {type: integer, notnull: true }
    character_slots: {type: integer, default: 1}
  relations:
    sfGuardUser:
      type:           one
      foreignType:    one
      class:          sfGuardUser
      local:          user_id
      foreign:        id
      onDelete:       cascade
      foreignAlias:   Profile
Be sure you update [GameName] to be your game name. In reality if you are forming a company and plan on having many games on your site you may want to update [GameName] to be your [SiteName] or [CompanyName]. The character_slots is just additional information that will be sent to our client in another tutorial when we cover messages to the client.


Save all the edited files if you havn't already.

First we will want to create our database, create a user, then tell symfony what the configuration is. So open the XAMPP control panel and click admin next to MySQL. Make sure Apache and MySQL are running before doing this. It will open a browser window to phpMyAdmin using the default login/pw root with no password.

In the new browser page you will see a box to Create new Database. Enter a name into the field, leave the collation where it is and click Create. It will take you to a new page with a success message. Click the button that looks like a house in the upper left to return to the beginning screen. Click the tab marked Privileges. Click the link that says Add a new User. Enter a username, leave the host blank, then enter a password in the next 2 fields. Don't change any other values, just click Go. This should show another success message. Scroll down to Database Specific Privileges and select the table you just created. Check the boxes SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, and DROP and click Go.

This will give you a user with permission to do everything symfony needs.

Open a command window and go to [XAMPPInstallDir]\[GameName] and enter the following command:


symfony configure:database "mysql:host=localhost;dbname=[DatabaseName]" [DBUser] [DBPassword]


symfony doctrine:build --all


this will display a confirmation to rebuild the databases and after you say y should go into creating all the objects and tables and get you ready for what is next.


Load up the page again and go into the registration form and create your first user. If you do this and then go into the phpMyAdmin you can click your database and see a list of the tables. Your sf_guard_user table should now have a single record, if you click on that, you will see your newly created user.


After registration you probably received an error in your browser. That is because you don't have a module called game with an action of index. Lets take care of that real quick.

  1. Create a new folder under apps\frontend\modules called game.
  2. Under game create 3 folders called actions, config, templates
  3. In the config folder create a new file called security.yml with the following code
default:
  is_secure: true
This will secure this module so the user must be logged in to access it. If they aren't, they will be redirected to the login page.

  1. In the actions folder create a file called actions.class.php and put in the following code:




<?php


/**
 * index actions.
 *
 * @package    AegisBorn
 * @subpackage index
 * @author     Your name here
 */
class gameActions extends sfActions
{
 /**
  * Executes index action
  *
  * @param sfRequest $request A request object
  */
  public function executeIndex(sfWebRequest $request)
  {
      $characters = $this->getUser()->getGuardUser()->getCharacters();
      if($characters->count() < 1)
      {
          $this->redirect('new_character');
      }
      $this->current_character = $this->getUser()->getGuardUser()->getCurrentCharacter();
  }
}

  1. Lastly we will create indexSuccess.php under templates:
<H1>[GameName]</H1&tg;


Logged in. Home page.


This completes this tutorial part. We can now create a user and log them in.

Symfony Registration and Login

So we have an initial setup for a working dev environment for people wishing to combine Symfony, Unity3d, and SmartFoxServer. Next we need some data and the best thing for that is a login and registration system for users.

Hopefully by this point you have read Chapter 3 from the Symfony book. It would also be helpful to skim through Chapter 13. We are going to use SfDoctrineGuard to lock down our site and provide us with user login capabilities. This post may get a little lengthy as it takes a bit of work to get through.

First there are 2 methods to get a hold of SfDoctrineGuard. I will describe both, but they are both run through Chapter 13.

Downloading and installing the plugin manually

  1. You need to go to this site and download the package. 
  2. Extract the package to [XAMPPInstallDir]\[GameName]\plugins
  3. rename SfDoctrineGuardPlugin-5.0.0 to SfDoctrineGuardPlugin
  4. In NetBeans in the [GameName] project go to open up config\ProjectConfiguration.class.php
  5. Add the following to the setup() above the setWebDir call:
  6. $this->enablePlugins('sfDoctrinePlugin');
  7. $this->enablePlugins('sfDoctrineGuardPlugin');
Using Symfony to install it for you

  1. Open a command prompt to [XAMPPInstallDir]\[GameName]
  2. type symfony plugin:install SfDoctrineGuardPlugin
Configuring our modules

So now we need to configure our modules. We are going to start with just the intro module. It'll be our web application's front end that includes user registration and login. Chapter 3 covers generation of modules but they generally contain way more stuff than we need.

  1. In NetBeans in the [GameName] project we need to go into apps\frontend\modules and create a folder called intro.
  2. Under the intro folder we need to create 2 more folders: actions and templates
  3. in the actions folder create a new php file actions.class.php
  4. Open actions.class.php and add the following code:

/**
* intro actions.
*
* @package [GameName]
* @subpackage intro
* @author Your name here
*/
class introActions extends sfActions
{
  /**
  * Executes index action
  *
  * @param sfRequest $request A request object
  */
  public function executeIndex(sfWebRequest $request)
  {
    $user = $this->getUser();
    if ($user->isAuthenticated())
    {
      return $this->redirect('@game_index');
    }


    $this->login_form = new sfGuardFormSignin();


    $this->registration_form = new sfGuardRegisterForm();
  }

}

This class gets the user, if the user is already logged in it redirects to game_index which we will define in a moment. If they aren't logged in the registration form and login form are loaded into the template and are shown to the user.

Now we need to define @game_index so open up apps\frontend\config\routing.yml and we will be changing a few things. 

#homepage
homepage:
  url:   /
  param: { module: intro, action: index }
#game_index
game_index:
  url:   /home
  param: { module: game, action: index }
#SFGuard
sf_guard_signin:
  url:   /login
  param: { module: sfGuardAuth, action: signin }

sf_guard_signout:
  url:   /logout
  param: { module: sfGuardAuth, action: signout }

sf_guard_register:
  url:   /register
  param: { module: sfGuardRegister, action: index }

sf_guard_password:
  url:   /request_password
  param: { module: sfGuardAuth, action: password }

Updating homepage forces the web application to load to that module/action when you first go to the page.

Now we need the template to display when the user opens that page. Create a new file called indexSuccess.php under apps\frontend\modules\intro\templates. This file should contain the following:



<?php use_helper('I18N') ?>
<div class="login_form">
    <form action="<?php echo url_for('@sf_guard_signin') ?>" method="post">
        <table>
            <tbody>
                <?php echo $login_form ?>
            </tbody>
            <tfoot>
                <tr>
                    <td colspan="2">
                        <input type="submit" value="<?php echo __('Signin', null, 'sf_guard') ?>" />


                        <?php $routes = $sf_context->getRouting()->getRoutes() ?>
                        <?php if (isset($routes['sf_guard_forgot_password'])): ?>
                            <a href="<?php echo url_for('@sf_guard_forgot_password') ?>"><?php echo __('Forgot your password?', null, 'sf_guard') ?></a>
                        <?php endif; ?>
                    </td>
                </tr>
            </tfoot>
        </table>
    </form>
</div>
<div class="register_form">
    <form action="<?php echo url_for('@sf_guard_register') ?>" method="post">
        <table>
            <?php echo $registration_form ?>
            <tfoot>
                <tr>
                    <td colspan="2">
                        <input type="submit" name="register" value="<?php echo __('Register', null, 'sf_guard') ?>" />
                    </td>
                </tr>
            </tfoot>
        </table>
    </form>
</div>

This takes the forms we passed in, login and register, and creates 2 forms that will redirect the user to the SfDoctrineGuardPlugin when you click submit. If you reload your browser you should now see 2 forms that look totally unformatted but function very well. You can continue to play with the styles and html or you can read Chapter 4 about the controller and view.

Now, you probably tried to create a user and it died horribly. Thats because we now need to set up the database. Which I will cover in Part 6.

Unity3D Install

Last time we left off with Creating our Java projects that we will use for Persistence and our Smart Fox Server Extension.

Unity 3D and our Client code

Up next we need to install Unity3D. Again, I just follow the default install with nothing special. This places Unity3D in C:\Program Files (x86)\Unity on x64 Windows machines and in C:\Program Files\Unity on 32 bit machines. From now on I will use [UnityInstallDir] to reference this directory.

When you first open up Unity 3D you will have to "register" or use the 30 trial of Professional. Personally I register and get the free version. The differences are Professional gives you some more nice water effects, engine culling, and some other nifty features. Nothing contained in these tutorials will be using the Professional version as I want this to be as free as possible.

Now that you are in the actual program you need to create a new project. I call mine AegisBorn3d and put it on my development drive. There are several Fantastic tutorials on Unity3D.

3dBuzz: http://www.3dbuzz.com/vbforum/showthread.php?181409-Over-7-hours-of-Unity-Training-Videos-Download-them-now...
BurgZergArcade: http://www.burgzergarcade.com/hack-slash-rpg-unity3d-game-engine-tutorial

And many more if you take the time to google for them.

This sets up our Unity 3D project. So for a running total of 4 projects. [GameName]3d (Unity3d), [GameName] (php), [GameName]Entities (Java), and [GameName]Extension (Java).

Next Time I'll cover our code to connect to Smart Fox Server from Unity3D.

SmartFoxServer Project Creation - Extension and Entity

Last time we left off we now had a working web server and had Smart Fox Server up and running with OpenJPA ready to be used. Now we are going to cover setting up our Java Extension for Smart Fox Server.

Creating our Extension and Entity Projects

Start by opening Netbeans. Here we will want to create 2 new Java Class Libraries.

We don't care where these projects are. I name them [GameName]Entities and [GameName]Extension.

So now you will have 3 projects, [GameName] (php), [GameName]Entities and [GameName]Extension (java). Next we need to reference a new library set. Open up the [GameName]Entities project and right-click Library and click Properties. The compile tab will start empty:
  1. Click Add Library...
  2. Click Create...
  3. Name it SmartFoxServer and leave it as Class Libraries type.
  4. Click OK.
  5. Click Add JAR/Folder...
  6. Navigate to [SFSInstallDir]\SFS2X\lib and select sfs2x.jar and sfs2x-core.jar
  7. Hit Add JAR/Folder to close the window.
  8. Hit Add JAR/Folder...
  9. Navigate to [OpenJPADir] and select openjpa-all-2.0.1.jar
  10. Hit Add JAR/Folder to close the window.
  11. Hit Add JAR/Folder...
  12. Navigate to [OpenJPADir]\lib and select ALL .jar files
  13. Hit Add JAR/Folder to close the window.
  14. Hit OK to create the library.
  15. Scroll through the list of Available Libraries and select SmartFoxServer
  16. Hit Add Library to close this window.
  17. Click OK to close the project properties window.
You will want to follow steps 1, 15, 16, and 17 and select both SmartFoxServer and MySQL JDBC Driver.
Before you close the Project Properties window for the Extension project, you will also want to click Add Project and navigate to your [GameName]Entities project and click Add Project JAR Files.

This will give you the setup you will use for your entities and extension in Smart Fox Server.