Wednesday, May 11, 2011

Preparing for character creation - [GameName]Account changes

So I have migrated my code from OpenJPA to Hibernate. I then tested my code to create a character and it works, but there was a catch. Because of earlier tutorials, we were taking the SfGuardUser and caching them in our Account class. Then we were taking the characters listed in the GuardUser.[GameName]CharacterCollection and passing those to the client. The problem is that when you create a new character, that data needs to be refreshed as it is now stale. This was also taking up a large chunk of memory for something we only used a few pieces of data from - MaxCharacters, number of characters, and the list of characters. So rather than keep all that data, I have modified the Account class to only keep the data we need.

So lets begin. First I removed the SfGuardUser property and the getSfGuardUser() method. I updated the name of setSfGuardUser(SfGuardUser guard) to setSfGuardUserValues(SfGuardUser guard). I then created 3 new properties and getters for those properties:
    private long guardID;
    private int maxCharacters;
    private int numCharacters;



    public long getGuardID()
    {
        return guardID;
    }
    
    public int getMaxCharacters()
    {
        return maxCharacters;
    }
    
    public int getNumCharacters()
    {
        return numCharacters;
    }

Then I replaced the code inside setSfGuardUserValues and created a helper function canAddCharacters:

    public void setGuardUserValues(SfGuardUser guard)
    {
        maxCharacters = guard.get[GameName]UserProfileCollection().iterator().next().getCharacterSlots().intValue();
        guardID = guard.getId();
        numCharacters = guard.get[GameName]CharacterCollection().size();
    }

    public boolean canAddCharacters()
    {
        return numCharacters < maxCharacters;
    }
This change made it so that we keep only the data we need in the account class since we do not update the account data from the server. We do this from the website.

These changes cause several changes throughout the system as we reconcile the missing/changed functions. The first is in DBLoginHandler. After the trace we need to call setGuardUserValues instead of setGuardUser:

    trace("Result: " + result); 
    if (guard.getPassword().equalsIgnoreCase(result))
    {
        player.setGuardUserValues(guard);
        send("loginsuccess", new SFSObject(), u);
    }

After that we need to go into CharacterListHandler and make several modifications. We need to add an entity manager, get our SfGuardUser, and load the characters the user has as well as get the account max characters and pass them along to the player. Here is the new function:

@Override
    public void handleClientRequest(User u, ISFSObject data) {
        EntityManager entityManager = (([GameName]Extension) this.getParentExtension()).getEntityManagerFactory().createEntityManager();
        entityManager.getTransaction().begin();
        try {
            trace("got character list request");
            World world = RoomHelper.getWorld(this);
            [GameName]Account player = world.getPlayer(u);
                        
            ISFSObject outputObject = new SFSObject();
            SfGuardUser guard = entityManager.find(SfGuardUser.class, player.getGuardID());
            player.setGuardUserValues(guard);
            outputObject.putInt("maxCharacters", player.getMaxCharacters());
            ISFSObject characterList = new SFSObject();
            int i = 0;
            trace("loading characters");
            Cipher cipher = player.GetCipher();
            for ([GameName]Character character : guard.get[GameName]CharacterCollection()) {
                domain.domainname.gamename.models.[GameName]Character ABCharacter = new domain.domainname.gamename.models.[GameName]Character(character);
                trace("outputting character" + i);
                characterList.putSFSObject("character" + i++, ABCharacter.createSFSObject());
            }
            outputObject.putSFSObject("characters", characterList);
            send("characterlist", outputObject, u);
        } catch (Exception e) {
            trace(e);
        } finally {
            entityManager.getTransaction().rollback();
        }
    }

With all these changes in place, we now have the most up to date list of characters sent to the player. This will be important when we add the character creation handler and the game returns to the character select screen after creating a character.

No comments: