Monday, May 16, 2011

Character creation Part 2 - SmartFoxServer Extension

Just to start out with, we need to go ahead and add in the character id to the message sent to the client with the character list. To do this we go into [GameName]Character in the models package and add in the following line to the createSFSObject function:


        data.putLong("id", character.getId());

This now gets us the data we need on the client for when we select our character. While we are in the file we can go ahead and add the code to the loadFromSFSObject function:

    public void loadFromSFSObject(ISFSObject data) 
    {
        character.setLevel(BigInteger.valueOf(1));
        character.setPositionX(BigInteger.ZERO);
        character.setPositionY(BigInteger.ZERO);
        character.setCreatedAt(new java.util.Date());
        character.setUpdatedAt(new java.util.Date());
        
        for(String key : data.getKeys())
        {
            if(key.equalsIgnoreCase("characterName"))
                character.setName(data.getUtfString("characterName"));
            if(key.equalsIgnoreCase("sex"))
                character.setSex(data.getUtfString("sex"));
            if(key.equalsIgnoreCase("characterClass"))
                character.setClass1(data.getUtfString("characterClass"));
        }
    }

This just gets our data from our packet and fills in the character. Next we need to add the code to pass the message to a handler that will do something with this data after calling the function. So in [GameName]Extension.init add to the list of handlers:

        addRequestHandler("createCharacter", CharacterCreationHandler.class);

Next we need to create our handler:

public class CharacterCreationHandler extends BaseClientRequestHandler {

    @Override
    public void handleClientRequest(User u, ISFSObject data)
    {
        World world = RoomHelper.getWorld(this);
        [GameName]Account player = world.getPlayer(u);
        if (player.canAddCharacters())
        {
            EntityManager entityManager = (([GameName]Extension) this.getParentExtension()).getEntityManagerFactory().createEntityManager();
            entityManager.getTransaction().begin();
            [GameName]Character character = new [GameName]Character(new domain.domainname.gamename.persistence.[GameName]Character());
            character.loadFromSFSObject(data);

            Query q = entityManager.createNamedQuery("[GameName]Character.findByName");
            q.setParameter("name", character.getCharacter().getName());
            try
            {
                q.getSingleResult();
                SFSObject err = new SFSObject();
                err.putUtfString("error", "That name is taken.");
                send("error", err, u);

            }
            catch(NoResultException e)
            {
                SfGuardUser guard = entityManager.find(SfGuardUser.class, player.getGuardID());
                character.getCharacter().setUserId(guard);
                // No character with that name, go ahead and create it!
                entityManager.persist(character.getCharacter());
                entityManager.flush();
                entityManager.getTransaction().commit();
                send("characterCreated", new SFSObject(), u);
            }
        }
        else
        {
            SFSObject err = new SFSObject();
            err.putUtfString("error", "No empty character slots.");
            send("error", err, u);
        }
    }
}
This code begins by getting our entity manager and calling the loadFromSFSObject to create our character object. After that we check to see if the name is already used and if so, send back an error response. If we get a NoResultException it means that name is not in use and we can go ahead and persist the character. From there we send the response back to the client saying we created the character.

This concludes Character creation. Next time we will be covering our simple character select screen and getting us over to the game itself. Almost there!

2 comments:

Anonymous said...

Hello Dragagon

i have some errors when using the code on Github.

1. when i press create button in Unity server returns this error
03:57:39,088 INFO [com.smartfoxserver.v2.controllers.ExtensionController-1] Ext
ensions - {RfaExtension}: loading characters
03:57:52,401 ERROR [com.smartfoxserver.v2.controllers.ExtensionController-1] con
trollers.ExtensionController -
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Exception: javax.persistence.PersistenceException
Message: org.hibernate.PropertyValueException: not-null property references a nu
ll or transient value: org.dyndns.evers3d.persistence.RfaCharacter.sfGuardUser
Description: Error while handling client request in extension: { Ext: RfaExtensi
on, Type: JAVA, Lev: ZONE, { Zone: RFA }, {} }
Extension Cmd: createCharacter
+--- --- ---+
Stack Trace:
+--- --- ---+
org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEn
tityManagerImpl.java:637)
org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.ja
va:226)
org.dyndns.evers3d.handlers.CharacterCreationHandler.handleClientRequest(Charact
erCreationHandler.java:58)
com.smartfoxserver.v2.extensions.SFSExtension.handleClientRequest(SFSExtension.j
ava:192)
com.smartfoxserver.v2.controllers.ExtensionController.processRequest(ExtensionCo
ntroller.java:137)
com.smartfoxserver.bitswarm.controllers.AbstractController.run(AbstractControlle
r.java:96)
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
java.lang.Thread.run(Unknown Source)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

2. in CharacterCreationHandler.java on line 56 method GetUserId is not defined..

Waiting for your response,
Thanks

Unknown said...

1) it is complaining that there is no sfGuardUser associated with the RfaCharacter while trying to save. so it sounds like you missed the line of code where we take the sfGuardUser and assign it to the newly created character before attempting to persist it.

2) I don't make a call to GetUserID. Are you sure it wasn't changed from either getGuardID or setUserID. I don't see where I made a call to getUserID anywhere in that function.