PureMVC in SFS2X

Post here your questions about SFS2X. Here we discuss all server-side matters. For client API questions see the dedicated forums.

Moderators: Lapo, Bax

User avatar
jpardoe
Posts: 132
Joined: 31 Aug 2009, 20:54

PureMVC in SFS2X

Postby jpardoe » 03 Nov 2010, 12:57

Introduction
First of all, if you have never heard of PureMVC, I recommend visiting the website: http://www.puremvc.org and finding out more: http://puremvc.org/component/option,com ... Itemid,31/

It has a steep learning curve, but once you have mastered it you will wonder how you ever programmed without it.

It has been developed for AS3, but ported to many other languages including Java.

I am currently incorporating the Java version of PureMVC into my SFS2X main extension.

I am doing this in the hopes that it will help to create an easily scalable and robust server-side extension that allows me to make modifications very easily, and structure the code in a manner that is easy to work with.

My AS3 client already uses PureMVC so by adding it to the server I will almost be able to mirror the game, thus adding even more continuity to development.

Whilst the purpose of this topic is to help others set up PureMVC on SFS2, I will write my thoughts with the assumption that you know a bit about it already, because otherwise it will turn into a document on PureMVC itself and I'll be here all week.

Getting Set Up
Setting up is surprisingly easy - First download the Java version of PureMVC.

There are two versions: Single Core and MultiCore. It is recommended that you use MultiCore as it's not vastly different and allows greater scalability.

Within the PureMVC zip file is a directory called "bin" - take the JAR file out of that and place it in {SFS2X dir}\SFS2X\lib\

Right click on your main project -> properties -> Libraries [tab] -> Add JAR/Folder[button].

Browse to the SFS2X lib directory and select the PureMVC JAR file.

Now you're ready to begin converting the extension to use PureMVC.

Download the example Java file here (Single Core - simpler setup): http://trac.puremvc.org/Demo_Java_J2ME_ ... /Downloads

Or for MultiCore (future proof, but more complicated to set up): http://trac.puremvc.org/Demo_Java_Multi ... /Downloads

Remember these are just example files of working PureMVC applications, so they show you how everything is structured and how PureMVC works. You can copy/paste/edit the code into the relevant places in your extension. It is ideal if you use the same package folder structure that the examples use.

If anyone is interested to know more, let me know and I'll add new updates as I progress.
Last edited by jpardoe on 04 Nov 2010, 07:07, edited 7 times in total.
User avatar
Lapo
Site Admin
Posts: 21791
Joined: 21 Mar 2005, 09:50
Location: Italy

Postby Lapo » 03 Nov 2010, 17:30

Interesting! I don't know PureMVC, could you explain what are the advantages of using it on the server side?
To be honest it sounds a bit strange to use an MVC approach on the server side where there is no V (iew) :)

Thanks for posting!
Lapo
--
gotoAndPlay()
...addicted to flash games
User avatar
jpardoe
Posts: 132
Joined: 31 Aug 2009, 20:54

Postby jpardoe » 04 Nov 2010, 04:53

Ah but there is a 'V'! It's the client! Therefore the View handles all inputs/outputs to/from the client.

To be honest I haven't figured it all out yet, so whether PureMVC is practical or not on the server-side I can't say. But in principle it will help to structure the code, an enable huge expandability without everything becoming 'spaghetti'.
User avatar
Lapo
Site Admin
Posts: 21791
Joined: 21 Mar 2005, 09:50
Location: Italy

Postby Lapo » 04 Nov 2010, 06:39

Sure, makes sense.
Keep us posted about your findings :)
Lapo

--

gotoAndPlay()

...addicted to flash games
ThomasLund
Posts: 1297
Joined: 14 Mar 2008, 07:52
Location: Sweden

Postby ThomasLund » 04 Nov 2010, 07:59

We have been using a MVC like approach in an online and local game.

The view is obviously the game client rendering part. Primarily taking input (click events in the 3d world) and then displaying the output (sound, models that move in the world to other coordinates, playing combat results etc)

The model is a datamodel and all logic surrounding it. So e.g. the client has clicked on a position in the 3d world and issued an "move unit X to position Y please" request. The model then take this, applies it to the data model and returns a "move ok" response.

So that part could be seen as a classic autoritative server setup.

But in comes the controller. The controller sits on the client and on startup (based on user selection in the startup menu) can either redirect all requests to the SFS server (in multiplayer) or start up a in-client model representation for single player. The controller simply redirects all requests to the local model suddenly instead of over tcp/sfs api.

This also enables us to record all requests/responses going through the controller, and thus have a place to record gameplay + inject fake responses/requests from a recording to replay a game.

So MVC _can_ be used in most useful ways with a little creativity

/Thomas
Haniman
Posts: 35
Joined: 02 Sep 2009, 22:52

Postby Haniman » 04 Nov 2010, 08:06

Hey i am using PureMVC for my Flashclient and it works really well and all is nice capsulated.

