createGame() problems

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

Moderators: Lapo, Bax

Post Reply
ericheimburg
Posts: 26
Joined: 18 Mar 2010, 07:25

createGame() problems

Post by ericheimburg »

Hi, I'm trying to use the Game API's createGame() on the server to create a new game. However, calling createGame() crashes with a Null Pointer Exception:

Code: Select all

Exception: java.lang.NullPointerException
Message: *** Null ***
Description: Error while handling client request in extension: { Ext: WteSfsPlugin, Type: JAVA, Lev: ZONE, { Zone: WteLo
bby }, {} }
Extension Cmd: arena.practice
+--- --- ---+
Stack Trace:
+--- --- ---+
java.util.concurrent.ConcurrentHashMap.containsKey(Unknown Source)
com.smartfoxserver.v2.entities.managers.SFSRoomManager.containsRoom(SFSRoomManager.java:407)
com.smartfoxserver.v2.entities.managers.SFSRoomManager.validateRoomName(SFSRoomManager.java:632)
com.smartfoxserver.v2.entities.managers.SFSRoomManager.createRoom(SFSRoomManager.java:88)
com.smartfoxserver.v2.entities.SFSZone.createRoom(SFSZone.java:230)
com.smartfoxserver.v2.api.SFSApi.createRoom(SFSApi.java:607)
com.smartfoxserver.v2.api.SFSGameApi.createGame(SFSGameApi.java:122)
com.smartfoxserver.v2.api.SFSGameApi.createGame(SFSGameApi.java:76)
wte.plugins.ArenaCmdHandler.handleClientRequest(ArenaCmdHandler.java:57)
com.smartfoxserver.v2.extensions.SFSExtension.handleClientRequest(SFSExtension.java:187)
com.smartfoxserver.v2.controllers.ExtensionController.processRequest(ExtensionController.java:137)
com.smartfoxserver.bitswarm.controllers.AbstractController.run(AbstractController.java:96)
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
java.lang.Thread.run(Unknown Source)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

I assume I'm not providing a value it needs, but none of the parameters I pass it are null, and I filled in all the documented members of the CreateSFSGameSettings() object, so I don't know what it's missing.
ericheimburg
Posts: 26
Joined: 18 Mar 2010, 07:25

Post by ericheimburg »

Ah, I found it. The documentation is not very complete here so in case others are trying to get this function to work, here's how I got it to work. In this case, it's a command handler that responds to the command "arena.practice". It creates a "practice" game where the user plays alone against the AI, but you can easily change the parameters to require/invite more people.

Code: Select all

package wte.plugins;

import com.smartfoxserver.v2.SmartFoxServer;
import com.smartfoxserver.v2.annotations.MultiHandler;
import com.smartfoxserver.v2.api.CreateRoomSettings.RoomExtensionSettings;
import com.smartfoxserver.v2.api.ISFSGameApi;
import com.smartfoxserver.v2.entities.SFSRoomRemoveMode;
import com.smartfoxserver.v2.entities.User;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;
import com.smartfoxserver.v2.exceptions.SFSCreateRoomException;
import com.smartfoxserver.v2.extensions.BaseClientRequestHandler;
import com.smartfoxserver.v2.extensions.SFSExtension;
import com.smartfoxserver.v2.game.CreateSFSGameSettings;
import java.util.ArrayList;

@MultiHandler
public class ArenaCmdHandler extends BaseClientRequestHandler
{
    static volatile int nextGameID = 1;

    @Override
	public void handleClientRequest(User user, ISFSObject params)
    {
        //WteSfsPlugin plugin = (WteSfsPlugin)getParentExtension();
        SFSExtension plugin = getParentExtension();
        ISFSGameApi gameApi = SmartFoxServer.getInstance().getAPIManager().getGameApi();

        String requestId = params.getUtfString(SFSExtension.MULTIHANDLER_REQUEST_ID);
        plugin.trace("ArenaCmdHandler called! Command is " + requestId);
        if (requestId.equals("practice"))
        {
            ISFSObject inviteParams = new SFSObject();
            inviteParams.putUtfString("Type", "practice");

            ArrayList<User> invitees = new ArrayList<User>();
            invitees.add(user);
            // invite other people who should be in game here

            CreateSFSGameSettings settings = new CreateSFSGameSettings();
            settings.setInvitationExpiryTime(30);
            settings.setInvitationParams(params);
            settings.setInvitedPlayers(invitees);
            settings.setMinPlayersToStartGame(1);
            settings.setGamePublic(false);
            settings.setExtension(new RoomExtensionSettings("WteSfsPlugin", "wte.plugins.GameManagerPlugin"));
            settings.setName(user.getName()+"'s practice #" + nextGameID++);
            settings.setMaxUsers(1);
            settings.setMaxVariablesAllowed(10);
            settings.setMaxSpectators(0);
            settings.setAutoRemoveMode(SFSRoomRemoveMode.WHEN_EMPTY);

            try
            {
                gameApi.createGame(plugin.getParentZone(), settings, user);
            }
            catch (SFSCreateRoomException ex)
            {
                plugin.trace("Could not create practice room! Error " + ex.getMessage());
            }
        }
    }
}
Last edited by ericheimburg on 14 Nov 2010, 02:53, edited 1 time in total.
ericheimburg
Posts: 26
Joined: 18 Mar 2010, 07:25

