Neople LogoNeople SDK JS

예제

Neople SDK JS의 실용적인 예제와 사용 패턴

예제

SDK 라이브러리의 실용적인 예제와 일반적인 사용 패턴을 제공합니다.

던전앤파이터 예제

캐릭터 조회 도구

import { NeopleDFClient } from 'neople-sdk-js';

class CharacterLookup {
  private dfClient: NeopleDFClient;

  constructor(apiKey: string) {
    this.dfClient = new NeopleDFClient(apiKey);
  }

  async findCharacter(name: string, serverName?: string) {
    try {
      // 캐릭터 검색
      const searchResults = await this.dfClient.searchCharacter(name);

      if (searchResults.rows.length === 0) {
        return { error: '캐릭터를 찾을 수 없습니다' };
      }

      // 서버가 지정된 경우 필터링
      let character = searchResults.rows[0];
      if (serverName) {
        const filtered = searchResults.rows.find(
          char => char.serverId === serverName
        );
        if (filtered) character = filtered;
      }

      // 상세 정보 조회
      const [details, equipment, skills] = await Promise.all([
        this.dfClient.getCharacter(character.serverId, character.characterId),
        this.dfClient.getCharacterEquipment(
          character.serverId,
          character.characterId
        ),
        this.dfClient.getCharacterSkill(
          character.serverId,
          character.characterId
        ),
      ]);

      return {
        character: details,
        equipment: equipment,
        skills: skills,
      };
    } catch (error) {
      return { error: error.message };
    }
  }
}

// 사용 예시
const lookup = new CharacterLookup(process.env.NEOPLE_DF_API_KEY!);
const result = await lookup.findCharacter('홍길동');
console.log(result);

장비 분석기

import { NeopleDFClient } from 'neople-sdk-js';

class EquipmentAnalyzer {
  private dfClient: NeopleDFClient;

  constructor(apiKey: string) {
    this.dfClient = new NeopleDFClient(apiKey);
  }

  async analyzeEquipment(serverId: string, characterId: string) {
    try {
      const equipment = await this.dfClient.getCharacterEquipment(
        serverId,
        characterId
      );

      const analysis = {
        totalItems: equipment.equipment.length,
        rarityDistribution: {},
        upgradeLevel: {
          average: 0,
          highest: 0,
          lowest: 100,
        },
        setItems: new Map(),
      };

      equipment.equipment.forEach(item => {
        // 희귀도 분포
        const rarity = item.itemRarity;
        analysis.rarityDistribution[rarity] =
          (analysis.rarityDistribution[rarity] || 0) + 1;

        // 강화 수치
        const upgrade = item.upgradeInfo?.upgrade || 0;
        analysis.upgradeLevel.highest = Math.max(
          analysis.upgradeLevel.highest,
          upgrade
        );
        analysis.upgradeLevel.lowest = Math.min(
          analysis.upgradeLevel.lowest,
          upgrade
        );

        // 세트 아이템
        if (item.setItemInfo) {
          const setName = item.setItemInfo.setItemName;
          const count = analysis.setItems.get(setName) || 0;
          analysis.setItems.set(setName, count + 1);
        }
      });

      // 평균 강화 수치 계산
      const totalUpgrade = equipment.equipment.reduce(
        (sum, item) => sum + (item.upgradeInfo?.upgrade || 0),
        0
      );
      analysis.upgradeLevel.average = totalUpgrade / equipment.equipment.length;

      return analysis;
    } catch (error) {
      throw new Error(`장비 분석 실패: ${error.message}`);
    }
  }
}

경매장 모니터

import { NeopleDFClient } from 'neople-sdk-js';

class AuctionMonitor {
  private dfClient: NeopleDFClient;
  private watchList: string[] = [];

  constructor(apiKey: string) {
    this.dfClient = new NeopleDFClient(apiKey);
  }

  addToWatchList(itemName: string) {
    if (!this.watchList.includes(itemName)) {
      this.watchList.push(itemName);
    }
  }

