/**
   * Called when a team's score changes.
   *
   * @param teamID the team id
   * @param teamScore the team score
   */
  public void onTeamScoreChanged(int teamID, int teamScore) {

    // System.out.println("server: onTeamScoreChanged");

    synchronized (getNetworkPlayers()) {
      for (NetworkPlayer networkPlayer : getNetworkPlayers()) {

        try {

          DataOutputStream out = networkPlayer.getOutStream();

          synchronized (out) {

            // Message type
            out.writeInt(NetworkConstants.S2C.TEAM_SCORE_CHANGE.ordinal());
            // Team ID
            out.writeInt(teamID);
            // Team score
            out.writeInt(teamScore);
          }

        } catch (IOException e) {

          removeNetworkPlayer(networkPlayer);
          continue;
        }
      }
    }
  }
  /**
   * Sends the new entity information to the network player
   *
   * @param networkPlayer the player being contacted
   * @throws IOException if there is an error writing to the output stream
   */
  private void broadcastNewEntities(NetworkPlayer networkPlayer) throws IOException {

    System.out.println("sending new entities");

    DataOutputStream out = networkPlayer.getOutStream();

    synchronized (out) {

      // Message type
      out.writeInt(NetworkConstants.S2C.CREATE_ENTITIES.ordinal());

      synchronized (this.newEntities) {

        // Number of entities
        out.writeInt(this.newEntities.size());

        for (Entity entity : this.newEntities) {

          // entity class name (without shared.entities. prefix)
          out.writeUTF(entity.getClass().getSimpleName());
          // entity properties
          entity.writeToNetStream(out);
        }
      }
    }
  }
  /**
   * Sends the server time to the network player
   *
   * @param networkPlayer the player being contacted
   * @throws IOException if there is an error writing to the output stream
   */
  private void broadcastServerTime(NetworkPlayer networkPlayer) throws IOException {

    DataOutputStream out = networkPlayer.getOutStream();

    synchronized (out) {

      // Message type
      out.writeInt(NetworkConstants.S2C.SET_SERVER_TIME.ordinal());
      // Server time
      out.writeLong(getTime());
    }
  }
  /**
   * Sends the entity update information to the network player
   *
   * @param networkPlayer the player being contacted
   * @throws IOException if there is an error writing to the output stream
   */
  private void broadcastEntityUpdates(NetworkPlayer networkPlayer) throws IOException {

    DataOutputStream out = networkPlayer.getOutStream();

    synchronized (out) {
      synchronized (this.entityFieldsToBroadcast) {
        for (NetworkedEntityField entityField : this.entityFieldsToBroadcast) {

          // Message type
          out.writeInt(NetworkConstants.S2C.UPDATE_ENTITY_FIELD.ordinal());
          // Entity ID
          out.writeInt(entityField.getParentEntityID());
          // Field ID
          out.writeInt(entityField.getFieldID());
          // Field value
          entityField.writeToNetStream(out);
        }
      }
    }
  }
  /**
   * Sends the information of dead entities to the network player
   *
   * @param networkPlayer the player being contacted
   * @throws IOException if there is an error writing to the output stream
   */
  private void broadcastDeadEntities(NetworkPlayer networkPlayer) throws IOException {

    DataOutputStream out = networkPlayer.getOutStream();

    synchronized (out) {

      // Message type
      out.writeInt(NetworkConstants.S2C.DELETE_ENTITIES.ordinal());

      synchronized (this.deadEntities) {

        // Number of entities
        out.writeInt(this.deadEntities.size());

        for (Entity entity : this.deadEntities) {

          // entity id
          out.writeInt(entity.getID());
        }
      }
    }
  }