/** * Moves the player into the referenced <code>Game</code>. This causes the <code>Player</code> to * leave the game they are currently playing (if they are currently playing a game) and notify the * new game that they are joining. If the reference provided is null, then this <code>Player * </code> is removed from the current game and sets itself as not playing any games. * * <p>When the <code>Player</code> is first started, it is not playing any games. In practice, * this method is only called with a value of null when the associated client logs out of the * server. * * @param gameRef a reference to the new <code>Game</code>, or null if the player is only being * removed from a game */ public void moveToGame(Game game) { AppContext.getDataManager().markForUpdate(this); // if we were previously playing a game, leave it if (isPlaying()) { gameRef.getForUpdate().leave(this); characterManagerRef.getForUpdate().setCurrentLevel(null); playing = false; } // if we got moved into a valid game, then make the migration if (game != null) { playing = true; // keep track of the new game... gameRef = AppContext.getDataManager().createReference(game); // ...and handle joining the new game messageHandler = game.createMessageHandler(); game.join(this); } // if we're no longer playing, then our user id is no longer valid if (!playing) this.currentSessionRef = null; }
/** * Returns the {@code ClientSession} instance for the given {@code id}, retrieved from the * specified {@code dataService}, or {@code null} if the client session isn't bound in the data * service. This method should only be called within a transaction. * * @param dataService a data service * @param id a session ID * @return the session for the given session {@code id}, or {@code null} * @throws TransactionException if there is a problem with the current transaction */ static ClientSessionImpl getSession(DataService dataService, BigInteger id) { ClientSessionImpl sessionImpl = null; try { ManagedReference<?> sessionRef = dataService.createReferenceForId(id); sessionImpl = (ClientSessionImpl) sessionRef.get(); } catch (ObjectNotFoundException e) { } return sessionImpl; }
/** {@inheritDoc} */ public void removingObject() { try { sessionRef.get().disconnect(); } catch (ObjectNotFoundException e) { // already disconnected. } }
/** * Returns the underlying {@code ClientSessionImpl} instance for this wrapper. If the underlying * client session has been removed, then the client session has been disconnected, so {@code * IllegalStateException} is thrown. * * @return the underlying {@code ClientSessionImpl} instance for this wrapper */ public ClientSessionImpl getClientSession() { try { return sessionRef.get(); } catch (ObjectNotFoundException e) { throw new IllegalStateException("client session is disconnected"); } }
/** {@inheritDoc} */ public boolean isConnected() { try { return sessionRef.get().isConnected(); } catch (ObjectNotFoundException e) { return false; } }
public void callMethod( MethodDescriptor method, RpcController controller, Message request, Message responsePrototype, RpcCallback<Message> done) { listener.get().callMethod(method, controller, request, responsePrototype, done); }
/** * This is used to handle leaving dungeons before we can actually call the <code>moveToGame</code> * (eg, when we die). It handles multiple calls while on the same level cleanly (which is done by * paranoid checking when leaving dungeons). */ public void leaveCurrentLevel() { PlayerCharacterManager pcm = characterManagerRef.get(); Level level = pcm.getCurrentLevel(); if (level != null) { level.removeCharacter(pcm); pcm.setCurrentLevel(null); } }
/** {@inheritDoc} */ @Override public boolean equals(Object object) { if (object == this) { return true; } else if (object instanceof ClientSessionWrapper) { return sessionRef.equals(((ClientSessionWrapper) object).sessionRef); } else { return false; } }
/** {@inheritDoc} */ @Override public String toString() { StringBuilder buf = new StringBuilder(getName()); buf.append('@'); if (getSession() == null) { buf.append("null"); } else { buf.append(currentSessionRef.getId()); } return buf.toString(); }
public MythologicChannelSessionListener( ClientSession clientSession, ManagedReference<Channel> channel1) { super(clientSession); // Join the session to all channels. We obtain the channel // in two different ways, by reference and by name. ChannelManager channelMgr = AppContext.getChannelManager(); // We were passed a reference to the first channel. channel1.get().join(clientSession); // We look up the second channel by name. Channel channel2 = channelMgr.getChannel("a"); channel2.join(clientSession); }
/** * Constructs an instance of this class with the specified {@code sessionService}, {@code * identity}, and the local node ID, and stores this instance with the following bindings: * * <p> * * <pre> * com.sun.sgs.impl.service.session.impl.<idBytes> * com.sun.sgs.impl.service.session.node.<nodeId>.impl.<idBytes> * </pre> * * This method should only be called within a transaction. * * @param sessionService a client session service * @param identity the session's identity * @throws TransactionException if there is a problem with the current transaction */ ClientSessionImpl(ClientSessionServiceImpl sessionService, Identity identity) { if (sessionService == null) { throw new NullPointerException("null sessionService"); } if (identity == null) { throw new IllegalStateException("session's identity is not set"); } this.sessionService = sessionService; this.identity = identity; this.nodeId = sessionService.getLocalNodeId(); writeBufferCapacity = sessionService.getWriteBufferSize(); DataService dataService = sessionService.getDataService(); ManagedReference<ClientSessionImpl> sessionRef = dataService.createReference(this); id = sessionRef.getId(); this.wrappedSessionRef = dataService.createReference(new ClientSessionWrapper(sessionRef)); idBytes = id.toByteArray(); dataService.setServiceBinding(getSessionKey(), this); dataService.setServiceBinding(getSessionNodeKey(), this); dataService.setServiceBinding(getEventQueueKey(), new EventQueue(this)); logger.log(Level.FINEST, "Stored session, identity:{0} id:{1}", identity, id); }
/** * Sets the current <code>UserID</code> for this <code>Player</code>, which changes from session * to session. Typically this is called when the player first logs again, and not again until the * player logs out and logs back in. * * @param uid the player's user identifier */ public void setCurrentSession(ClientSession session) { DataManager dataMgr = AppContext.getDataManager(); dataMgr.markForUpdate(this); currentSessionRef = dataMgr.createReference(session); // Also inform the client of the session ID // FIXME, this is hacked in as the only non-channel message // for ease of porting -JM BigInteger sid = currentSessionRef.getId(); byte[] bytes = sid.toByteArray(); session.send(ByteBuffer.wrap(bytes)); }
/** {@inheritDoc} */ @Override public String toString() { ClientSessionImpl sessionImpl = null; try { sessionImpl = sessionRef.get(); } catch (ObjectNotFoundException e) { } return getClass().getName() + "[" + (sessionImpl == null ? "(not found)" : sessionImpl.toString()) + "]"; }
public boolean removePlayer(RocketPlayer player) { logger.log(Level.INFO, "{0} leaves {1}", new Object[] {player.getName(), this.getName()}); AppContext.getDataManager().markForUpdate(this); Channel tableChannel = tableChannelRef.getForUpdate(); tableChannel.leave(player.getClientSessionRef().get()); // The reference created below should be identical to one of the players // on our table. I think createReference has some clever logic to // not create another reference if one already exists. ManagedReference<RocketPlayer> playerRef = AppContext.getDataManager().createReference(player); if (playerRef.equals(player1Ref)) { player1Ref = null; } else if (playerRef.equals(player2Ref)) { player2Ref = null; } else if (playerRef.equals(player3Ref)) { player3Ref = null; } else if (playerRef.equals(player4Ref)) { player4Ref = null; } else { logger.log( Level.SEVERE, "player " + player.getName() + " doesn't appear to be one of this table!"); return false; } setTableAvailable(true); maybeChangeStatusOnRemovePlayer(); return true; }
public boolean addPlayer(RocketPlayer player) { ManagedReference<RocketPlayer> playerRef = AppContext.getDataManager().createReference(player); AppContext.getDataManager().markForUpdate(this); Channel tableChannel = tableChannelRef .getForUpdate(); // ?? Do I really need to get for update when adding new sessions? int playerId = 0; if (player1Ref == null) { player1Ref = playerRef; playerId = 1; } else if (player2Ref == null) { player2Ref = playerRef; playerId = 2; } else if (player3Ref == null) { player3Ref = playerRef; playerId = 3; } else if (player4Ref == null) { player4Ref = playerRef; playerId = 4; } else { // Theoretically, this should never happen as the tableAvailability // won't let players in if the table is full. logger.log( Level.SEVERE, "Not sure how, but a player has tried to join a table with no free spaces!"); return false; } tableChannel.join(player.getClientSessionRef().get()); player.setMyCurrentTable(AppContext.getDataManager().createReference(this)); logger.log( Level.INFO, "{0} enters {1} as player " + playerId, new Object[] {player.getName(), this.getName()}); tableChannel.send( Utils.encodeString( ClientServerMessageInteractor.createTableJoinSuccessMessage( player.getName(), playerId))); updateTableAvailabilty(); maybeChangeStatusOnAddPlayer(); return true; }
private UtilChannel channel() { return channelRef == null ? null : channelRef.get(); }
/** * This method takes a <code>StreamTokenizer</code> that is setup at the start of a single dungeon * file, and loads all the data, creating the AIs, stitching together all connectors between * levels, etc. At the end a single <code>Connector</code> is provded as an entry point to the * dungeon. * * <p>FIXME: we should make the aggregator real, or remove it and go back to use of the PDTimer * directly. * * @param stok the stream to tokenize * @param gameName the name of the dungeon this is being loaded into * @param impassableSprites the set of identifiers that are impassable * @param lobbyRef a reference to the lobby * @param eventAg an aggreagator for all AI tasks * @return a reference to a <code>GameConnector</code> that is the connection between the dungeon * and the lobby * @throws IOException if the stream isn't formatted correctly */ public static GameConnector loadDungeon( StreamTokenizer stok, String gameName, Set<Integer> impassableSprites, Game lobby) throws IOException { DataManager dataManager = AppContext.getDataManager(); // the prefix for all level names String levelPrefix = gameName + ":" + SimpleLevel.NAME_PREFIX; // details about where we enter the dungeon String entryLevel = null; int entryX = 0; int entryY = 0; // the collection of boards and levels HashMap<String, SimpleBoard> boards = new HashMap<String, SimpleBoard>(); HashMap<String, ManagedReference<SimpleLevel>> levelRefs = // simplelevel new HashMap<String, ManagedReference<SimpleLevel>>(); // the various kinds of connectors HashSet<ConnectionData> connections = new HashSet<ConnectionData>(); HashSet<ConnectionData> oneWays = new HashSet<ConnectionData>(); HashSet<ConnectionData> playerConnectors = new HashSet<ConnectionData>(); // the collection of Monster (AI) and NPC characters // to AICharacterManager HashMap<String, HashSet<ManagedReference<AICharacterManager>>> npcMap = new HashMap<String, HashSet<ManagedReference<AICharacterManager>>>(); HashMap<String, HashSet<ManagedReference<AICharacterManager>>> aiMap = new HashMap<String, HashSet<ManagedReference<AICharacterManager>>>(); // first, parse the data file itself while (stok.nextToken() != StreamTokenizer.TT_EOF) { if (stok.sval.equals("EntryPoint")) { // an Entry is LEVEL X_POS Y_POS stok.nextToken(); entryLevel = levelPrefix + stok.sval; stok.nextToken(); entryX = (int) (stok.nval); stok.nextToken(); entryY = (int) (stok.nval); } else if (stok.sval.equals("DefineLevel")) { // levels are handled separately by SimpleLevel stok.nextToken(); String levelName = levelPrefix + stok.sval; boards.put(levelName, new SimpleBoard(stok, impassableSprites)); } else if (stok.sval.equals("Connection")) { connections.add(readConnection(stok, levelPrefix)); } else if (stok.sval.equals("OneWayConnection")) { oneWays.add(readConnection(stok, levelPrefix)); } else if (stok.sval.equals("PlayerConnection")) { playerConnectors.add(readConnection(stok, levelPrefix)); } else if (stok.sval.equals("NPC")) { // an NPC is LEVEL NAME ID MESSAGE_1 [ ... MESSAGE_N ] stok.nextToken(); String levelName = levelPrefix + stok.sval; stok.nextToken(); String npcName = stok.sval; stok.nextToken(); int id = (int) (stok.nval); stok.nextToken(); int count = (int) (stok.nval); String[] messages = new String[count]; for (int i = 0; i < count; i++) { stok.nextToken(); messages[i] = stok.sval; } // create the manager for the NPC and the NPC itself AICharacterManager aiCMR = AICharacterManager.newInstance(); NPCharacter npc = new NPCharacter(id, npcName, messages, aiCMR); aiCMR.setCharacter(npc); // put it into a bucket for the given level, creating the // bucket if it doesn't already exist // to AICharacterManager HashSet<ManagedReference<AICharacterManager>> set = npcMap.get(levelName); if (set == null) { set = new HashSet<ManagedReference<AICharacterManager>>(); npcMap.put(levelName, set); } set.add(dataManager.createReference(aiCMR)); } else if (stok.sval.equals("Monster")) { // a Monster is LEVEL TYPE ID stok.nextToken(); String levelName = levelPrefix + stok.sval; stok.nextToken(); String type = stok.sval; stok.nextToken(); int id = (int) (stok.nval); // create the manager and get the right instance AICharacterManager aiCMR = MonsterFactory.getMonster(id, type); // put the monster into a bucket for the given level, creating // the bucket if it doesn't already exist HashSet<ManagedReference<AICharacterManager>> set = aiMap.get(levelName); if (set == null) { set = new HashSet<ManagedReference<AICharacterManager>>(); aiMap.put(levelName, set); } set.add(dataManager.createReference(aiCMR)); } else { throw new IOException("Unknown type: " + stok.sval + " on line " + stok.lineno()); } } // next, create a GLO for each of the levels for (String levelName : boards.keySet()) { SimpleLevel level = new SimpleLevel(levelName, gameName); String gloName = Game.NAME_PREFIX + levelName; dataManager.setBinding(gloName, level); levelRefs.put(levelName, dataManager.createReference(level)); } // with the levels in place, we can generate the connectors and // assign them to their board spaces for (ConnectionData data : connections) { // create a connector and register it SimpleConnector connector = new SimpleConnector( levelRefs.get(data.level1).get(), data.level1X, data.level1Y, levelRefs.get(data.level2).get(), data.level2X, data.level2Y); // notify both boards of the connector boards.get(data.level1).setAsConnector(data.level1X, data.level1Y, connector); boards.get(data.level2).setAsConnector(data.level2X, data.level2Y, connector); } // we also get the player connectors for (ConnectionData data : playerConnectors) { // create a connector and register it PlayerConnector connector = new PlayerConnector( levelRefs.get(data.level1).get(), data.level1X, data.level1Y, levelRefs.get(data.level2).get(), data.level2X, data.level2Y); // notify both boards of the connector boards.get(data.level1).setAsConnector(data.level1X, data.level1Y, connector); boards.get(data.level2).setAsConnector(data.level2X, data.level2Y, connector); } // same for the one-ways, except that we only set one side for (ConnectionData data : oneWays) { // create the connector and register it OneWayConnector connector = new OneWayConnector(levelRefs.get(data.level2).get(), data.level2X, data.level2Y); // notify the source board of the connector boards.get(data.level1).setAsConnector(data.level1X, data.level1Y, connector); } // also generate the entry connector, register it, and set it for // the entry board GameConnector gameConnector = new GameConnector(lobby, levelRefs.get(entryLevel).get(), entryX, entryY); boards.get(entryLevel).setAsConnector(entryX, entryY, gameConnector); // with all the connectors in place, notify the levels for (ManagedReference<SimpleLevel> levelRef : levelRefs.values()) { SimpleLevel level = levelRef.get(); level.setBoard(boards.get(level.getName())); } TaskManager taskManager = AppContext.getTaskManager(); // now that the levels are all set, add the NPC characters to the // levels and the timer for (String levelName : npcMap.keySet()) { Level level = levelRefs.get(levelName).get(); for (ManagedReference<AICharacterManager> mgrRef : npcMap.get(levelName)) { AICharacterManager mgr = mgrRef.get(); taskManager.schedulePeriodicTask(mgr, 0, 1700); // eventAg.addCharacterMgr(mgr); level.addCharacter(mgr); } } // add the Monsters too for (String levelName : aiMap.keySet()) { Level level = levelRefs.get(levelName).get(); for (ManagedReference<AICharacterManager> mgrRef : aiMap.get(levelName)) { AICharacterManager mgr = mgrRef.get(); taskManager.schedulePeriodicTask(mgr, 0, 1100); // eventAg.addCharacterMgr(mgr); level.addCharacter(mgr); } } // finally add, the items // FIXME: support items in file format // return the game connector, which is all the Dungeon needs to // interact with everything we've setup here return gameConnector; }
/** Returns the wrapped client session for this instance. */ ClientSessionWrapper getWrappedClientSession() { return wrappedSessionRef.get(); }
/** * Returns this <code>Player</code>'s current <code>UserID</code>. Note that this is only * meaningful if <code>isPlaying</code> returns true. Otherwise this will return null. * * @return the current user identifier, or null if the player is not currently playing */ public ClientSession getCurrentSession() { return currentSessionRef == null ? null : currentSessionRef.get(); }
/** * Returns the session for this listener. * * @return the session for this listener */ protected ClientSession getSession() { if (currentSessionRef == null) { return null; } return currentSessionRef.get(); }
public void run() throws Exception { for (ManagedReference<AICharacterManager> mgrRef : mgrs) mgrRef.get().run(); }
public RemoteCall newRpcController() { return listener.get().newRpcController(); }
/** * Invokes the {@code disconnected} callback on this session's {@code ClientSessionListener} (if * present and {@code notify} is {@code true}), removes the listener and its binding (if present), * and then removes this session and its bindings from the specified {@code dataService}. If the * bindings have already been removed from the {@code dataService} this method takes no action. * This method should only be called within a transaction. * * @param dataService a data service * @param graceful {@code true} if disconnection is graceful, and {@code false} otherwise * @param notify {@code true} if the {@code disconnected} callback should be invoked * @throws TransactionException if there is a problem with the current transaction */ void notifyListenerAndRemoveSession( final DataService dataService, final boolean graceful, boolean notify) { String sessionKey = getSessionKey(); String sessionNodeKey = getSessionNodeKey(); String listenerKey = getListenerKey(); String eventQueueKey = getEventQueueKey(); /* * Get ClientSessionListener, and remove its binding and * wrapper if applicable. The listener may not be bound * in the data service if: the AppListener.loggedIn callback * either threw a non-retryable exception or returned a * null listener, or the application removed the * ClientSessionListener object from the data service. */ ClientSessionListener listener = null; try { ManagedObject obj = dataService.getServiceBinding(listenerKey); dataService.removeServiceBinding(listenerKey); if (obj instanceof ListenerWrapper) { dataService.removeObject(obj); listener = ((ListenerWrapper) obj).get(); } else { listener = (ClientSessionListener) obj; } } catch (NameNotBoundException e) { logger.logThrow(Level.FINE, e, "removing ClientSessionListener for session:{0} throws", this); } /* * Remove event queue and associated binding. */ try { ManagedObject eventQueue = dataService.getServiceBinding(eventQueueKey); dataService.removeServiceBinding(eventQueueKey); dataService.removeObject(eventQueue); } catch (NameNotBoundException e) { logger.logThrow(Level.FINE, e, "removing EventQueue for session:{0} throws", this); } /* * Invoke listener's 'disconnected' callback if 'notify' * is true and a listener exists for this client session. If the * 'disconnected' callback throws a non-retryable exception, * schedule a task to remove this session and its associated * bindings without invoking the listener, and rethrow the * exception so that the currently executing transaction aborts. */ if (notify && listener != null) { try { listener.disconnected(graceful); } catch (RuntimeException e) { if (!isRetryableException(e)) { logger.logThrow( Level.WARNING, e, "invoking disconnected callback on listener:{0} " + " for session:{1} throws", listener, this); sessionService.scheduleTask( new AbstractKernelRunnable() { public void run() { ClientSessionImpl sessionImpl = ClientSessionImpl.getSession(dataService, id); sessionImpl.notifyListenerAndRemoveSession(dataService, graceful, false); } }, identity); } throw e; } } /* * Remove this session's state and bindings. */ try { dataService.removeServiceBinding(sessionKey); dataService.removeServiceBinding(sessionNodeKey); dataService.removeObject(this); } catch (NameNotBoundException e) { logger.logThrow(Level.WARNING, e, "session binding already removed:{0}", sessionKey); } /* * Remove this session's wrapper object, if it still exists. */ try { dataService.removeObject(wrappedSessionRef.get()); } catch (ObjectNotFoundException e) { // already removed } }
/** Returns the client session for this queue. */ ClientSessionImpl getClientSession() { return sessionRef.get(); }
/** {@inheritDoc} */ @Override public int hashCode() { return sessionRef.hashCode(); }
public RocketPlayer getCurrentPlayer() { return currentPlayerRef.get(); }
/** * Returns the <code>CharacterManager</code> that this <code>Player</code> uses to manage their * <code>Character</code>s. A <code>Player</code> may only play as one <code>Character</code> at a * time. * * @return the character manager */ public PlayerCharacterManager getCharacterManager() { return characterManagerRef.get(); }
/** * Returns the room this player is currently in, or {@code null} if this player is not in a room. * * <p> * * @return the room this player is currently in, or {@code null} */ protected SwordWorldRoom getRoom() { if (currentRoomRef == null) { return null; } return currentRoomRef.get(); }
public void userLoggedIn(WonderlandClientID clientID, ManagedReference<UserMO> userRef) { users.put( clientID, new User(clientID.getID().toString(), userRef.get().getUsername(), new Date())); }
/** Returns the client session ID for this queue. */ BigInteger getSessionRefId() { return sessionRef.getId(); }