랭킹 출력 플러그인

SheepDuck·2024년 8월 8일

Minecraft

목록 보기
3/3

Bitbucket 주소

요구사항

기능 요구사항

  1. 지정된 시간마다 level, pvp 랭킹 출력
    • level 랭킹: 매 정각마다 출력
    • pvp 랭킹: 매 30분마다 출력
  2. 특정 커맨드 입력 시 level, pvp 랭킹 출력
    1. 커맨드: “rank”

핵심 코드 분석

DB config 코드

public class MongoDB {
    // MongoDB 클라이언트 인스턴스
    private static MongoClient db;
    
    // MongoDatabase 참조
    @Getter
    private static MongoDatabase RPGSharp;

    // 설정 파일에서 사용할 키 이름들
    private static final String HOST_CONFIG_NAME = "database.host";
    private static final String PORT_CONFIG_NAME = "database.port";
    private static final String DATABASE_CONFIG_NAME = "database.database";

    // MongoDB URI 형식 문자열
    private static final String MONGODB_URI_FORMAT = "mongodb://%s:%d";
    
    // 설정 파일 이름
    private static final String CONFIG_FILE_NAME = "config.yml";

    /**
     * config.yml 파일에서 설정을 읽어와 MongoDB 데이터베이스에 연결합니다.
     * 설정 파일이 존재하지 않으면 기본 값으로 설정 파일을 생성합니다.
     */
    public static void connect() {
        // 플러그인의 데이터 폴더에서 설정 파일을 가져옵니다.
        File configFile = new File(RankingPlugin_Bungee.getInstance().getDataFolder(), CONFIG_FILE_NAME);
        
        // 설정 파일이 존재하지 않으면 기본 설정 파일을 생성합니다.
        if (!configFile.exists()) {
            createDefaultConfig(configFile, RankingPlugin_Bungee.getInstance());
        }

        Configuration config;
        try {
            // 파일에서 설정을 로드합니다.
            config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile);
        } catch (IOException e) {
            // 설정 로드 실패 시 오류 메시지를 출력합니다.
            ErrorView.MONGODB_LOAD_FAILED.print(e.getMessage());
            return;
        }

        // 설정에서 호스트, 포트, 데이터베이스 이름을 가져옵니다.
        String host = config.getString(HOST_CONFIG_NAME);
        int port = config.getInt(PORT_CONFIG_NAME);
        String database = config.getString(DATABASE_CONFIG_NAME);

        // MongoDB 클라이언트를 생성하고 데이터베이스에 연결합니다.
        db = MongoClients.create(String.format(MONGODB_URI_FORMAT, host, port));
        RPGSharp = db.getDatabase(database);
        
        // MongoDB 연결 성공 로그를 출력합니다.
        OutView.MONGODB_CONNECTED.log();
    }
    .... disconnect, createDefaultConfig 메소드 등등
}

DB 읽는 코드

public class LevelRanking {
    // 레벨 랭킹 배열 및 변경 사항 배열
    @Getter
    private static List<LevelRankDTO> levelRankingArr;
    @Getter
    private static List<RankDiff> levelRankingDiffArr;
    @Getter
    private static String lastModifiedAt;

    // 레벨 정렬 기준 (레벨 내림차순, 경험치 내림차순)
    @Getter
    private static final Document LEVEL_SORT_CRITERIA = new Document("level", -1).append("exp", -1);
    
    /**
     * 레벨 랭킹 배열을 업데이트합니다.
     * MongoDB에서 데이터를 가져와 정렬 후 배열에 저장합니다.
     *
     * @param readCount 읽어올 문서 수
     */
    private static void updateLevelRankingArr(int readCount) {
        MongoDB.connect();
        levelRankingArr = new ArrayList<>();
        // MongoDB에서 RPGPlayer 컬렉션의 문서를 조회하고 정렬하여 가져오는 커서를 생성합니다.
	MongoCursor<Document> cursor = MongoDB.getRPGSharp().getCollection("RPGPlayer").find()
      // projection: 가져올 필드를 지정합니다. nickname, level, exp 필드만 결과에 포함됩니다.
      .projection(new Document("nickname", 1).append("level", 1).append("exp", 1))
      // sort: 결과를 level 필드를 기준으로 내림차순(-1), 그 다음 exp 필드를 기준으로 내림차순(-1)으로 정렬합니다.
      .sort(LEVEL_SORT_CRITERIA)
      // limit: 결과의 최대 개수를 readCount로 제한합니다.
      .limit(readCount)
      // iterator: 위의 조건으로 MongoDB 쿼리를 실행하고 결과를 순회(iterate)할 수 있는 커서를 반환합니다.
      .iterator();

        int i = 1;
        while (cursor.hasNext()) {
            Document document = cursor.next();
            String nickname = document.getString("nickname");
            int level = document.getInteger("level");
            double exp = document.getDouble("exp");
            
            if (i > 1) {
            	// level, exp 둘다 같은 경우 공동 순위로 처리
                if (levelRankingArr.get(levelRankingArr.size() - 1).getLevel() == level
                        && levelRankingArr.get(levelRankingArr.size() - 1).getExp() == exp) {
                    levelRankingArr.add(new LevelRankDTO(i - 1, nickname, level, exp));
                    i++;
                    continue;
                }
            }
            levelRankingArr.add(new LevelRankDTO(i++, nickname, level, exp));
        }
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        lastModifiedAt = sdf.format(new Date());
        MongoDB.disconnect();
    }
    .... 
}

Message Broadcast 코드

public class Broadcast {
    public static final String BUNGEE_CHANNEL = "BungeeCord";
    public static final String RANKING_CHANNEL = "Ranking";

    public static void send(String channel, String message) {
        ByteArrayDataOutput out = ByteStreams.newDataOutput();
        out.writeUTF("Forward");
        out.writeUTF("ALL");
        out.writeUTF(channel);
        out.writeUTF(message);

        for (ServerInfo server : ProxyServer.getInstance().getServers().values()) {
            server.sendData(BUNGEE_CHANNEL, out.toByteArray());
        }
    }
}

"Forward", "ALL" 옵션을 써줘야 번지 서버에서 모든 버킷 서버로 메세지가 날아갑니다.

profile
code sheepDuck

0개의 댓글