  async checkPrices() {
    const results = [];

    for (const itemName of this.watchList) {
      try {
        const auctions = await this.dfClient.searchAuction({
          itemName,
          limit: 50,
        });

        if (auctions.rows.length > 0) {
          const prices = auctions.rows.map(auction => auction.currentPrice);
          const analysis = {
            itemName,
            totalListings: auctions.rows.length,
            lowestPrice: Math.min(...prices),
            highestPrice: Math.max(...prices),
            averagePrice: prices.reduce((a, b) => a + b, 0) / prices.length,
            recentListings: auctions.rows.slice(0, 10),
          };

          results.push(analysis);
        }
      } catch (error) {
        console.error(`${itemName} 확인 실패:`, error.message);
      }
    }

    return results;
  }

  async findBargains(maxPrice: number) {
    const allResults = await this.checkPrices();
    return allResults
      .filter(result => result.lowestPrice <= maxPrice)
      .sort((a, b) => a.lowestPrice - b.lowestPrice);
  }
}

// 사용 예시
const monitor = new AuctionMonitor(process.env.NEOPLE_DF_API_KEY!);
monitor.addToWatchList('강화의 숨결');
monitor.addToWatchList('모험가의 징표');

const prices = await monitor.checkPrices();
const bargains = await monitor.findBargains(1000000);

사이퍼즈 예제

플레이어 통계 추적기

import { NeopleCyphersClient } from 'neople-sdk-js';

class PlayerStats {
  private cyphersClient: NeopleCyphersClient;

  constructor(apiKey: string) {
    this.cyphersClient = new NeopleCyphersClient(apiKey);
  }

  async getPlayerProfile(playerName: string) {
    try {
      // 플레이어 검색
      const searchResults = await this.cyphersClient.searchPlayer(playerName);
      if (searchResults.rows.length === 0) {
        throw new Error('플레이어를 찾을 수 없습니다');
      }

      const playerId = searchResults.rows[0].playerId;

      // 종합적인 플레이어 데이터 조회
      const [player, ranking, recentMatches] = await Promise.all([
        this.cyphersClient.getPlayer(playerId),
        this.cyphersClient.getPlayerRanking(playerId),
        this.cyphersClient.getMatches(
          playerId,
          'rating',
          undefined,
          undefined,
          20
        ),
      ]);

      // 최근 성과 분석
      const winRate = this.calculateWinRate(recentMatches.rows);
      const favoriteCharacters = this.getFavoriteCharacters(recentMatches.rows);

      return {
        player,
        ranking,
        recentPerformance: {
          totalGames: recentMatches.rows.length,
          winRate,
          favoriteCharacters,
        },
      };
    } catch (error) {
      throw new Error(`플레이어 프로필 조회 실패: ${error.message}`);
    }
  }

  private calculateWinRate(matches: any[]): number {
    if (matches.length === 0) return 0;

    const wins = matches.filter(match => {
      const playerTeam = match.teams.find(team =>
        team.players.some(p => p.playerId === match.playerId)
      );
      return playerTeam?.result === 'win';
    }).length;

    return (wins / matches.length) * 100;
  }

  private getFavoriteCharacters(
    matches: any[]
  ): Array<{ character: string; usage: number }> {
    const characterUsage = {};

    matches.forEach(match => {
      const character = match.players.find(
        p => p.playerId === match.playerId
      )?.characterName;
      if (character) {
        characterUsage[character] = (characterUsage[character] || 0) + 1;
      }
    });

    return Object.entries(characterUsage)
      .map(([character, usage]) => ({ character, usage: usage as number }))
      .sort((a, b) => b.usage - a.usage)
      .slice(0, 5);
  }
}

경기 분석기

import { NeopleCyphersClient } from 'neople-sdk-js';

class MatchAnalyzer {
  private cyphersClient: NeopleCyphersClient;

  constructor(apiKey: string) {
    this.cyphersClient = new NeopleCyphersClient(apiKey);
  }

  async analyzeMatch(matchId: string) {
    try {
      const match = await this.cyphersClient.getMatch(matchId);

      const analysis = {
        basicInfo: {
          matchId: match.matchId,
          gameType: match.gameTypeId,
          playTime: match.playTime,
          map: match.mapId,
        },
        teams: await this.analyzeTeams(match.teams),
        mvp: this.findMVP(match.players),
        characterDistribution: this.getCharacterDistribution(match.players),
      };

      return analysis;
    } catch (error) {
      throw new Error(`경기 분석 실패: ${error.message}`);
    }
  }

