Skip to content

Commit

Permalink
feature(TTW-7104): Individual character Log Header (WoWAnalyzer#7105)
Browse files Browse the repository at this point in the history
* feature(TTW-7104): Individual character Log Header

* handle hidden response type in wcl parses

---------

Co-authored-by: emallson <[email protected]>
  • Loading branch information
danny-janse and emallson authored Oct 3, 2024
1 parent 04295a6 commit 9992951
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 25 deletions.
1 change: 1 addition & 0 deletions src/CHANGELOG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import SpellLink from 'interface/SpellLink';

// prettier-ignore
export default [
change(date(2024, 10, 3), 'Fixed rendering of the Header on the character log browser.', Vetyst),
change(date(2024, 9, 30), 'Add Classic Cata Firelands raid zone, headshots, and placeholder image', jazminite),
change(date(2024, 9, 30), 'Enchant checker now detects Spellthreads', Sref),
change(date(2024, 9, 26), "Add support for Warlock Hero Talents", Gazh),
Expand Down
6 changes: 5 additions & 1 deletion src/common/WCL_TYPES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ export interface WCLParse {
estimated: boolean;
}

export type WCLParsesResponse = WCLParse[];
export type WCLParsesResponse = WCLParse[] | { hidden: true };

export function isHiddenParsesResponse(data: WCLParsesResponse): data is { hidden: true } {
return !Array.isArray(data);
}

export type WCLResponseJSON =
| WCLGuildReportsResponse
Expand Down
16 changes: 16 additions & 0 deletions src/game/CLASSES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ export enum CLASSES {
WARRIOR,
}

export const CLASS_NAMES: { [classId: number]: { name: string } } = {
1: { name: 'Warrior' },
2: { name: 'Paladin' },
3: { name: 'Hunter' },
4: { name: 'Rogue' },
5: { name: 'Priest' },
6: { name: 'Death Knight' },
7: { name: 'Shaman' },
8: { name: 'Mage' },
9: { name: 'Warlock' },
10: { name: 'Monk' },
11: { name: 'Druid' },
12: { name: 'Demon Hunter' },
13: { name: 'Evoker' },
};

export function getClassBySpecId(specId: number) {
if (DEATH_KNIGHT_SPECS.find((spec) => spec.id === specId)) {
return CLASSES.DEATH_KNIGHT;
Expand Down
44 changes: 33 additions & 11 deletions src/interface/CharacterParses.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,18 @@ import REPORT_HISTORY_TYPES from 'interface/REPORT_HISTORY_TYPES';
import { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { WCLParse, WCLParsesResponse } from 'common/WCL_TYPES';
import { isHiddenParsesResponse, WCLParse, WCLParsesResponse } from 'common/WCL_TYPES';
import { isSupportedRegion } from 'common/regions';

import './report/Results/Header.scss';
import './CharacterParses.scss';
import ParsesList, { Parse } from './CharacterParsesList';
import { appendReportHistory } from './reducers/reportHistory';
import { CLASS_NAMES } from 'game/CLASSES';
import {
classBackgroundImage,
characterBackgroundImage,
} from 'interface/report/Results/PlayerInfo';

const loadRealms = (classic: boolean) =>
retryingPromise(() =>
Expand Down Expand Up @@ -100,7 +106,8 @@ interface CharacterParsesState {
activeEncounter: number;
sortBy: number;
metric: string;
image: string | null;
characterImage: string | null;
classImage: string | null;
avatarImage: string | null;
parses: Parse[];
isLoading: boolean;
Expand All @@ -123,7 +130,8 @@ class CharacterParses extends Component<CharacterParsesProps, CharacterParsesSta
activeEncounter: BOSS_DEFAULT_ALL_BOSSES,
sortBy: ORDER_BY.DATE,
metric: 'dps',
image: null,
characterImage: null,
classImage: null,
avatarImage: null,
parses: [],
isLoading: true,
Expand Down Expand Up @@ -266,7 +274,7 @@ class CharacterParses extends Component<CharacterParsesProps, CharacterParsesSta
// Skip Blizzard API - Classic is not supported
this.setState(
{
image: FALLBACK_PICTURE,
characterImage: FALLBACK_PICTURE,
},
() => {
this.load();
Expand All @@ -281,7 +289,7 @@ class CharacterParses extends Component<CharacterParsesProps, CharacterParsesSta
if (region === 'CN') {
this.setState(
{
image: FALLBACK_PICTURE,
characterImage: FALLBACK_PICTURE,
},
() => {
this.load();
Expand Down Expand Up @@ -312,18 +320,19 @@ class CharacterParses extends Component<CharacterParsesProps, CharacterParsesSta
}

const data = await response.json();

const classImageUrl = classBackgroundImage(CLASS_NAMES[data.class].name, data.region);
const avatarUrl = data.thumbnail
? data.thumbnail.startsWith('https')
? data.thumbnail
: `https://render-${this.props.region}.worldofwarcraft.com/character/${data.thumbnail}`
: undefined;
const imageUrl = avatarUrl?.replace('avatar.jpg', 'main.jpg');
const characterImageUrl = characterBackgroundImage(avatarUrl, data.region);
const role = data.role;
const metric = role === 'HEALING' ? 'hps' : 'dps';
this.setState(
{
image: imageUrl,
characterImage: characterImageUrl,
classImage: classImageUrl,
avatarImage: avatarUrl,
metric: metric,
},
Expand Down Expand Up @@ -389,6 +398,15 @@ class CharacterParses extends Component<CharacterParsesProps, CharacterParsesSta
refresh,
)
.then((rawParses) => {
if (isHiddenParsesResponse(rawParses)) {
// WCL responds with {hidden:true} when the logs are hidden.
this.setState({
parses: [],
isLoading: false,
error: ERRORS.CHARACTER_HIDDEN,
});
return;
}
if (rawParses.length === 0) {
this.setState({
parses: [],
Expand All @@ -397,7 +415,6 @@ class CharacterParses extends Component<CharacterParsesProps, CharacterParsesSta
});
return;
}
// hidden isn't a value on the parse response

if (this.state.class !== '') {
//only update parses when class was already parsed (since its only a metric/raid change)
Expand Down Expand Up @@ -593,11 +610,16 @@ class CharacterParses extends Component<CharacterParsesProps, CharacterParsesSta
return (
<div className="results">
<header>
<div className="background">
<div
className="background"
style={{
backgroundImage: `url(${this.state.classImage})`,
}}
>
<div
className="img"
style={{
backgroundImage: `url(${this.state.image})`,
backgroundImage: `url(${this.state.characterImage})`,
backgroundPosition: 'center center',
}}
/>
Expand Down
11 changes: 7 additions & 4 deletions src/interface/GuildReports.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Component } from 'react';
import { Link } from 'react-router-dom';
import { isSupportedRegion } from 'common/regions';

import './report/Results/Header.scss';
import './GuildReports.scss';
import ReportsList from './GuildReportsList';
import ALLIANCE_PICTURE from './images/ally_guild_banner_bwl.jpg';
Expand Down Expand Up @@ -431,10 +432,12 @@ class GuildReports extends Component<Props, State> {
)}
</div>
<div className="player">
<h2>
{this.props.region} - {this.props.realm}
</h2>
<h1>{this.props.name}</h1>
<div className="details">
<h2>
{this.props.region} - {this.props.realm}
</h2>
<h1>{this.props.name}</h1>
</div>
</div>
</div>
<nav>
Expand Down
2 changes: 2 additions & 0 deletions src/interface/report/Results/Header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
padding-top: 85px;

.background {
background-position: center 62.5%;
background-size: cover;
position: absolute;
top: 0;
left: 50%;
Expand Down
4 changes: 3 additions & 1 deletion src/interface/report/Results/PlayerInfo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
text-decoration: none;
}

.player-background {
.class-background {
background-position: center;
background-size: cover;
}

.player-gear {
background-size: contain;
background-position: center 62.5%;
display: grid;
grid-template-columns: 45px 15px auto 30px 15px 45px 45px 15px 30px auto 15px 45px;
grid-template-rows: 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px;
Expand Down
30 changes: 22 additions & 8 deletions src/interface/report/Results/PlayerInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import PlayerInfoGear from './PlayerInfoGear';
import PlayerInfoGems from './PlayerInfoGems';
import PlayerInfoTalents from './PlayerInfoTalents';
import GameBranch from 'game/GameBranch';
import { CLASS_NAMES } from 'game/CLASSES';

function _parseGear(gear: Item[]) {
return gear.reduce((gearItemsBySlotId: Item[], item: Item) => gearItemsBySlotId.concat(item), []);
Expand All @@ -18,33 +19,46 @@ interface Props {
combatant: Combatant;
}

const backgroundImage = (thumbnail?: string, region?: string): string => {
export const characterBackgroundImage = (thumbnail?: string, region?: string): string => {
if (thumbnail?.startsWith('https')) {
return thumbnail.replace('avatar.jpg', 'main.jpg');
return thumbnail.replace('avatar.jpg', 'main-raw.png');
} else if (thumbnail && region) {
return `https://render-${region}.worldofwarcraft.com/character/${thumbnail.replace(
'avatar',
'main',
'avatar.jpg',
'main-raw.png',
)}`;
} else {
return '/img/fallback-character.jpg';
}
};
export const classBackgroundImage = (className?: string, region?: string): string | null => {
if (className && region) {
return `https://render.worldofwarcraft.com/${region}/profile-backgrounds/v2/armory_bg_class_${className.toLowerCase().replaceAll(' ', '_')}.jpg`;
}

return null;
};

const PlayerInfo = ({ combatant }: Props) => {
const isRetail = combatant.owner.config.branch === GameBranch.Retail;
const gear: Item[] = _parseGear(combatant._combatantInfo.gear);
const talents = combatant._combatantInfo.talentTree;
const averageIlvl = getAverageItemLevel(gear);
const background = backgroundImage(
const classBackground = classBackgroundImage(
CLASS_NAMES[combatant.characterProfile.class].name,
combatant.characterProfile?.region,
);
const characterBackground = characterBackgroundImage(
combatant.characterProfile?.thumbnail,
combatant.characterProfile?.region,
);

return (
<div className="player-info">
<div className="player-background" style={{ backgroundImage: `url(${background})` }}>
<div className="player-gear">
<div className="class-background" style={{ backgroundImage: `url(${classBackground})` }}>
<div
className="player-gear player-background"
style={{ backgroundImage: `url(${characterBackground})` }}
>
<PlayerGearHeader player={combatant} averageIlvl={averageIlvl} />
<PlayerInfoGear gear={gear} />
<PlayerInfoGems gear={gear} />
Expand Down

0 comments on commit 9992951

Please sign in to comment.