@axiapps/bridge-metrics 0.1.0
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.
- package/dist/aggregationTypes.cjs +18 -0
- package/dist/aggregationTypes.d.cts +21 -0
- package/dist/aggregationTypes.d.ts +21 -0
- package/dist/aggregationTypes.js +1 -0
- package/dist/boonGeneration.cjs +308 -0
- package/dist/boonGeneration.d.cts +65 -0
- package/dist/boonGeneration.d.ts +65 -0
- package/dist/boonGeneration.js +16 -0
- package/dist/chunk-42DVJJLC.js +106 -0
- package/dist/chunk-4F55Q6K2.js +0 -0
- package/dist/chunk-ELKDB763.js +349 -0
- package/dist/chunk-FU74LJEM.js +77 -0
- package/dist/chunk-J3YCFY3C.js +37 -0
- package/dist/chunk-JP2ZL44R.js +18 -0
- package/dist/chunk-K2SRAMGC.js +0 -0
- package/dist/chunk-KRHODGVU.js +48 -0
- package/dist/chunk-LIGIXSSA.js +1383 -0
- package/dist/chunk-M2WR3JBQ.js +0 -0
- package/dist/chunk-PMVLNDZZ.js +279 -0
- package/dist/chunk-R5EJF5AW.js +147 -0
- package/dist/chunk-RGXSI3AI.js +298 -0
- package/dist/chunk-UFJJ6WLD.js +197 -0
- package/dist/chunk-WW5XFXGC.js +234 -0
- package/dist/chunk-ZFZS7JFU.js +10 -0
- package/dist/combatMetrics.cjs +251 -0
- package/dist/combatMetrics.d.cts +26 -0
- package/dist/combatMetrics.d.ts +26 -0
- package/dist/combatMetrics.js +21 -0
- package/dist/computePlayerAggregation.cjs +2042 -0
- package/dist/computePlayerAggregation.d.cts +249 -0
- package/dist/computePlayerAggregation.d.ts +249 -0
- package/dist/computePlayerAggregation.js +30 -0
- package/dist/conditionsMetrics.cjs +328 -0
- package/dist/conditionsMetrics.d.cts +67 -0
- package/dist/conditionsMetrics.d.ts +67 -0
- package/dist/conditionsMetrics.js +18 -0
- package/dist/constants.cjs +36 -0
- package/dist/constants.d.cts +18 -0
- package/dist/constants.d.ts +18 -0
- package/dist/constants.js +10 -0
- package/dist/dashboardMetrics.cjs +226 -0
- package/dist/dashboardMetrics.d.cts +29 -0
- package/dist/dashboardMetrics.d.ts +29 -0
- package/dist/dashboardMetrics.js +42 -0
- package/dist/dpsReportTypes.cjs +18 -0
- package/dist/dpsReportTypes.d.cts +294 -0
- package/dist/dpsReportTypes.d.ts +294 -0
- package/dist/dpsReportTypes.js +1 -0
- package/dist/index.cjs +2902 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +152 -0
- package/dist/metrics-methods.json +38 -0
- package/dist/metricsSettings.cjs +75 -0
- package/dist/metricsSettings.d.cts +23 -0
- package/dist/metricsSettings.d.ts +23 -0
- package/dist/metricsSettings.js +8 -0
- package/dist/professionUtils.cjs +265 -0
- package/dist/professionUtils.d.cts +10 -0
- package/dist/professionUtils.d.ts +10 -0
- package/dist/professionUtils.js +20 -0
- package/dist/reportMetrics.cjs +224 -0
- package/dist/reportMetrics.d.cts +85 -0
- package/dist/reportMetrics.d.ts +85 -0
- package/dist/reportMetrics.js +12 -0
- package/dist/resUtility.cjs +52 -0
- package/dist/resUtility.d.cts +5 -0
- package/dist/resUtility.d.ts +5 -0
- package/dist/resUtility.js +8 -0
- package/dist/roles.cjs +18 -0
- package/dist/roles.d.cts +17 -0
- package/dist/roles.d.ts +17 -0
- package/dist/roles.js +1 -0
- package/dist/rollup.cjs +378 -0
- package/dist/rollup.d.cts +103 -0
- package/dist/rollup.d.ts +103 -0
- package/dist/rollup.js +16 -0
- package/dist/statsMetrics.cjs +153 -0
- package/dist/statsMetrics.d.cts +39 -0
- package/dist/statsMetrics.d.ts +39 -0
- package/dist/statsMetrics.js +22 -0
- package/dist/timestampUtils.cjs +63 -0
- package/dist/timestampUtils.d.cts +12 -0
- package/dist/timestampUtils.d.ts +12 -0
- package/dist/timestampUtils.js +9 -0
- package/package.json +44 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
// src/rollup.ts
|
|
2
|
+
var ROLLUP_SOURCES_VERSION = 1;
|
|
3
|
+
var extractRollupSource = (payload) => {
|
|
4
|
+
const meta = payload?.meta || {};
|
|
5
|
+
const commanderRows = Array.isArray(payload?.stats?.commanderStats?.rows) ? payload.stats.commanderStats.rows : [];
|
|
6
|
+
const attendanceRows = Array.isArray(payload?.stats?.attendanceData) ? payload.stats.attendanceData : [];
|
|
7
|
+
return {
|
|
8
|
+
meta: {
|
|
9
|
+
id: meta.id,
|
|
10
|
+
dateStart: meta.dateStart,
|
|
11
|
+
dateEnd: meta.dateEnd,
|
|
12
|
+
generatedAt: meta.generatedAt
|
|
13
|
+
},
|
|
14
|
+
stats: {
|
|
15
|
+
commanderStats: {
|
|
16
|
+
rows: commanderRows.map((row) => ({
|
|
17
|
+
key: row?.key,
|
|
18
|
+
account: row?.account,
|
|
19
|
+
characterNames: Array.isArray(row?.characterNames) ? row.characterNames : [],
|
|
20
|
+
profession: row?.profession,
|
|
21
|
+
fights: row?.fights,
|
|
22
|
+
kills: row?.kills,
|
|
23
|
+
downs: row?.downs,
|
|
24
|
+
commanderDeaths: row?.commanderDeaths,
|
|
25
|
+
alliesDead: row?.alliesDead,
|
|
26
|
+
wins: row?.wins,
|
|
27
|
+
losses: row?.losses
|
|
28
|
+
}))
|
|
29
|
+
},
|
|
30
|
+
attendanceData: attendanceRows.map((row) => ({
|
|
31
|
+
account: row?.account,
|
|
32
|
+
characterNames: Array.isArray(row?.characterNames) ? row.characterNames : [],
|
|
33
|
+
combatTimeMs: row?.combatTimeMs,
|
|
34
|
+
squadTimeMs: row?.squadTimeMs,
|
|
35
|
+
classTimes: (Array.isArray(row?.classTimes) ? row.classTimes : []).map((entry) => ({
|
|
36
|
+
profession: entry?.profession,
|
|
37
|
+
timeMs: entry?.timeMs
|
|
38
|
+
}))
|
|
39
|
+
}))
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
var updateRollupSourcesForPublish = (options) => {
|
|
44
|
+
const { existingSources, currentReport, validIds, loadLocalReport } = options;
|
|
45
|
+
const sourcesById = /* @__PURE__ */ new Map();
|
|
46
|
+
existingSources.forEach((source) => {
|
|
47
|
+
const id = String(source?.meta?.id || "").trim();
|
|
48
|
+
if (id) sourcesById.set(id, source);
|
|
49
|
+
});
|
|
50
|
+
const currentId = String(currentReport?.meta?.id || "").trim();
|
|
51
|
+
if (currentId) {
|
|
52
|
+
sourcesById.set(currentId, extractRollupSource(currentReport));
|
|
53
|
+
}
|
|
54
|
+
const validIdSet = new Set(validIds.map((id) => String(id || "").trim()).filter(Boolean));
|
|
55
|
+
if (loadLocalReport) {
|
|
56
|
+
for (const id of validIdSet) {
|
|
57
|
+
if (sourcesById.has(id)) continue;
|
|
58
|
+
const localReport = loadLocalReport(id);
|
|
59
|
+
if (localReport) {
|
|
60
|
+
sourcesById.set(id, extractRollupSource(localReport));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const sources = Array.from(sourcesById.entries()).filter(([id]) => validIdSet.has(id)).map(([, source]) => source);
|
|
65
|
+
return {
|
|
66
|
+
version: ROLLUP_SOURCES_VERSION,
|
|
67
|
+
sources,
|
|
68
|
+
rollup: buildRollupData(sources)
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
var removeRollupSources = (file, deletedIds) => {
|
|
72
|
+
const deleted = new Set(deletedIds.map((id) => String(id || "").trim()).filter(Boolean));
|
|
73
|
+
const sources = file.sources.filter(
|
|
74
|
+
(source) => !deleted.has(String(source?.meta?.id || "").trim())
|
|
75
|
+
);
|
|
76
|
+
return {
|
|
77
|
+
version: ROLLUP_SOURCES_VERSION,
|
|
78
|
+
sources,
|
|
79
|
+
rollup: buildRollupData(sources)
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
var parseRollupSourcesFile = (data) => {
|
|
83
|
+
const candidate = data;
|
|
84
|
+
if (!candidate || typeof candidate !== "object") return null;
|
|
85
|
+
if (candidate.version !== ROLLUP_SOURCES_VERSION) return null;
|
|
86
|
+
if (!Array.isArray(candidate.sources)) return null;
|
|
87
|
+
if (!candidate.rollup || typeof candidate.rollup !== "object") return null;
|
|
88
|
+
return candidate;
|
|
89
|
+
};
|
|
90
|
+
var toFiniteNumber = (value) => {
|
|
91
|
+
const numeric = Number(value ?? 0);
|
|
92
|
+
return Number.isFinite(numeric) ? numeric : 0;
|
|
93
|
+
};
|
|
94
|
+
var parseTimestamp = (meta) => {
|
|
95
|
+
const candidates = [meta?.dateEnd, meta?.dateStart];
|
|
96
|
+
for (const candidate of candidates) {
|
|
97
|
+
if (!candidate) continue;
|
|
98
|
+
const parsed = new Date(candidate).getTime();
|
|
99
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
100
|
+
return parsed;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return 0;
|
|
104
|
+
};
|
|
105
|
+
var parseGeneratedTimestamp = (meta) => {
|
|
106
|
+
const generated = meta?.generatedAt ? new Date(meta.generatedAt).getTime() : 0;
|
|
107
|
+
if (Number.isFinite(generated) && generated > 0) {
|
|
108
|
+
return generated;
|
|
109
|
+
}
|
|
110
|
+
return parseTimestamp(meta);
|
|
111
|
+
};
|
|
112
|
+
var buildRaidKey = (report, fallbackIndex) => {
|
|
113
|
+
const dateStart = String(report?.meta?.dateStart || "").trim();
|
|
114
|
+
const dateEnd = String(report?.meta?.dateEnd || "").trim();
|
|
115
|
+
if (dateStart || dateEnd) {
|
|
116
|
+
return `${dateStart}|${dateEnd}`;
|
|
117
|
+
}
|
|
118
|
+
const id = String(report?.meta?.id || "").trim();
|
|
119
|
+
if (id) return id;
|
|
120
|
+
return `report-${fallbackIndex}`;
|
|
121
|
+
};
|
|
122
|
+
var choosePrimaryProfession = (professionTimeMs, fallback = "Unknown") => {
|
|
123
|
+
const entries = Object.entries(professionTimeMs).filter(([profession, timeMs]) => profession && timeMs > 0).sort((a, b) => {
|
|
124
|
+
const delta = b[1] - a[1];
|
|
125
|
+
if (delta !== 0) return delta;
|
|
126
|
+
return a[0].localeCompare(b[0]);
|
|
127
|
+
});
|
|
128
|
+
return entries[0]?.[0] || fallback;
|
|
129
|
+
};
|
|
130
|
+
var chooseMostCommonProfession = (professionCounts, fallback = "Unknown") => {
|
|
131
|
+
const entries = Object.entries(professionCounts).filter(([profession, count]) => profession && count > 0).sort((a, b) => {
|
|
132
|
+
const delta = b[1] - a[1];
|
|
133
|
+
if (delta !== 0) return delta;
|
|
134
|
+
return a[0].localeCompare(b[0]);
|
|
135
|
+
});
|
|
136
|
+
return entries[0]?.[0] || fallback;
|
|
137
|
+
};
|
|
138
|
+
var buildProfessionBreakdown = (professionRuns) => Object.entries(professionRuns).filter(([profession, runs]) => profession && runs > 0).sort((a, b) => {
|
|
139
|
+
const delta = b[1] - a[1];
|
|
140
|
+
if (delta !== 0) return delta;
|
|
141
|
+
return a[0].localeCompare(b[0]);
|
|
142
|
+
}).map(([profession, runs]) => ({ profession, runs }));
|
|
143
|
+
var buildRollupData = (reports) => {
|
|
144
|
+
const uniqueRaidKeys = /* @__PURE__ */ new Set();
|
|
145
|
+
const reportsByRaid = /* @__PURE__ */ new Map();
|
|
146
|
+
reports.forEach((report, index) => {
|
|
147
|
+
const raidKey = buildRaidKey(report, index);
|
|
148
|
+
uniqueRaidKeys.add(raidKey);
|
|
149
|
+
const generatedTs = parseGeneratedTimestamp(report?.meta);
|
|
150
|
+
if (!reportsByRaid.has(raidKey)) {
|
|
151
|
+
reportsByRaid.set(raidKey, []);
|
|
152
|
+
}
|
|
153
|
+
reportsByRaid.get(raidKey).push({ report, generatedTs, index });
|
|
154
|
+
});
|
|
155
|
+
const raidGroups = Array.from(reportsByRaid.values()).sort((a, b) => {
|
|
156
|
+
const aLatest = Math.max(...a.map((entry) => entry.generatedTs || 0));
|
|
157
|
+
const bLatest = Math.max(...b.map((entry) => entry.generatedTs || 0));
|
|
158
|
+
if (bLatest !== aLatest) return bLatest - aLatest;
|
|
159
|
+
const aIndex = Math.max(...a.map((entry) => entry.index));
|
|
160
|
+
const bIndex = Math.max(...b.map((entry) => entry.index));
|
|
161
|
+
return bIndex - aIndex;
|
|
162
|
+
}).map((entries) => [...entries].sort((a, b) => {
|
|
163
|
+
if (b.generatedTs !== a.generatedTs) return b.generatedTs - a.generatedTs;
|
|
164
|
+
return b.index - a.index;
|
|
165
|
+
}));
|
|
166
|
+
const commanders = /* @__PURE__ */ new Map();
|
|
167
|
+
const players = /* @__PURE__ */ new Map();
|
|
168
|
+
let reportsWithCommanderDetails = 0;
|
|
169
|
+
let reportsMissingCommanderDetails = 0;
|
|
170
|
+
let reportsWithAttendanceDetails = 0;
|
|
171
|
+
let reportsMissingAttendanceDetails = 0;
|
|
172
|
+
let includedRaidGroups = 0;
|
|
173
|
+
let includedSourceReports = 0;
|
|
174
|
+
raidGroups.forEach((group) => {
|
|
175
|
+
const attendanceSource = group.find((entry) => Array.isArray(entry.report?.stats?.attendanceData) && entry.report.stats.attendanceData.length > 0) || null;
|
|
176
|
+
const attendanceReport = attendanceSource?.report || null;
|
|
177
|
+
const attendanceTimestamp = attendanceReport ? parseTimestamp(attendanceReport.meta) : 0;
|
|
178
|
+
const attendanceRows = Array.isArray(attendanceReport?.stats?.attendanceData) ? attendanceReport.stats.attendanceData : [];
|
|
179
|
+
if (attendanceRows.length > 0) {
|
|
180
|
+
reportsWithAttendanceDetails += 1;
|
|
181
|
+
} else {
|
|
182
|
+
reportsMissingAttendanceDetails += 1;
|
|
183
|
+
}
|
|
184
|
+
const latestCommanderRowsByAccount = /* @__PURE__ */ new Map();
|
|
185
|
+
group.forEach((entry) => {
|
|
186
|
+
const report = entry.report;
|
|
187
|
+
const timestamp = parseTimestamp(report?.meta);
|
|
188
|
+
const commanderRows2 = Array.isArray(report?.stats?.commanderStats?.rows) ? report.stats.commanderStats.rows : [];
|
|
189
|
+
commanderRows2.forEach((row) => {
|
|
190
|
+
const account = String(row?.account || row?.key || "").trim();
|
|
191
|
+
if (!account) return;
|
|
192
|
+
const existing = latestCommanderRowsByAccount.get(account);
|
|
193
|
+
if (!existing) {
|
|
194
|
+
latestCommanderRowsByAccount.set(account, { row, timestamp, generatedTs: entry.generatedTs, index: entry.index });
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const shouldReplace = entry.generatedTs > existing.generatedTs || entry.generatedTs === existing.generatedTs && entry.index > existing.index;
|
|
198
|
+
if (shouldReplace) {
|
|
199
|
+
latestCommanderRowsByAccount.set(account, { row, timestamp, generatedTs: entry.generatedTs, index: entry.index });
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
if (latestCommanderRowsByAccount.size > 0) {
|
|
204
|
+
reportsWithCommanderDetails += 1;
|
|
205
|
+
} else {
|
|
206
|
+
reportsMissingCommanderDetails += 1;
|
|
207
|
+
}
|
|
208
|
+
if (attendanceRows.length === 0 || latestCommanderRowsByAccount.size === 0) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
includedRaidGroups += 1;
|
|
212
|
+
includedSourceReports += group.length;
|
|
213
|
+
attendanceRows.forEach((row) => {
|
|
214
|
+
const account = String(row?.account || "").trim();
|
|
215
|
+
if (!account || account === "Unknown") return;
|
|
216
|
+
const existing = players.get(account) || {
|
|
217
|
+
account,
|
|
218
|
+
characterNames: /* @__PURE__ */ new Set(),
|
|
219
|
+
professionTimeMs: {},
|
|
220
|
+
professionRuns: {},
|
|
221
|
+
runs: 0,
|
|
222
|
+
combatTimeMs: 0,
|
|
223
|
+
squadTimeMs: 0,
|
|
224
|
+
lastSeenTs: 0
|
|
225
|
+
};
|
|
226
|
+
existing.runs += 1;
|
|
227
|
+
existing.combatTimeMs += Math.max(0, toFiniteNumber(row?.combatTimeMs));
|
|
228
|
+
existing.squadTimeMs += Math.max(0, toFiniteNumber(row?.squadTimeMs));
|
|
229
|
+
existing.lastSeenTs = Math.max(existing.lastSeenTs, attendanceTimestamp);
|
|
230
|
+
if (Array.isArray(row?.characterNames)) {
|
|
231
|
+
row.characterNames.forEach((name) => {
|
|
232
|
+
const normalized = String(name || "").trim();
|
|
233
|
+
if (normalized) existing.characterNames.add(normalized);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const classTimes = Array.isArray(row?.classTimes) ? row.classTimes : [];
|
|
237
|
+
const professionsThisRun = /* @__PURE__ */ new Set();
|
|
238
|
+
classTimes.forEach((classRow) => {
|
|
239
|
+
const profession = String(classRow?.profession || "").trim();
|
|
240
|
+
if (!profession || profession === "Unknown") return;
|
|
241
|
+
const timeMs = Math.max(0, toFiniteNumber(classRow?.timeMs));
|
|
242
|
+
existing.professionTimeMs[profession] = (existing.professionTimeMs[profession] || 0) + timeMs;
|
|
243
|
+
if (timeMs > 0) professionsThisRun.add(profession);
|
|
244
|
+
});
|
|
245
|
+
professionsThisRun.forEach((profession) => {
|
|
246
|
+
existing.professionRuns[profession] = (existing.professionRuns[profession] || 0) + 1;
|
|
247
|
+
});
|
|
248
|
+
players.set(account, existing);
|
|
249
|
+
});
|
|
250
|
+
latestCommanderRowsByAccount.forEach(({ row, timestamp }) => {
|
|
251
|
+
const account = String(row?.account || row?.key || "").trim();
|
|
252
|
+
if (!account) return;
|
|
253
|
+
const existing = commanders.get(account) || {
|
|
254
|
+
account,
|
|
255
|
+
characterNames: /* @__PURE__ */ new Set(),
|
|
256
|
+
professionCounts: {},
|
|
257
|
+
runs: 0,
|
|
258
|
+
fightsLed: 0,
|
|
259
|
+
kills: 0,
|
|
260
|
+
downs: 0,
|
|
261
|
+
commanderDeaths: 0,
|
|
262
|
+
alliesDead: 0,
|
|
263
|
+
wins: 0,
|
|
264
|
+
losses: 0,
|
|
265
|
+
lastSeenTs: 0
|
|
266
|
+
};
|
|
267
|
+
existing.runs += 1;
|
|
268
|
+
existing.fightsLed += Math.max(0, toFiniteNumber(row?.fights));
|
|
269
|
+
existing.kills += Math.max(0, toFiniteNumber(row?.kills));
|
|
270
|
+
existing.downs += Math.max(0, toFiniteNumber(row?.downs));
|
|
271
|
+
existing.commanderDeaths += Math.max(0, toFiniteNumber(row?.commanderDeaths));
|
|
272
|
+
existing.alliesDead += Math.max(0, toFiniteNumber(row?.alliesDead));
|
|
273
|
+
existing.wins += Math.max(0, toFiniteNumber(row?.wins));
|
|
274
|
+
existing.losses += Math.max(0, toFiniteNumber(row?.losses));
|
|
275
|
+
existing.lastSeenTs = Math.max(existing.lastSeenTs, timestamp);
|
|
276
|
+
if (Array.isArray(row?.characterNames)) {
|
|
277
|
+
row.characterNames.forEach((name) => {
|
|
278
|
+
const normalized = String(name || "").trim();
|
|
279
|
+
if (normalized) existing.characterNames.add(normalized);
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
const profession = String(row?.profession || "").trim();
|
|
283
|
+
if (profession) {
|
|
284
|
+
existing.professionCounts[profession] = (existing.professionCounts[profession] || 0) + 1;
|
|
285
|
+
}
|
|
286
|
+
commanders.set(account, existing);
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
const commanderRows = Array.from(commanders.values()).map((entry) => {
|
|
290
|
+
const kdr = entry.alliesDead > 0 ? entry.kills / entry.alliesDead : entry.kills;
|
|
291
|
+
return {
|
|
292
|
+
account: entry.account,
|
|
293
|
+
characterNames: Array.from(entry.characterNames.values()).sort((a, b) => a.localeCompare(b)),
|
|
294
|
+
profession: chooseMostCommonProfession(entry.professionCounts),
|
|
295
|
+
professionBreakdown: buildProfessionBreakdown(entry.professionCounts),
|
|
296
|
+
runs: entry.runs,
|
|
297
|
+
fightsLed: entry.fightsLed,
|
|
298
|
+
kills: entry.kills,
|
|
299
|
+
downs: entry.downs,
|
|
300
|
+
commanderDeaths: entry.commanderDeaths,
|
|
301
|
+
alliesDead: entry.alliesDead,
|
|
302
|
+
wins: entry.wins,
|
|
303
|
+
losses: entry.losses,
|
|
304
|
+
kdr,
|
|
305
|
+
lastSeenTs: entry.lastSeenTs
|
|
306
|
+
};
|
|
307
|
+
}).sort((a, b) => {
|
|
308
|
+
if (b.runs !== a.runs) return b.runs - a.runs;
|
|
309
|
+
if (b.fightsLed !== a.fightsLed) return b.fightsLed - a.fightsLed;
|
|
310
|
+
if (b.kills !== a.kills) return b.kills - a.kills;
|
|
311
|
+
return a.account.localeCompare(b.account);
|
|
312
|
+
});
|
|
313
|
+
const playerRows = Array.from(players.values()).map((entry) => ({
|
|
314
|
+
account: entry.account,
|
|
315
|
+
characterNames: Array.from(entry.characterNames.values()).sort((a, b) => a.localeCompare(b)),
|
|
316
|
+
profession: choosePrimaryProfession(entry.professionTimeMs),
|
|
317
|
+
professionBreakdown: buildProfessionBreakdown(entry.professionRuns),
|
|
318
|
+
runs: entry.runs,
|
|
319
|
+
combatTimeMs: entry.combatTimeMs,
|
|
320
|
+
squadTimeMs: entry.squadTimeMs,
|
|
321
|
+
lastSeenTs: entry.lastSeenTs
|
|
322
|
+
})).sort((a, b) => {
|
|
323
|
+
if (b.runs !== a.runs) return b.runs - a.runs;
|
|
324
|
+
if (b.lastSeenTs !== a.lastSeenTs) return b.lastSeenTs - a.lastSeenTs;
|
|
325
|
+
if (b.squadTimeMs !== a.squadTimeMs) return b.squadTimeMs - a.squadTimeMs;
|
|
326
|
+
return a.account.localeCompare(b.account);
|
|
327
|
+
});
|
|
328
|
+
return {
|
|
329
|
+
commanderRows,
|
|
330
|
+
playerRows,
|
|
331
|
+
sourceReports: reports.length,
|
|
332
|
+
uniqueRaids: includedRaidGroups,
|
|
333
|
+
duplicateReportsCollapsed: Math.max(0, includedSourceReports - includedRaidGroups),
|
|
334
|
+
raidsSkippedMissingRequiredData: Math.max(0, raidGroups.length - includedRaidGroups),
|
|
335
|
+
reportsWithCommanderDetails,
|
|
336
|
+
reportsMissingCommanderDetails,
|
|
337
|
+
reportsWithAttendanceDetails,
|
|
338
|
+
reportsMissingAttendanceDetails
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
export {
|
|
343
|
+
ROLLUP_SOURCES_VERSION,
|
|
344
|
+
extractRollupSource,
|
|
345
|
+
updateRollupSourcesForPublish,
|
|
346
|
+
removeRollupSources,
|
|
347
|
+
parseRollupSourcesFile,
|
|
348
|
+
buildRollupData
|
|
349
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeDownContribution,
|
|
3
|
+
computeOutgoingCrowdControl,
|
|
4
|
+
computeSquadBarrier,
|
|
5
|
+
computeSquadHealing,
|
|
6
|
+
resolveDisruptionValue
|
|
7
|
+
} from "./chunk-R5EJF5AW.js";
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_DISRUPTION_METHOD
|
|
10
|
+
} from "./chunk-KRHODGVU.js";
|
|
11
|
+
|
|
12
|
+
// src/dashboardMetrics.ts
|
|
13
|
+
var getPlayerDamage = (player) => player.dpsAll?.[0]?.damage || 0;
|
|
14
|
+
var getPlayerDps = (player) => player.dpsAll?.[0]?.dps || 0;
|
|
15
|
+
var getPlayerCleanses = (player) => (player.support?.[0]?.condiCleanse || 0) + (player.support?.[0]?.condiCleanseSelf || 0);
|
|
16
|
+
var getPlayerStrips = (player, method = DEFAULT_DISRUPTION_METHOD) => {
|
|
17
|
+
const support = player.support?.[0];
|
|
18
|
+
const count = Number(support?.boonStrips ?? 0);
|
|
19
|
+
const durationMs = Number(support?.boonStripsTime ?? 0);
|
|
20
|
+
return resolveDisruptionValue(count, durationMs, method);
|
|
21
|
+
};
|
|
22
|
+
var getPlayerResurrects = (player) => player.support?.[0]?.resurrects || 0;
|
|
23
|
+
var getPlayerDistanceToTag = (player) => {
|
|
24
|
+
const stats = player.statsAll?.[0];
|
|
25
|
+
const distToCom = stats?.distToCom;
|
|
26
|
+
if (distToCom !== void 0 && distToCom !== null) {
|
|
27
|
+
return distToCom;
|
|
28
|
+
}
|
|
29
|
+
return stats?.stackDist || 0;
|
|
30
|
+
};
|
|
31
|
+
var getPlayerBreakbarDamage = (player) => player.dpsAll?.[0]?.breakbarDamage || 0;
|
|
32
|
+
var getPlayerDamageTaken = (player) => player.defenses?.[0]?.damageTaken || 0;
|
|
33
|
+
var getPlayerDeaths = (player) => player.defenses?.[0]?.deadCount || 0;
|
|
34
|
+
var getPlayerDodges = (player) => player.defenses?.[0]?.dodgeCount || 0;
|
|
35
|
+
var getPlayerMissed = (player) => player.defenses?.[0]?.missedCount || 0;
|
|
36
|
+
var getPlayerBlocked = (player) => player.defenses?.[0]?.blockedCount || 0;
|
|
37
|
+
var getPlayerEvaded = (player) => player.defenses?.[0]?.evadedCount || 0;
|
|
38
|
+
var getPlayerDownsTaken = (player) => player.defenses?.[0]?.downCount || 0;
|
|
39
|
+
var getTargetStatTotal = (player, field) => {
|
|
40
|
+
let total = 0;
|
|
41
|
+
const statsTargets = player.statsTargets || [];
|
|
42
|
+
for (const targetStats of statsTargets) {
|
|
43
|
+
if (targetStats && targetStats.length > 0) {
|
|
44
|
+
total += Number(targetStats[0][field] || 0);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return total;
|
|
48
|
+
};
|
|
49
|
+
var getPlayerOutgoingInterrupts = (player) => getTargetStatTotal(player, "interrupts");
|
|
50
|
+
var getPlayerDashboardTotals = (player, method = DEFAULT_DISRUPTION_METHOD) => ({
|
|
51
|
+
downContrib: computeDownContribution(player),
|
|
52
|
+
cleanses: getPlayerCleanses(player),
|
|
53
|
+
strips: getPlayerStrips(player, method),
|
|
54
|
+
healing: computeSquadHealing(player),
|
|
55
|
+
barrier: computeSquadBarrier(player),
|
|
56
|
+
cc: computeOutgoingCrowdControl(player, method)
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export {
|
|
60
|
+
getPlayerDamage,
|
|
61
|
+
getPlayerDps,
|
|
62
|
+
getPlayerCleanses,
|
|
63
|
+
getPlayerStrips,
|
|
64
|
+
getPlayerResurrects,
|
|
65
|
+
getPlayerDistanceToTag,
|
|
66
|
+
getPlayerBreakbarDamage,
|
|
67
|
+
getPlayerDamageTaken,
|
|
68
|
+
getPlayerDeaths,
|
|
69
|
+
getPlayerDodges,
|
|
70
|
+
getPlayerMissed,
|
|
71
|
+
getPlayerBlocked,
|
|
72
|
+
getPlayerEvaded,
|
|
73
|
+
getPlayerDownsTaken,
|
|
74
|
+
getTargetStatTotal,
|
|
75
|
+
getPlayerOutgoingInterrupts,
|
|
76
|
+
getPlayerDashboardTotals
|
|
77
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TIMESTAMP_MS_THRESHOLD
|
|
3
|
+
} from "./chunk-ZFZS7JFU.js";
|
|
4
|
+
|
|
5
|
+
// src/timestampUtils.ts
|
|
6
|
+
var parseTimestamp = (value) => {
|
|
7
|
+
if (value === void 0 || value === null || value === "") return 0;
|
|
8
|
+
if (typeof value === "number") {
|
|
9
|
+
if (!Number.isFinite(value) || value <= 0) return 0;
|
|
10
|
+
return value > TIMESTAMP_MS_THRESHOLD ? value : value * 1e3;
|
|
11
|
+
}
|
|
12
|
+
if (value instanceof Date) {
|
|
13
|
+
const ms = value.getTime();
|
|
14
|
+
return Number.isFinite(ms) && ms > 0 ? ms : 0;
|
|
15
|
+
}
|
|
16
|
+
const str = String(value).trim();
|
|
17
|
+
if (!str) return 0;
|
|
18
|
+
const numeric = Number(str);
|
|
19
|
+
if (Number.isFinite(numeric) && numeric > 0) {
|
|
20
|
+
return numeric > TIMESTAMP_MS_THRESHOLD ? numeric : numeric * 1e3;
|
|
21
|
+
}
|
|
22
|
+
const parsed = Date.parse(str);
|
|
23
|
+
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
24
|
+
const normalized = str.replace(/([+-]\d{2})$/, "$1:00");
|
|
25
|
+
const reparsed = Date.parse(normalized);
|
|
26
|
+
return Number.isFinite(reparsed) && reparsed > 0 ? reparsed : 0;
|
|
27
|
+
};
|
|
28
|
+
var resolveFightTimestamp = (details, log) => {
|
|
29
|
+
return parseTimestamp(
|
|
30
|
+
details?.timeStartStd ?? details?.timeStart ?? details?.timeEndStd ?? details?.timeEnd ?? details?.timeStartText ?? details?.timeEndText ?? details?.uploadTime ?? log?.uploadTime
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
parseTimestamp,
|
|
36
|
+
resolveFightTimestamp
|
|
37
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RES_UTILITY_IDS,
|
|
3
|
+
RES_UTILITY_NAME_MATCHES
|
|
4
|
+
} from "./chunk-42DVJJLC.js";
|
|
5
|
+
|
|
6
|
+
// src/resUtility.ts
|
|
7
|
+
var isResUtilitySkill = (id, skillMap) => {
|
|
8
|
+
if (RES_UTILITY_IDS.has(id)) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
const entry = skillMap?.[`s${id}`] || skillMap?.[`${id}`];
|
|
12
|
+
const name = entry?.name?.toLowerCase() || "";
|
|
13
|
+
return RES_UTILITY_NAME_MATCHES.some((match) => name.includes(match));
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
isResUtilitySkill
|
|
18
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// src/metrics-methods.json
|
|
2
|
+
var metrics_methods_default = {
|
|
3
|
+
specVersion: "v5",
|
|
4
|
+
methods: {
|
|
5
|
+
count: {
|
|
6
|
+
label: "Count Events",
|
|
7
|
+
summary: "Counts each CC/strip event once.",
|
|
8
|
+
implications: [
|
|
9
|
+
"Simple and stable across EI versions.",
|
|
10
|
+
"Multi-hit skills can inflate totals."
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
duration: {
|
|
14
|
+
label: "Duration (Seconds)",
|
|
15
|
+
summary: "Uses total CC/strip duration in seconds.",
|
|
16
|
+
implications: [
|
|
17
|
+
"Reflects control impact more directly.",
|
|
18
|
+
"Totals represent time, not event count."
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
tiered: {
|
|
22
|
+
label: "Tiered Impact",
|
|
23
|
+
summary: "Weights events based on average duration tiers.",
|
|
24
|
+
implications: [
|
|
25
|
+
"Balances short vs long CC/strip effects.",
|
|
26
|
+
"Uses averaged durations per player."
|
|
27
|
+
],
|
|
28
|
+
tiers: {
|
|
29
|
+
shortMs: 500,
|
|
30
|
+
mediumMs: 1500,
|
|
31
|
+
weights: {
|
|
32
|
+
short: 0.5,
|
|
33
|
+
medium: 1,
|
|
34
|
+
long: 2
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/metricsSettings.ts
|
|
42
|
+
var METRICS_SPEC = metrics_methods_default;
|
|
43
|
+
var DEFAULT_DISRUPTION_METHOD = "count";
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
METRICS_SPEC,
|
|
47
|
+
DEFAULT_DISRUPTION_METHOD
|
|
48
|
+
};
|