  private async analyzeTeams(teams: any[]) {
    const teamAnalysis = [];

    for (const team of teams) {
      const players = team.players;
      const totalKills = players.reduce(
        (sum, p) => sum + (p.killCount || 0),
        0
      );
      const totalDeaths = players.reduce(
        (sum, p) => sum + (p.deathCount || 0),
        0
      );
      const totalAssists = players.reduce(
        (sum, p) => sum + (p.assistCount || 0),
        0
      );

      teamAnalysis.push({
        teamId: team.teamId,
        result: team.result,
        players: players.length,
        teamKDA: {
          kills: totalKills,
          deaths: totalDeaths,
          assists: totalAssists,
          ratio:
            totalDeaths > 0
              ? (totalKills + totalAssists) / totalDeaths
              : totalKills + totalAssists,
        },
      });
    }

    return teamAnalysis;
  }

  private findMVP(players: any[]) {
    return players.reduce((mvp, player) => {
      const score =
        (player.killCount || 0) * 2 +
        (player.assistCount || 0) -
        (player.deathCount || 0);
      const mvpScore =
        (mvp.killCount || 0) * 2 +
        (mvp.assistCount || 0) -
        (mvp.deathCount || 0);

      return score > mvpScore ? player : mvp;
    });
  }

  private getCharacterDistribution(players: any[]) {
    const distribution = {};
    players.forEach(player => {
      const char = player.characterName;
      distribution[char] = (distribution[char] || 0) + 1;
    });
    return distribution;
  }
}

랭킹 추적기

import { NeopleCyphersClient } from 'neople-sdk-js';

class RankingTracker {
  private cyphersClient: NeopleCyphersClient;
  private trackedPlayers: Set<string> = new Set();

  constructor(apiKey: string) {
    this.cyphersClient = new NeopleCyphersClient(apiKey);
  }

  addPlayer(playerId: string) {
    this.trackedPlayers.add(playerId);
  }

  async getTopPlayers(rankingType = 'mmr', limit = 100) {
    try {
      const ranking = await this.cyphersClient.getRanking(
        rankingType,
        0,
        limit
      );

      return ranking.rows.map((player, index) => ({
        rank: index + 1,
        playerName: player.nickname,
        playerId: player.playerId,
        rating: player.grade,
        isTracked: this.trackedPlayers.has(player.playerId),
      }));
    } catch (error) {
      throw new Error(`상위 플레이어 조회 실패: ${error.message}`);
    }
  }

  async trackPlayerProgress(playerId: string, days = 30) {
    try {
      const player = await this.cyphersClient.getPlayer(playerId);
      const matches = await this.cyphersClient.getMatches(
        playerId,
        'rating',
        this.getDateString(days),
        this.getDateString(0),
        100
      );

      const progress = {
        currentRating: player.clanGrade,
        totalMatches: matches.rows.length,
        winRate: this.calculateWinRate(matches.rows),
        ratingChange: this.calculateRatingChange(matches.rows),
        streaks: this.calculateStreaks(matches.rows),
      };

      return progress;
    } catch (error) {
      throw new Error(`플레이어 진행상황 추적 실패: ${error.message}`);
    }
  }

  private getDateString(daysAgo: number): string {
    const date = new Date();
    date.setDate(date.getDate() - daysAgo);
    return date.toISOString().split('T')[0];
  }

  private calculateWinRate(matches: any[]): number {
    if (matches.length === 0) return 0;
    const wins = matches.filter(match => match.result === 'win').length;
    return (wins / matches.length) * 100;
  }

  private calculateRatingChange(matches: any[]): number {
    if (matches.length < 2) return 0;
    const latest = matches[0];
    const oldest = matches[matches.length - 1];
    return latest.grade - oldest.grade;
  }

  private calculateStreaks(matches: any[]) {
    let currentStreak = 0;
    let maxWinStreak = 0;
    let maxLossStreak = 0;
    let currentType = null;

    matches.reverse().forEach(match => {
      const isWin = match.result === 'win';

      if (currentType === isWin) {
        currentStreak++;
      } else {
        if (currentType === true) {
          maxWinStreak = Math.max(maxWinStreak, currentStreak);
        } else if (currentType === false) {
          maxLossStreak = Math.max(maxLossStreak, currentStreak);
        }
        currentStreak = 1;
        currentType = isWin;
      }
    });

    return { maxWinStreak, maxLossStreak, currentStreak, currentType };
  }
}