@sjtdev/koishi-plugin-dota2tracker 1.1.5 → 1.1.6-hotfix
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/lib/index.js +40 -27
- package/package.json +1 -1
- package/readme.md +19 -11
- package/template/match/match_1.ejs +6 -6
- package/template/match/match_2.ejs +4 -4
package/lib/index.js
CHANGED
|
@@ -525,11 +525,21 @@ function getFormattedMatchData(match) {
|
|
|
525
525
|
["radiant", "dire"].forEach((team) => {
|
|
526
526
|
match[team] = { killsCount: match[team + "Kills"]?.reduce((acc, cva) => acc + cva, 0) ?? 0, damageReceived: 0, heroDamage: 0, networth: 0, experience: 0 };
|
|
527
527
|
});
|
|
528
|
+
if (!match.parsedDateTime) {
|
|
529
|
+
match.players.reduce((acc, player) => {
|
|
530
|
+
if (player.isRadiant) {
|
|
531
|
+
acc.radiant.killsCount += player.kills;
|
|
532
|
+
} else {
|
|
533
|
+
acc.dire.killsCount += player.kills;
|
|
534
|
+
}
|
|
535
|
+
return acc;
|
|
536
|
+
}, match);
|
|
537
|
+
}
|
|
528
538
|
match.party = {};
|
|
529
539
|
let party_index = 0;
|
|
530
540
|
const party_mark = ["I", "II", "III", "IV"];
|
|
531
541
|
let heroOrderList = {};
|
|
532
|
-
for (let hero of match.pickBans) {
|
|
542
|
+
for (let hero of match.pickBans ?? []) {
|
|
533
543
|
if (hero.isPick)
|
|
534
544
|
heroOrderList[hero.heroId] = hero.order;
|
|
535
545
|
}
|
|
@@ -561,27 +571,29 @@ function getFormattedMatchData(match) {
|
|
|
561
571
|
};
|
|
562
572
|
player.killContribution = (player.kills + player.assists) / match[player.team].killsCount;
|
|
563
573
|
player.deathContribution = player.deaths / match[player.team === "radiant" ? "dire" : player.team].killsCount;
|
|
564
|
-
player.damageReceived = player.stats?.heroDamageReport?.receivedTotal
|
|
574
|
+
player.damageReceived = (player.stats?.heroDamageReport?.receivedTotal?.physicalDamage ?? 0) + (player.stats?.heroDamageReport?.receivedTotal?.magicalDamage ?? 0) + (player.stats?.heroDamageReport?.receivedTotal?.pureDamage ?? 0);
|
|
565
575
|
match[player.team].heroDamage = (match[player.team].heroDamage ?? 0) + player.heroDamage;
|
|
566
576
|
match[player.team].damageReceived = (match[player.team].damageReceived ?? 0) + player.damageReceived;
|
|
567
577
|
match[player.team].networth += player.networth;
|
|
568
578
|
match[player.team].experience += Math.floor(player.experiencePerMinute / 60 * match.durationSeconds);
|
|
569
579
|
player.titles = [];
|
|
570
580
|
player.mvpScore = // 计算MVP分数
|
|
571
|
-
player.kills * 5 + player.assists * 3 + player.stats.heroDamageReport
|
|
581
|
+
player.kills * 5 + player.assists * 3 + (player.stats.heroDamageReport?.dealtTotal.stunDuration ?? 0) / 100 * 0.1 + (player.stats.heroDamageReport?.dealtTotal.disableDuration ?? 0) / 100 * 0.05 + (player.stats.heroDamageReport?.dealtTotal.slowDuration ?? 0) / 100 * 0.025 + player.heroDamage * 1e-3 + player.towerDamage * 0.01 + player.heroHealing * 2e-3 + player.imp * 0.25;
|
|
572
582
|
player.order = heroOrderList[player.hero.id];
|
|
573
583
|
if (player.partyId != null) {
|
|
574
584
|
if (!match.party[player.partyId])
|
|
575
585
|
match.party[player.partyId] = party_mark[party_index++];
|
|
576
586
|
}
|
|
577
|
-
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
acc[key]
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
587
|
+
if (match.parsedDateTime) {
|
|
588
|
+
const maxStackCountsByAbilityOrItem = player.stats.matchPlayerBuffEvent.reduce((acc, event) => {
|
|
589
|
+
const key = event.abilityId !== null ? `ability-${event.abilityId}` : `item-${event.itemId}`;
|
|
590
|
+
if (!acc[key] || event.stackCount > acc[key].stackCount) {
|
|
591
|
+
acc[key] = event;
|
|
592
|
+
}
|
|
593
|
+
return acc;
|
|
594
|
+
}, {});
|
|
595
|
+
player.stats.matchPlayerBuffEvent.splice(0, player.stats.matchPlayerBuffEvent.length, ...Object.values(maxStackCountsByAbilityOrItem));
|
|
596
|
+
}
|
|
585
597
|
switch (player.lane) {
|
|
586
598
|
case "SAFE_LANE":
|
|
587
599
|
player.laneResult = laneResult[player.isRadiant ? "bottom" : "top"][player.team];
|
|
@@ -726,18 +738,20 @@ function getFormattedMatchData(match) {
|
|
|
726
738
|
).titles.push({ name: "魂", color: "#6cf" });
|
|
727
739
|
findMaxByProperty("networth").titles.push({ name: "富", color: "#FFD700" });
|
|
728
740
|
findMaxByProperty("experiencePerMinute").titles.push({ name: "睿", color: "#8888FF" });
|
|
729
|
-
match.
|
|
730
|
-
|
|
731
|
-
|
|
741
|
+
if (match.parsedDateTime) {
|
|
742
|
+
match.players.reduce(
|
|
743
|
+
(max, player) => player.stats.heroDamageReport.dealtTotal.stunDuration + player.stats.heroDamageReport.dealtTotal.disableDuration / 2 + player.stats.heroDamageReport.dealtTotal.slowDuration / 4 > max.stats.heroDamageReport.dealtTotal.stunDuration + max.stats.heroDamageReport.dealtTotal.disableDuration / 2 + max.stats.heroDamageReport.dealtTotal.slowDuration / 4 ? player : max
|
|
744
|
+
).titles.push({ name: "控", color: "#FF00FF" });
|
|
745
|
+
match.players.reduce(
|
|
746
|
+
(max, player) => player.stats.heroDamageReport.receivedTotal.physicalDamage + player.stats.heroDamageReport.receivedTotal.magicalDamage + player.stats.heroDamageReport.receivedTotal.pureDamage > max.stats.heroDamageReport.receivedTotal.physicalDamage + max.stats.heroDamageReport.receivedTotal.magicalDamage + max.stats.heroDamageReport.receivedTotal.pureDamage ? player : max
|
|
747
|
+
).titles.push({ name: "耐", color: "#84A1C7" });
|
|
748
|
+
}
|
|
732
749
|
findMaxByProperty("heroDamage").titles.push({ name: "爆", color: "#CC0088" });
|
|
733
750
|
findMaxByProperty("kills", "heroDamage").titles.push({ name: "破", color: "#DD0000" });
|
|
734
751
|
findMaxByProperty("deaths", "networth", void 0, void 0, "min" /* Min */).titles.push({ name: "鬼", color: "#CCCCCC" });
|
|
735
752
|
findMaxByProperty("assists", "heroDamage").titles.push({ name: "助", color: "#006400" });
|
|
736
753
|
findMaxByProperty("towerDamage", "heroDamage").titles.push({ name: "拆", color: "#FEDCBA" });
|
|
737
754
|
findMaxByProperty("heroHealing").titles.push({ name: "奶", color: "#00FF00" });
|
|
738
|
-
match.players.reduce(
|
|
739
|
-
(max, player) => player.stats.heroDamageReport.receivedTotal.physicalDamage + player.stats.heroDamageReport.receivedTotal.magicalDamage + player.stats.heroDamageReport.receivedTotal.pureDamage > max.stats.heroDamageReport.receivedTotal.physicalDamage + max.stats.heroDamageReport.receivedTotal.magicalDamage + max.stats.heroDamageReport.receivedTotal.pureDamage ? player : max
|
|
740
|
-
).titles.push({ name: "耐", color: "#84A1C7" });
|
|
741
755
|
match.players.reduce((lowest, player) => {
|
|
742
756
|
const currentContribution = (player.kills + player.assists) / match[player.team].KillsCount;
|
|
743
757
|
const lowestContribution = (lowest.kills + lowest.assists) / match[lowest.team].KillsCount;
|
|
@@ -1249,9 +1263,10 @@ async function apply(ctx, config) {
|
|
|
1249
1263
|
match = getFormattedMatchData(queryRes.data.data.match);
|
|
1250
1264
|
}
|
|
1251
1265
|
}
|
|
1252
|
-
if (match && match.parsedDateTime) {
|
|
1266
|
+
if (match && (match.parsedDateTime || import_moment.default.unix(match.endDateTime).isBefore((0, import_moment.default)().subtract(1, "hours")))) {
|
|
1253
1267
|
session.send(await ctx.puppeteer.render(genImageHTML(match, config.template_match, "match" /* Match */)));
|
|
1254
|
-
|
|
1268
|
+
if (match.parsedDateTime)
|
|
1269
|
+
ctx.database.upsert("dt_previous_query_results", (row) => [{ matchId: match.id, data: match, queryTime: /* @__PURE__ */ new Date() }]);
|
|
1255
1270
|
} else {
|
|
1256
1271
|
pendingMatches.push({ matchId, guilds: [{ platform: session.event.platform, guildId: session.event.guild.id, players: [] }] });
|
|
1257
1272
|
session.send("比赛尚未解析,将在解析完成后发布。");
|
|
@@ -1477,7 +1492,7 @@ async function apply(ctx, config) {
|
|
|
1477
1492
|
});
|
|
1478
1493
|
});
|
|
1479
1494
|
let heroes3 = Array.from(mergedMap.values());
|
|
1480
|
-
return heroes3.find((hero) => hero.names_cn.
|
|
1495
|
+
return heroes3.find((hero) => hero.names_cn.some((cn) => cn.toLowerCase() == input.toLowerCase()) || hero.shortName === input.toLowerCase() || hero.id == input);
|
|
1481
1496
|
}
|
|
1482
1497
|
__name(findingHero, "findingHero");
|
|
1483
1498
|
ctx.command("7.36 <input_data>", "查询7.36改动").option("refresh", "-r 重新获取数据").usage("可查询英雄改动并生成图片返回").example("7.36 小松许").action(async ({ session, options }, input_data) => {
|
|
@@ -1574,9 +1589,6 @@ async function apply(ctx, config) {
|
|
|
1574
1589
|
} else
|
|
1575
1590
|
session.send("https://www.dota2.com/patches/7.36");
|
|
1576
1591
|
});
|
|
1577
|
-
ctx.command("test <input_data>").option("a", "a").action(async ({ session, options }, input_data) => {
|
|
1578
|
-
console.log((await ctx.database.get("dt_7_36", [0]))[0].data);
|
|
1579
|
-
});
|
|
1580
1592
|
ctx.on("ready", async () => {
|
|
1581
1593
|
const tables = await ctx.database.tables;
|
|
1582
1594
|
if (!("dt_subscribed_guilds" in tables)) {
|
|
@@ -1713,10 +1725,10 @@ async function apply(ctx, config) {
|
|
|
1713
1725
|
} else {
|
|
1714
1726
|
let queryRes = await query(MATCH_INFO(pendingMatch.matchId));
|
|
1715
1727
|
if (queryRes.status == 200) {
|
|
1716
|
-
match =
|
|
1728
|
+
match = getFormattedMatchData(queryRes.data.data.match);
|
|
1717
1729
|
}
|
|
1718
1730
|
}
|
|
1719
|
-
if (match.parsedDateTime || import_moment.default.unix(match.
|
|
1731
|
+
if (match.parsedDateTime || import_moment.default.unix(match.endDateTime).isBefore((0, import_moment.default)().subtract(1, "hours"))) {
|
|
1720
1732
|
pendingMatches = pendingMatches.filter((item) => item.matchId != match.id);
|
|
1721
1733
|
const img = await ctx.puppeteer.render(genImageHTML(match, config.template_match, "match" /* Match */));
|
|
1722
1734
|
for (let commingGuild of pendingMatch.guilds) {
|
|
@@ -1743,7 +1755,8 @@ KDA:${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${
|
|
|
1743
1755
|
await ctx.broadcast([`${commingGuild.platform}:${commingGuild.guildId}`], broadMatchMessage + img);
|
|
1744
1756
|
ctx.logger.info(`已解析${match.id}并发布于${commingGuild.platform}:${commingGuild.guildId}。`);
|
|
1745
1757
|
}
|
|
1746
|
-
|
|
1758
|
+
if (match.parsedDateTime)
|
|
1759
|
+
ctx.database.upsert("dt_previous_query_results", (row) => [{ matchId: match.id, data: match, queryTime: /* @__PURE__ */ new Date() }]);
|
|
1747
1760
|
ctx.database.create("dt_sended_match_id", { matchId: match.id, sendTime: /* @__PURE__ */ new Date() });
|
|
1748
1761
|
} else
|
|
1749
1762
|
ctx.logger.info("比赛 %d 尚未解析完成,继续等待。", match.id);
|
|
@@ -1769,7 +1782,7 @@ function genImageHTML(data, template, type) {
|
|
|
1769
1782
|
moment: import_moment.default
|
|
1770
1783
|
};
|
|
1771
1784
|
let result = "";
|
|
1772
|
-
ejs.renderFile(templatePath, templateData, (err, html) => {
|
|
1785
|
+
ejs.renderFile(templatePath, templateData, { strict: false }, (err, html) => {
|
|
1773
1786
|
if (err)
|
|
1774
1787
|
throw err;
|
|
1775
1788
|
else
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -17,27 +17,35 @@ DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑
|
|
|
17
17
|
指令 <必填参数> [可选参数]
|
|
18
18
|
##### 订阅
|
|
19
19
|
(bot仅向已订阅群组推送信息)
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* `订阅本群`
|
|
21
|
+
* `取消订阅`
|
|
22
22
|
##### 绑定
|
|
23
23
|
(bot会追踪每位绑定玩家的最新对局)
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* `绑定 <玩家SteamID> [玩家别名]`
|
|
25
|
+
* `取消绑定`
|
|
26
|
+
* `改名 <新玩家别名>`
|
|
27
27
|
##### 查询
|
|
28
|
-
*
|
|
28
|
+
* `查询玩家 [SteamID|别名] [<--hero|-o> <英雄ID|英雄名|英雄常用别名>]`
|
|
29
29
|
返回一张图片,包含玩家各类信息。(缺省参数时并且调用者已绑定将自查)(输入--hero或-o并跟上查询英雄的参数时,将查询玩家指定英雄)
|
|
30
|
-
*
|
|
30
|
+
* `查询比赛 <比赛ID>`
|
|
31
31
|
返回一张图片,包含比赛对战信息。
|
|
32
|
-
*
|
|
32
|
+
* `查询最近比赛 [SteamID|别名]`
|
|
33
33
|
查询指定玩家的最近一场比赛,效果同上。(缺省参数时并且调用者已绑定将自查)
|
|
34
|
-
*
|
|
34
|
+
* `查询英雄 <英雄ID|英雄名|英雄常用别名>`
|
|
35
35
|
返回一张图片,包含英雄属性与技能详情。(此处英雄名为中文名)
|
|
36
|
-
* <
|
|
36
|
+
* <del>`查询英雄对战 <英雄ID|英雄名|英雄常用别名>`</del>
|
|
37
37
|
好像不是很实用
|
|
38
|
+
* `7.36 [英雄ID|英雄名|英雄常用别名] [--refresh|-r]`
|
|
39
|
+
查询官网7.36更新日志中指定英雄的改动信息
|
|
40
|
+
无英雄参数时直接返回官网7.36更新日志网址
|
|
41
|
+
首次使用时将缓存更新日志网页,若读取失败或出错,可添加`--refresh`或`-r`指令重新缓存
|
|
42
|
+
|
|
43
|
+
### 英雄ID|英雄名|英雄常用别名 列表
|
|
44
|
+
[dotaconstants_add.json](https://github.com/sjtdev/koishi-plugin-dota2tracker/blob/master/src/dotaconstants_add.json#L102-L226)
|
|
45
|
+
补充或纠错请提issue
|
|
38
46
|
|
|
39
47
|
### 图片模板列表
|
|
40
|
-
展示见[wiki](
|
|
48
|
+
展示见[wiki](https://github.com/sjtdev/koishi-plugin-dota2tracker/wiki)
|
|
41
49
|
生成图片已使用ejs模板实现,所有模板都在[template]文件夹下,若是有大佬想自己设计模板欢迎联系我完善数据接口。(当前有很多在模板中后处理的数据,不是很友好)
|
|
42
50
|
|
|
43
51
|
### 其他问题
|
|
@@ -718,7 +718,7 @@
|
|
|
718
718
|
<img alt="" src="${utils.getImageUrl(player.hero.shortName, ImageType.Heroes)}" />
|
|
719
719
|
<p class="party_line${player.partyId != null ? " party_" + match.party[player.partyId] : ""}"></p>
|
|
720
720
|
<p class="party_mark${player.partyId != null ? " party_" + match.party[player.partyId] : ""}"></p>
|
|
721
|
-
<p class="position p${Math.floor(player.order / 4) + 1}">${player.isRandom ? "随机" : `第<span>${player.order == null ? "-" : player.order + 1}</span>手`}<br/>${d2a.position[player.position?.slice(-1)]}</p>
|
|
721
|
+
<p class="position p${Math.floor(player.order / 4) + 1}">${player.isRandom ? "随机" : `第<span>${player.order == null ? "-" : player.order + 1}</span>手`}<br/>${d2a.position[player.position?.slice(-1)]??""}</p>
|
|
722
722
|
<p class="level">${player.level}</p>
|
|
723
723
|
</div>
|
|
724
724
|
<div class="player_info">
|
|
@@ -804,7 +804,7 @@
|
|
|
804
804
|
<p>${buff.stackCount ?? ""}</p>
|
|
805
805
|
</div>`
|
|
806
806
|
)
|
|
807
|
-
.join("")}
|
|
807
|
+
.join("")??""}
|
|
808
808
|
</section>
|
|
809
809
|
<section>
|
|
810
810
|
<div class="support_item"${player.supportItemsCount[30] > 0 ? "" : ' style="display:none"'}>
|
|
@@ -946,19 +946,19 @@
|
|
|
946
946
|
<section>英雄伤害:<span class="hero_damage">${player.heroDamage}</span></section>
|
|
947
947
|
<section>建筑伤害:<span class="building_damage">${player.towerDamage}</span></section>
|
|
948
948
|
<section>受到伤害(减免后):<span class="tak">${
|
|
949
|
-
player.stats?.heroDamageReport?.receivedTotal.physicalDamage + player.stats?.heroDamageReport?.receivedTotal.magicalDamage + player.stats?.heroDamageReport?.receivedTotal.pureDamage
|
|
949
|
+
(player.stats?.heroDamageReport?.receivedTotal.physicalDamage??0) + (player.stats?.heroDamageReport?.receivedTotal.magicalDamage??0) + (player.stats?.heroDamageReport?.receivedTotal.pureDamage??0)
|
|
950
950
|
}</span></section>
|
|
951
951
|
<section>补刀:<span class="lh">${player.numLastHits}</span>/<span class="dn">${player.numDenies}</span></section>
|
|
952
952
|
<section>GPM/XPM:<span class="gpm">${player.goldPerMinute}</span>/<span class="xpm">${player.experiencePerMinute}</span></section>
|
|
953
953
|
<section>治疗量:<span class="heal">${player.heroHealing}</span></section>
|
|
954
|
-
<section>控制时间:<span class="building_damage">${(player.stats?.heroDamageReport?.dealtTotal.stunDuration / 100).toFixed(2)}/${(player.stats?.heroDamageReport?.dealtTotal.slowDuration / 100).toFixed(2)}/${(
|
|
955
|
-
player.stats?.heroDamageReport?.dealtTotal.disableDuration / 100
|
|
954
|
+
<section>控制时间:<span class="building_damage">${((player.stats?.heroDamageReport?.dealtTotal.stunDuration ?? 0) / 100).toFixed(2)}/${((player.stats?.heroDamageReport?.dealtTotal.slowDuration ?? 0) / 100).toFixed(2)}/${(
|
|
955
|
+
(player.stats?.heroDamageReport?.dealtTotal.disableDuration ?? 0) / 100
|
|
956
956
|
).toFixed(2)}</span>s</section>
|
|
957
957
|
</div>
|
|
958
958
|
</div>`).join("") %>
|
|
959
959
|
</div>
|
|
960
960
|
<div class="ban_list">
|
|
961
|
-
<%- match.pickBans
|
|
961
|
+
<%- (match.pickBans??[])
|
|
962
962
|
.filter((hero) => !hero.isPick)
|
|
963
963
|
.map((hero) => `<div class="ban_hero"><img src="${utils.getImageUrl(/^npc_dota_hero_(?<name>.+)$/.exec(dotaconstants.heroes[hero.bannedHeroId].name)[1], ImageType.Heroes)}" alt="" /></div>`)
|
|
964
964
|
.join("") %>
|
|
@@ -396,11 +396,11 @@
|
|
|
396
396
|
(${(player.heroDamage / player.networth)?.toFixed(2)})
|
|
397
397
|
</p>
|
|
398
398
|
<p class="hero_damage">造成伤害:${player.heroDamage} (${(player.heroDamage/match[player.team].heroDamage*100).toFixed(2)}%)</p>
|
|
399
|
-
<p class="damage_received">承受伤害:${player.damageReceived} (${(player.damageReceived/match[player.team].damageReceived*100).toFixed(2)}%)</p>
|
|
399
|
+
<p class="damage_received">承受伤害:${player.damageReceived} (${match[player.team].damageReceived>0?((player.damageReceived/match[player.team].damageReceived*100).toFixed(2)):"0.00"}%)</p>
|
|
400
400
|
<p class="tower_damage">建筑伤害:${player.towerDamage}</p>
|
|
401
401
|
<p class="kda row-1">${player.kills}/${player.deaths}/${player.assists} (${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)})</p>
|
|
402
402
|
<p class="kill_contribution">参战率:${(player.killContribution * 100).toFixed(2)}%</p>
|
|
403
|
-
<p class="stun_duration">控制时间:${(player.stats.heroDamageReport
|
|
403
|
+
<p class="stun_duration">控制时间:${((player.stats.heroDamageReport?.dealtTotal.stunDuration ?? 0)/ 100).toFixed(2)}s</p>
|
|
404
404
|
<p class="heal">治疗量:${player.heroHealing}</p>
|
|
405
405
|
<div class="items row-1">
|
|
406
406
|
<div class="normal">
|
|
@@ -430,8 +430,8 @@
|
|
|
430
430
|
</div>
|
|
431
431
|
<div class="neutral_item row-1" style="background-image: url(${utils.getImageUrl(dotaconstants.item_ids[player.neutral0Id], ImageType.Items)})"></div>
|
|
432
432
|
<div class="ahgs row-1">
|
|
433
|
-
<img src="${utils.getImageUrl("scepter_"+((player.items.concat(player.backpacks).find(item=>item?.id==108)||player.stats
|
|
434
|
-
<img src="${utils.getImageUrl("shard_"+(player.stats
|
|
433
|
+
<img src="${utils.getImageUrl("scepter_"+((player.items.concat(player.backpacks).find(item=>item?.id==108)||(player.stats?.matchPlayerBuffEvent||[]).find(buff=>buff.itemId==108))?1:0))}" alt="" />
|
|
434
|
+
<img src="${utils.getImageUrl("shard_"+((player.stats?.matchPlayerBuffEvent||[]).find(buff=>buff.itemId==609)?1:0))}" alt="" />
|
|
435
435
|
</div>
|
|
436
436
|
</div>
|
|
437
437
|
`).join("") %>
|