It helps a lot to make reusable components, but i dont really see the adantage for using it on the Serverside, because there is no view for the Model, View, Controlled prinzip.

An advatage would may the easy passibility to send messages around and let the controllers do something.

So i think its to much overhead but if you try and its good ill will may be follow you :D
User avatar
jpardoe
Posts: 132
Joined: 31 Aug 2009, 20:54

Postby jpardoe » 04 Nov 2010, 08:36

Haniman, As I said previously, when using MVC on the server-side, the View should be considered the client. The models store the server data, and the controllers issue the commands.

I have made a few changes to the standard PureMVC setup to account for SFS2X's way of working. The two combined appear to create a very robust and easily workable server-side that can handle expansion very easily.

Haniman, You said that overhead could be an issue - I am unsure of this, I think that PureMVC is pretty light-weight and the benefits of development and added server functionality surely outweigh that. Let me know if you feel otherwise.

I am still not at a stage to definitively say "Yes, this works" - I will continue to develop the server-side and see how things progress.

I'll keep you updated!
Haniman
Posts: 35
Joined: 02 Sep 2009, 22:52

Postby Haniman » 04 Nov 2010, 08:54

Ah ok i read over the client - view thing.

Hmm yeah sound interesting. I like PureMVC so give it a try. :)


I still trying to get the new server to work...
May be then will try too.
User avatar
jpardoe
Posts: 132
Joined: 31 Aug 2009, 20:54

Success

Postby jpardoe » 04 Nov 2010, 15:03

Well I have successfully managed to get PureMVC working on SFS2X, and so far I've been able to add custom functionality that is far more structured and controllable than SFS2X on its own (although, kudos to SFS2X; it's a vast improvement over SFS1...I doubt PureMVC would even be possible with that!).

So without further ado, here is the basic code you'll need to get going:
User avatar
jpardoe
Posts: 132
Joined: 31 Aug 2009, 20:54

Postby jpardoe » 04 Nov 2010, 15:04

ExtensionShell.java: This is the main extension that is specified in the Admin control panel.

Code: Select all

package com.domain;


import com.smartfoxserver.v2.core.SFSEventType;
import com.smartfoxserver.v2.extensions.SFSExtension;

/**
 *
 * @author James Pardoe
 */
public class ExtensionShell extends SFSExtension {

    public static String ZONE = "ZoneName";
   
    public ServerFacade serverFacade;

    @Override
    public void init()
    {
        // Create a new PureMVC instance
        // Pass a reference of this extension to the instance to enable
        // communication with the server (See ServerMediator.java)
        serverFacade = ServerFacade.getInstance(this);
        serverFacade.startup();
    }

    public void addHandler(SFSEventType eventType, Class<?> theClass)
    {
        addEventHandler(eventType, theClass);
    }

    @Override
    public Object handleInternalMessage(String cmdName, Object params)
    {
        serverFacade.sendNotification(cmdName, params);

        return null;
    }
}

User avatar
jpardoe
Posts: 132
Joined: 31 Aug 2009, 20:54

Postby jpardoe » 04 Nov 2010, 15:07

ServerFacade.java: This is where most of the notifications are registered and the main initialisation code:

Code: Select all

package com.domain;

import com.domain.controller.ErrorCommands;
import com.domain.controller.StartupCommand;
import com.domain.controller.UniverseCommands;
import com.smartfoxserver.v2.extensions.SFSExtension;
import lib.Notifications;
import org.puremvc.java.multicore.patterns.facade.Facade;

/**
 *
 * @author James Pardoe
 */
public class ServerFacade extends Facade {

    public static String CORE = "MainExtension";
    public static final String NAME = "ServerFacade";

    public static SFSExtension extension = null;

    /**
     * Unique instance.
     */
    private static ServerFacade instance = null;

    /**
     * Constructor.
     */
    protected ServerFacade() {
        super(NAME);
    }

    /**
     * get the instance.
     * @return the singleton
     */
    public static ServerFacade getInstance(SFSExtension ext) {
        extension = ext;
        if (instance == null) {
            // nuke the multiton so we can do the recompile
            if (ServerFacade.hasCore(NAME)) {
                ServerFacade.removeCore(NAME);
            }
           
            instance = new ServerFacade();
        }
        return instance;
    }

    /**
     * Start the application.
     */
    public final void startup() {
         sendNotification(Notifications.STARTUP);
     }

    /**
     * Initialize controller. Register the commands.
     */
    @Override
    protected final void initializeController() {
        super.initializeController();
        registerCommand(Notifications.STARTUP, new StartupCommand());
        registerCommand(Notifications.QUERY_ERROR, new ErrorCommands());
        registerCommand(Notifications.SEND_DATA, new ServerCommands());
    }
}

Last edited by jpardoe on 04 Nov 2010, 15:12, edited 1 time in total.
User avatar
jpardoe
Posts: 132
Joined: 31 Aug 2009, 20:54

Postby jpardoe » 04 Nov 2010, 15:11

ServerMediator.java Handles the messages to and from the client:

Code: Select all

package com.domain.view;