Post by ericheimburg »

OTHER THINGS TO KNOW: this causes an Invitation to be sent to the invitees -- not too surprising, I know, but it even sends an Invitation to the room's owner! You have to catch this and not let the user reject this invitation.

The docs don't show how to actually HANDLE an Invitation on the client. Here's how (in C#):

Code: Select all

using Sfs2X.Entities.Invitation;

	// during setup...
	sfs.AddEventListener(SFSEvent.INVITATION, OnInvitation);

	private void OnInvitation(BaseEvent evt)
	{
		SFSInvitation invite = (SFSInvitation)evt.Params["invitation"];
		esProxy.Engine.Send(new InvitationReplyRequest(invite, 
			InvitationReply.ACCEPT));
	}


NOTE THE MINOR EXPLOIT SCENARIO: There is a design flaw (as far as I can tell) with the Game system. If none of the invitees ever accept the ticket, not even the "owner" of the game, then the new room can never die, no matter what you set its AutoRemoveMode to.

This means that if a user hacked their game client, or if your game has a bug, then users can create PERMANENT empty rooms on your system. Depending on how you architect your rooms, it may be possible to create an infinite number of permanent empty rooms, jamming the system up good.

The only work-around I've found is to have the extension notice when a room remains empty a long time, and clean it up.

(In the code above, I use an auto-incrementing integer in the room's name. This doesn't fix the exploit -- in fact it makes it worse because now people don't even need to log out/log back in repeatedly to make infinite rooms -- but it did make testing easier while developing the client invitation-handling code.)
User avatar
Lapo
Site Admin
Posts: 23438
Joined: 21 Mar 2005, 09:50
Location: Italy

Post by Lapo »

OTHER THINGS TO KNOW: this causes an Invitation to be sent to the invitees -- not too surprising, I know, but it even sends an Invitation to the room's owner! You have to catch this and not let the user reject this invitation.
I don't follow your observation. In your code you are creating a Game Room for one player only and you are inviting the creator of the room itself. So, of course, the invitation goes to the Room owner, as requested... but it doesn't make sense because the user is auto-joined in the GameRoom.
The docs don't show how to actually HANDLE an Invitation on the client. Here's how (in C#):

We do in the Actionscript 3 example, called GameLobby. The example can be run in the browser right away after the installation and you can check the sources of the client there, the GameLobby.as file. Actionscript 3 is very similar to JScript and C#
NOTE THE MINOR EXPLOIT SCENARIO: There is a design flaw (as far as I can tell) with the Game system. If none of the invitees ever accept the ticket, not even the "owner" of the game, then the new room can never die, no matter what you set its AutoRemoveMode to.

I think there is some confusion here.
The owner of the Game is immediately joined in the Room right after the creation and he does not need to invite himself. The invitations should only be sent to the other players.

Hope it helps
Lapo
--
gotoAndPlay()
...addicted to flash games
ericheimburg
Posts: 26
Joined: 18 Mar 2010, 07:25

Post by ericheimburg »

Well, using the code above, the user is NOT moved into the room on their own. They just aren't, until they respond to the invitation.

I can't leave them out of the Invite list, either, because then the createGame function fails: Something like "There is not enough invitees for the minimum number of players". So it seems you MUST invite the owner if they are going to be a player.
ericheimburg
Posts: 26
Joined: 18 Mar 2010, 07:25

Post by ericheimburg »

Seems this works fine for multiplayer games, the game owner IS moved into the room.

But I still have to put the game owner into the Invite list, so that the right number of users are in the game and it will start. If there's something else I'm supposed to be doing, please let me know.
User avatar
Lapo
Site Admin
Posts: 23438
Joined: 21 Mar 2005, 09:50
Location: Italy

Post by Lapo »

The user creating the game is always joined in the Room without the need to send any invitations to him. He doesn't need to invite himself :) He his the one who's starting the game.
Seems this works fine for multiplayer games, the game owner IS moved into the room.
Ehm... yes this is done only for multiplayer games. SFS2X is a multiplayer game server.

Did you check the SFS2X-GameLobby example in Flash that we provide? It shows exactly how to work with API, setting up invitations, handling responses and all that. Please take a moment to study that example
Lapo
--
gotoAndPlay()
...addicted to flash games
Post Reply