diff --git a/package-lock.json b/package-lock.json index 121827e..74b0ebf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "azerothcore-armory", - "version": "0.9.1", + "version": "0.10.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "azerothcore-armory", - "version": "0.9.1", + "version": "0.10.0", "license": "MIT", "dependencies": { "@supercharge/promise-pool": "^2.1.0", diff --git a/package.json b/package.json index cf8630a..0552307 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "azerothcore-armory", - "version": "0.9.1", + "version": "0.10.0", "description": "", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/src/armory/Armory.ts b/src/armory/Armory.ts index eaa25e9..bc90a54 100644 --- a/src/armory/Armory.ts +++ b/src/armory/Armory.ts @@ -138,6 +138,7 @@ export class Armory { app.get("/character/:realm/:name/talents", this.wrapRoute(charsController.talents.bind(charsController))); app.get("/character/:realm/:name/achievements", this.wrapRoute(charsController.achievements.bind(charsController))); app.get("/character/:realm/:character/achievements/data", this.wrapRoute(charsController.achievementsData.bind(charsController))); + app.get("/character/:realm/:name/pvp", this.wrapRoute(charsController.pvp.bind(charsController))); const guildsController = new GuildController(this); app.get("/guild/:realm/:name", this.wrapRoute(guildsController.guild.bind(guildsController))); diff --git a/src/armory/Utils.ts b/src/armory/Utils.ts index 3c1f654..7f0c427 100644 --- a/src/armory/Utils.ts +++ b/src/armory/Utils.ts @@ -3,6 +3,14 @@ export enum EFaction { Alliance = 1, } +export interface IEmblem { + icon: string; + iconColor: string; + border: string; + borderColor: string; + background: string; +} + export class Utils { public static raceNames = { 1: "human", @@ -32,4 +40,15 @@ export class Utils { public static getFactionFromRaceId(race: number): EFaction { return [1, 3, 4, 7, 11].includes(race) ? EFaction.Alliance : EFaction.Horde; } + + public static makeEmblemObject(obj: any, padWithZeroes: boolean = true): IEmblem { + const padLength = padWithZeroes ? 2 : 0; + return { + icon: obj.emblemStyle.toString().padStart(padLength, "0"), + iconColor: obj.emblemColor.toString().padStart(padLength, "0"), + border: obj.borderStyle.toString().padStart(padLength, "0"), + borderColor: obj.borderColor.toString().padStart(padLength, "0"), + background: obj.background.toString().padStart(padLength, "0"), + }; + } } diff --git a/src/armory/controllers/CharacterController.ts b/src/armory/controllers/CharacterController.ts index 66d363b..bc56c90 100644 --- a/src/armory/controllers/CharacterController.ts +++ b/src/armory/controllers/CharacterController.ts @@ -178,9 +178,9 @@ export class CharacterController { const mounts = await this.getMounts(realmName, charData.guid); res.render("character.hbs", { - title: `Armory - ${charName}`, + title: `Armory - ${charData.name}`, ...this.makeSharedDataObject(realm, charData), - data: JSON.stringify({ + data: { race: charData.race, gender: charData.gender, class: charData.class, @@ -189,7 +189,7 @@ export class CharacterController { customizationOptions: customization, equipment, mounts, - }), + }, }); this.armory.gc(); @@ -212,13 +212,13 @@ export class CharacterController { } res.render("character-talents.hbs", { - title: `Armory - ${charName} - Talents`, + title: `Armory - ${charData.name} - Talents`, ...this.makeSharedDataObject(realm, charData), - data: JSON.stringify({ + data: { talents: await this.getTalents(realm.name, charData.guid), trees: await this.getTalentTrees(charData.class), glyphs: await this.getGlyphs(realm.name, charData.guid), - }), + }, }); } @@ -239,7 +239,7 @@ export class CharacterController { } res.render("character-achievements.hbs", { - title: `Armory - ${charName} - Achievements`, + title: `Armory - ${charData.name} - Achievements`, ...this.makeSharedDataObject(realm, charData), }); } @@ -266,6 +266,31 @@ export class CharacterController { }); } + public async pvp(req: express.Request, res: express.Response, next: express.NextFunction): Promise { + const realmName = req.params.realm; + const charName = req.params.name; + + const realm = this.armory.getRealm(realmName); + if (realm === undefined) { + // Could not find realm + return next(404); + } + + const charData = await this.getCharacterData(realm, charName); + if (charData === null) { + // Could not find character + return next(404); + } + + res.render("character-pvp.hbs", { + title: `Armory - ${charData.name} - PvP`, + ...this.makeSharedDataObject(realm, charData), + faction: Utils.getFactionFromRaceId(charData.race), + kills: await this.getPvpKills(realm.name, charData.guid), + arenaTeams: await this.getArenaTeams(realm.name, charData.guid), + }); + } + private makeSharedDataObject(realm: IRealmConfig, charData: ICharacterData) { return { realm: realm.name, @@ -323,7 +348,7 @@ export class CharacterController { FROM character_spell WHERE guid = ? AND spell IN (?) `, - values:[charGuid, this.mountSpells], + values: [charGuid, this.mountSpells], timeout: this.armory.config.dbQueryTimeout, }); @@ -770,4 +795,44 @@ export class CharacterController { earned, }; } + + private async getPvpKills(realm: string, charGuid: number): Promise<{ total: number, today: number, yesterday: number }> { + const [rows, fields] = await this.armory.getCharactersDb(realm).query({ + sql: ` + SELECT totalKills, todayKills, yesterdayKills + FROM characters + WHERE guid = ? + `, + values: [charGuid], + timeout: this.armory.config.dbQueryTimeout, + }); + const row = rows[0]; + + return { + total: row.totalKills, + today: row.todayKills, + yesterday: row.yesterdayKills, + }; + } + + private async getArenaTeams(realm: string, charGuid: number): Promise { + const [rows, fields] = await this.armory.getCharactersDb(realm).query({ + sql: ` + SELECT + arena_team.arenaTeamId AS id, arena_team.name, arena_team.type, arena_team.rating, arena_team.seasonWins, arena_team.seasonGames, + arena_team.backgroundColor AS background, arena_team.emblemStyle, arena_team.emblemColor, arena_team.borderStyle, arena_team.borderColor + FROM arena_team_member + LEFT JOIN arena_team ON arena_team_member.arenaTeamId = arena_team.arenaTeamId + WHERE guid = ? + ORDER BY arena_team.type ASC + `, + values: [charGuid], + timeout: this.armory.config.dbQueryTimeout, + }); + + return (rows as RowDataPacket[]).map(row => { + row.emblem = Utils.makeEmblemObject(row, false); + return row; + }); + } } diff --git a/src/armory/controllers/GuildController.ts b/src/armory/controllers/GuildController.ts index f5a3876..8eb22d2 100644 --- a/src/armory/controllers/GuildController.ts +++ b/src/armory/controllers/GuildController.ts @@ -133,13 +133,7 @@ export class GuildController { name: guild.name, leader: leader.name, faction: Utils.getFactionFromRaceId(leader.race), - emblem: { - icon: guild.emblemStyle.toString().padStart(2, "0"), - iconColor: guild.emblemColor.toString().padStart(2, "0"), - border: guild.borderStyle.toString().padStart(2, "0"), - borderColor: guild.borderColor.toString().padStart(2, "0"), - background: guild.background.toString().padStart(2, "0"), - }, + emblem: Utils.makeEmblemObject(guild), membersCount, }; } diff --git a/src/tools/fetchdata.ts b/src/tools/fetchdata.ts index 5556e53..9e6b412 100644 --- a/src/tools/fetchdata.ts +++ b/src/tools/fetchdata.ts @@ -18,18 +18,18 @@ require("source-map-support").install(); const baseUrl = "https://wow.zamimg.com/modelviewer/live"; class Stopwatch { - private startTime: Date; + private startTime: number; public constructor() { this.start(); } public start(): void { - this.startTime = new Date(); + this.startTime = Date.now(); } public stop(text?: string): void { - const dt = Date.now() - this.startTime.getTime(); + const dt = Date.now() - this.startTime; const txt = text ?? "Done in {time}"; console.log(txt.replace("{time}", prettyMs(dt))); } diff --git a/static/character-pvp.hbs b/static/character-pvp.hbs new file mode 100644 index 0000000..6a62632 --- /dev/null +++ b/static/character-pvp.hbs @@ -0,0 +1,42 @@ + +{{> emblems}} + +{{> character-header }} + +
+
+ {{#eq faction 1}} + + {{else}} + + {{/eq}} + +
Total Kills: {{kills.total}}
+
Kills Today: {{kills.today}}
+
Kills Yesterday: {{kills.yesterday}}
+
+ + {{#each arenaTeams}} +
+
+
+
{{this.name}}
+
{{this.type}}v{{this.type}} Team
+
Rating: {{this.rating}}
+
{{this.seasonWins}} W / {{subtract this.seasonGames this.seasonWins}} L
+
+
+
+ +
+
+
+
+ {{/each}} +
+ + diff --git a/static/character-talents.hbs b/static/character-talents.hbs index 9d79bb6..d2ee79f 100644 --- a/static/character-talents.hbs +++ b/static/character-talents.hbs @@ -53,7 +53,7 @@