fortnite-replay-analysis 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +89 -28
  2. package/index.js +48 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,56 +1,117 @@
1
1
  # Fortnite Replay Analysis
2
2
 
3
- Fortniteの `.replay` ファイルを解析して、試合中のプレイヤー情報やパーティごとの統計データを取得できるNode.jsモジュールです。
3
+ Fortniteのリプレイファイルを解析して、プレイヤーデータを取得・集計・ソートできるNode.jsのモジュールです。
4
4
 
5
5
  ## 特徴
6
6
 
7
- * クロスプラットフォーム対応(Windows / Linux)
8
- * .NET製CLIバイナリとNode.jsで連携
9
- * Decimal.jsで高精度な生存時間計算
10
- * スコア集計、C6S3公式準拠の並び替え機能付き
7
+ * OS判定してC#でビルドされた自己完結バイナリを呼び出すから、高速解析できる
8
+ * botプレイヤーの除外や順位ソートなどオプション対応
9
+ * 複数マッチのスコアをパーティ単位でマージして集計可能
10
+ * 公式準拠でのスコアのソートも可能
11
11
 
12
12
  ## インストール
13
13
 
14
- ```bash
15
- npm install fortnite-replay-analysis
14
+ ```
15
+ npm install fortnite-replay-analysis@latest
16
16
  ```
17
17
 
18
- ## 使用例
18
+ ## 使い方
19
19
 
20
20
  ```js
21
- const { ReplayAnalysis, sortScores, mergeScores } = require('fortnite-replay-analysis');
21
+ const { ReplayAnalysis, mergeScores, sortScores, calculateScore } = require('fortnite-replay-analysis');
22
+
23
+ (async () => {
24
+ try {
25
+ // 1試合分のリプレイ解析(返り値はJSON形式)
26
+ // rawPlayerData: 元の解析結果、生データ
27
+ // processedPlayerInfo: bot除外や順位ソート済みのプレイヤーデータ
28
+ const { rawPlayerData, processedPlayerInfo } = await ReplayAnalysis('./path/to/replayDir', { bot: false, sort: true });
29
+
30
+ console.log('Raw Data:', rawPlayerData);
31
+ console.log('Processed Player Info:', processedPlayerInfo);
32
+
33
+ // 解析結果のスコア配列を公式準拠のルールでソートも可能
34
+ const sortedScores = sortScores(processedPlayerInfo);
35
+
36
+ // 複数マッチの解析結果をまとめたいときは、
37
+ // sortScoresでソート済みの配列を複数用意して
38
+ // mergeScoresに配列の配列として渡す
39
+ const mergedScores = mergeScores([
40
+ sortedScores, // 1試合目の結果
41
+ sortedScores2, // 2試合目の結果
42
+ // ...
43
+ ]);
44
+
45
+ // マージ後の結果もsortScoresで再ソート可能
46
+ const finalSorted = sortScores(mergedScores);
47
+
48
+ console.log('Merged and Sorted:', finalSorted);
49
+
50
+ } catch (e) {
51
+ console.error(e);
52
+ }
53
+ })();
54
+ ```
55
+
56
+ ## calculateScoreの使い方
57
+
58
+ リプレイ解析済みの`ReplayAnalysis` の `result.processedPlayerInfo` を保存した JSON ファイル(ファイル名は任意でOK)から、大会形式のスコアを計算したいときに使える。
22
59
 
23
- // リプレイファイルのパスを指定して解析
24
- ReplayAnalysis('./match1.replay').then(({ processedPlayerInfo }) => {
25
- console.log(processedPlayerInfo);
60
+ ```js
61
+ const { calculateScore } = require('fortnite-replay-analysis');
62
+
63
+ const score = await calculateScore({
64
+ matchDataPath: './output/matchA1/playerInfo.json',
65
+ points: {
66
+ 1: 11, 2: 6, 3: 5, 4: 4, 5: 3,
67
+ 6: 2, 7: 1, 8: 1, 9: 1, 10: 1
68
+ },
69
+ killPointMultiplier: 1,
70
+ killCountUpperLimit: 10
26
71
  });