import com.domain.ExtensionShell;
import com.domain.ServerFacade;
import com.domain.model.ServerProxy;
import com.smartfoxserver.v2.core.SFSEventType;
import com.domain.eventhandlers.LoginEventHandler;
import com.domain.eventhandlers.ZoneEventHandler;
import lib.Notifications;
import org.puremvc.java.multicore.interfaces.INotification;
import org.puremvc.java.multicore.patterns.mediator.Mediator;

/**
 *
 * @author James
 */
public class ServerMediator extends Mediator
{
    public static final String NAME = "ServerMediator";

    /**
     * Reference to the user proxy.
     */
    private ServerProxy serverProxy = null;

    public ServerMediator()
    {
        super(NAME, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final void onRegister() {
        serverProxy = (ServerProxy) getFacade().retrieveProxy(ServerProxy.NAME);

        // Register for login event
        getExtension().addHandler(SFSEventType.USER_LOGIN, LoginEventHandler.class);
        getExtension().addHandler(SFSEventType.USER_JOIN_ZONE, ZoneEventHandler.class);

        getExtension().trace("extension working with PureMVC");

        super.onRegister();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final String[] listNotificationInterests() {
        return new String[] {
            Notifications.USER_DATA,
            Notifications.SEND_ITEMS
        };
    }

    @Override
    public void handleNotification(INotification note)
    {
        String name = note.getName();
        Object body = note.getBody();

        if(name.equals(Notifications.USER_DATA))
        {
            // Do something
        } else if(name.equals(Notifications.SEND_ITEMS))
        {
            // Do something else
        }

        super.handleNotification(note);
    }

    private ExtensionShell getExtension(){
        return (ExtensionShell) ServerFacade.extension;
    }
}

User avatar
jpardoe
Posts: 132
Joined: 31 Aug 2009, 20:54

Postby jpardoe » 04 Nov 2010, 15:15

ServerProxy.java Used to store server data. You can probably tell I haven't got to this yet:

Code: Select all

package com.domain.model;

import org.puremvc.java.multicore.patterns.proxy.Proxy;

/**
 *
 * @author James Pardoe
 */
public class ServerProxy extends Proxy
{
    public static final String NAME = "ServerProxy";

    public ServerProxy()
    {
        super(NAME, new Hashtable());
    }
}

User avatar
jpardoe
Posts: 132
Joined: 31 Aug 2009, 20:54

Postby jpardoe » 04 Nov 2010, 15:17

StartupCommand.java Used to register the proxies and mediators:

Code: Select all

package com.domain.controller;

import com.domain.model.ServerProxy;
import com.domain.view.ServerMediator;
import lib.Notifications;
import org.puremvc.java.multicore.interfaces.IMediator;
import org.puremvc.java.multicore.interfaces.INotification;
import org.puremvc.java.multicore.patterns.command.SimpleCommand;

public class StartupCommand extends SimpleCommand
{
    /**
     * Register mediator and proxy.
     * @param notification notification
     */
    @Override
    public final void execute(final INotification notification) {
        getFacade().registerProxy(new ServerProxy());

        getFacade().registerMediator((IMediator) new ServerMediator());

        // Remove the command because it will never be called more than once
        getFacade().removeCommand(Notifications.STARTUP);
    }
}

User avatar
jpardoe
Posts: 132
Joined: 31 Aug 2009, 20:54

Postby jpardoe » 04 Nov 2010, 15:21

ErrorCommands.java An example Command used to dispatch an error message to the client:

To dispatch an error, you would do like so:

Code: Select all

} catch (SQLException ex) {
    GameObject errorData = new GameObject ();

    errorData.putString("msg", "Unable to perform database query");
    errorData.putUser("user", user);

    sendNotification(Notifications.QUERY_ERROR, errorData);
}



Code: Select all

package com.domain.controller;

import com.domain.ExtensionShell;
import com.domain.ServerFacade;
import com.domain.data.GameObject;
import com.smartfoxserver.v2.entities.User;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;
import lib.Notifications;
import org.puremvc.java.multicore.interfaces.INotification;
import org.puremvc.java.multicore.patterns.command.SimpleCommand;

public class ErrorCommands extends SimpleCommand
{
    /**
     * Register mediator and proxy.
     * @param notification notification
     */
    @Override
    public final void execute(final INotification note) {
        String name = note.getName();
        GameObject body = (GameObject ) note.getBody();

        if(name.equals(Notifications.QUERY_ERROR)){
            getExtension().trace("\n\nERROR: " + body.getString("msg") + "\n\n");
           
            ISFSObject params = SFSObject.newInstance();
            params.putUtfString("msg", (String) body.getString("msg"));
            getExtension().send(Notifications.QUERY_ERROR, params, (User) body.getUser("user"));
        }
    }

    private ExtensionShell getExtension(){
        return (ExtensionShell) ServerFacade.extension;
    }
}


Return to “SFS2X Questions”

Who is online

Users browsing this forum: DavinVicy, DerikFent, Kevengar and 32 guests