예제 #1
0
  /**
   * 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;
  }
예제 #2
0
 /**
  * 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;
 }
예제 #3
0
 /** {@inheritDoc} */
 public void removingObject() {
   try {
     sessionRef.get().disconnect();
   } catch (ObjectNotFoundException e) {
     // already disconnected.
   }
 }
예제 #4
0
 /**
  * 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");
   }
 }
예제 #5
0
 /** {@inheritDoc} */
 public boolean isConnected() {
   try {
     return sessionRef.get().isConnected();
   } catch (ObjectNotFoundException e) {
     return false;
   }
 }
예제 #6
0
  public void callMethod(
      MethodDescriptor method,
      RpcController controller,
      Message request,
      Message responsePrototype,
      RpcCallback<Message> done) {

    listener.get().callMethod(method, controller, request, responsePrototype, done);
  }
예제 #7
0
  /**
   * 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);
    }
  }
예제 #8
0
 /** {@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);
 }
예제 #11
0
 /**
  * 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.&lt;idBytes&gt;
  * com.sun.sgs.impl.service.session.node.&lt;nodeId&gt;.impl.&lt;idBytes&gt;
  * </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);
 }
예제 #12
0
  /**
   * 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));
  }
예제 #13
0
 /** {@inheritDoc} */
 @Override
 public String toString() {
   ClientSessionImpl sessionImpl = null;
   try {
     sessionImpl = sessionRef.get();
   } catch (ObjectNotFoundException e) {
   }
   return getClass().getName()
       + "["
       + (sessionImpl == null ? "(not found)" : sessionImpl.toString())
       + "]";
 }
예제 #14
0
  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;
  }
예제 #15
0
  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;
  }
예제 #16
0
 private UtilChannel channel() {
   return channelRef == null ? null : channelRef.get();
 }
예제 #17
0
  /**
   * 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;
  }
예제 #18
0
 /** Returns the wrapped client session for this instance. */
 ClientSessionWrapper getWrappedClientSession() {
   return wrappedSessionRef.get();
 }
예제 #19
0
 /**
  * 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();
 }
예제 #21
0
 public void run() throws Exception {
   for (ManagedReference<AICharacterManager> mgrRef : mgrs) mgrRef.get().run();
 }
예제 #22
0
 public RemoteCall newRpcController() {
   return listener.get().newRpcController();
 }
예제 #23
0
  /**
   * 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
    }
  }
예제 #24
0
 /** Returns the client session for this queue. */
 ClientSessionImpl getClientSession() {
   return sessionRef.get();
 }
예제 #25
0
 /** {@inheritDoc} */
 @Override
 public int hashCode() {
   return sessionRef.hashCode();
 }
예제 #26
0
 public RocketPlayer getCurrentPlayer() {
   return currentPlayerRef.get();
 }
예제 #27
0
 /**
  * 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()));
 }
예제 #30
0
 /** Returns the client session ID for this queue. */
 BigInteger getSessionRefId() {
   return sessionRef.getId();
 }