72
+
73
+ console.log(score);
27
74
  ```
28
75
 
29
- ## 関数一覧
76
+ ## API
77
+
78
+ ### `ReplayAnalysis(replayFileDir, options)`
30
79
 
31
- ### `ReplayAnalysis(replayFilePath: string, options?: { bot?: boolean, sort?: boolean }): Promise<{ rawPlayerData, processedPlayerInfo }>`
80
+ * `replayFileDir`:リプレイファイルが入ったディレクトリのパス
81
+ * `options`:
32
82
 
33
- * `.replay` ファイルを解析して、プレイヤーごとの詳細情報を取得
34
- * `bot`: Botプレイヤーを含めるかどうか(デフォルト: `false`)
35
- * `sort`: 順位でソートするか(デフォルト: `true`)
83
+ * `bot`(boolean):botプレイヤーを結果に含めるか(デフォルトfalse)
84
+ * `sort`(boolean):順位でソートするか(デフォルトtrue)
85
+ * 返り値はPromiseで、`rawPlayerData`と`processedPlayerInfo`を含むオブジェクトを返す
36
86
 
37
- ### `mergeScores(scoreArrays: ProcessedMatch[][]): MergedPartyResult[]`
87
+ ### `mergeScores(scoreArrays)`
38
88
 
39
- * 複数のマッチを統合してパーティ単位の統計を作成
89
+ * 複数マッチのスコア配列をパーティ単位でマージする
90
+ * 返り値はマージされたスコア配列
40
91
 
41
- ### `sortScores(partyResults: MergedPartyResult[]): MergedPartyResult[]`
92
+ ### `sortScores(scoreArray)`
42
93
 
43
- * Fortnite公式基準でスコア順にソート(スコア → VictoryRoyale数 → 平均キル → 平均順位 → 生存時間)
94
+ * 公式準拠のルールでスコアをソートする
95
+ * 引数はマージ済みのスコア配列
44
96
 
45
- ## 開発者向け
97
+ ### `calculateScore({ matchDataPath, points, killCountUpperLimit, killPointMultiplier })`
46
98
 
47
- * このパッケージは自己完結型の.NETバイナリを含みます(OSにより異なる)
48
- * 実行にはNode.js v22以上を推奨
99
+ * `matchDataPath`:`ReplayAnalysis` の `result.processedPlayerInfo` を保存した JSON ファイルのパス(ファイル名は任意でOK)
100
+ * `points`:順位に対するポイント設定(例:{ 1: 11, 2: 6, ... })
101
+ * `killCountUpperLimit`:キル数制限(nullで無制限)
102
+ * `killPointMultiplier`:キル数倍率(例:1なら1キル1ポイント、2なら1キル2ポイント)
49
103
 
50
- ## ライセンス
104
+ ## 動作環境
51
105
 
52
- MIT License
106
+ * Node.js v22以上
107
+ * Windows / Linux対応(Macは未対応)
108
+ * C#で作られた自己完結バイナリが`CSproj/bin/Release/net8.0/`配下に同補されていること
53
109
 
54
- ## リポジトリ
110
+ ## 注意事項
55
111
 
56
- [https://github.com/yuyutti/Fortnite_Replay_Analysis](https://github.com/yuyutti/Fortnite_Replay_Analysis)
112
+ * リプレイファイルはディレクトリに1つ以上`.replay`ファイルが必要
113
+ * ディレクトリ内に複数ファイルある場合は現状最初の1つのみ処理される
114
+ * 何か問題起こっても俺は責任追わない
115
+ * このリポジトリをフォークする際は、GitHubの「Fork」ボタンからフォークしてください。
116
+ git cloneして新しく別リポジトリを作るのではなく、GitHub上のフォーク機能を使っていただけると、変更履歴を正しく追えます。
117
+ ご協力よろしくお願いします!
package/index.js CHANGED
@@ -103,6 +103,53 @@ function ReplayAnalysis(replayFileDir, { bot = false, sort = true } = {}) { // F
103
103
  });
104
104
  }
105
105
 
106
+ async function calculateScore({ matchDataPath, points, killCountUpperLimit = null, killPointMultiplier = 1 } = {}) {
107
+ if (!matchDataPath || !fs.existsSync(matchDataPath)) {
108
+ throw new Error(`Match data file not found: ${matchDataPath}`);
109
+ }
110
+ if (!points || typeof points !== 'object' || Object.keys(points).length === 0) {
111
+ throw new Error('Points configuration is required and must be a non-empty object.');
112
+ }
113
+ if (killCountUpperLimit !== null && (typeof killCountUpperLimit !== 'number' || killCountUpperLimit < 0)) {
114
+ throw new Error('killCountUpperLimit must be a non-negative number or null.');
115
+ }
116
+
117
+ const playerInfo = JSON.parse(fs.readFileSync(path.join(matchDataPath), 'utf8'));
118
+ const partyScore = playerInfo.reduce((acc, player) => {
119
+ if (!acc[player.partyNumber]) {
120
+ const limitedKills = killCountUpperLimit == null
121
+ ? (player.TeamKills || 0)
122
+ : Math.min(player.TeamKills || 0, killCountUpperLimit);
123
+ acc[player.partyNumber] = {
124
+ partyPlacement: player.Placement,
125
+ partyNumber: player.partyNumber,
126
+ partyKills: limitedKills,
127
+ partyKillsNoLimit: player.TeamKills || 0,
128
+ partyScore: (points[player.Placement] ?? 0) + ((limitedKills) * killPointMultiplier),
129
+ partyPoint: points[player.Placement] ?? 0,
130
+ partyVictoryRoyale: player.Placement === 1,
131
+ partyKillsList: [],
132
+ partyAliveTimeList: [],
133
+ partyMemberList: [],
134
+ partyMemberIdList: [],
135
+ };
136
+ }
137
+
138
+ // キル数の加算
139
+ acc[player.partyNumber].partyKillsList.push(player.Kills || 0);
140
+ acc[player.partyNumber].partyAliveTimeList.push(player.aliveTime || 0);
141
+ acc[player.partyNumber].partyMemberList.push(player.PlayerName);
142
+ acc[player.partyNumber].partyMemberIdList.push(player.EpicId);
143
+
144
+ return acc;
145
+ }, {});
146
+
147
+ let result = Object.values(partyScore);
148
+ result = sortScores(result);
149
+
150
+ return result;
151
+ }
152
+
106
153
  function mergeScores(scoreArrays) { // 複数マッチの結果をマージしてパーティごとに集計
107
154
  const map = new Map();
108
155
  scoreArrays.forEach(scores =>
@@ -227,6 +274,7 @@ function sumMaxAliveTime(partyAliveTimeList, partyAliveTimeByMatch) {
227
274
 
228
275
  module.exports = {
229
276
  ReplayAnalysis,
277
+ calculateScore,
230
278
  sortScores,
231
279
  mergeScores
232
280
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fortnite-replay-analysis",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Fortniteのリプレイ解析をNode.jsから呼べる自己完結型C#バイナリラッパー",
5
5
  "repository": {
6
6
  "type": "git",