Skip to content

Commit

Permalink
fix(amaroquest): parse directly from lodestone
Browse files Browse the repository at this point in the history
  • Loading branch information
tyrone-sudeium committed Jan 5, 2024
1 parent 48492ed commit 8539937
Show file tree
Hide file tree
Showing 9 changed files with 2,235 additions and 44 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@napi-rs/canvas": "^0.1",
"@types/ws": "^7.2.1",
"@tyrone-sudeium/napi-gif-encoder": "^0.0.1",
"@xivapi/nodestone": "^0.2.6",
"anchorme": "^1.1.2",
"array-flatten": "^3.0.0",
"chrono-node": "^2.3.1",
Expand Down
45 changes: 16 additions & 29 deletions src/features/amaroquest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
*/

import * as Discord from "discord.js"
import { getJSON } from "../util/http"
import { log } from "../log"
import { XIVCharacter, getCharacterExpData } from "../util/lodestone/parser"
import { GlobalFeature, MessageContext } from "./feature"

const EXP_CURVE = [
Expand Down Expand Up @@ -143,19 +143,6 @@ const TOTAL_EXP = Object.entries(ADVENTURER_CLASSES)

const NUMBER_FORMATTER = new Intl.NumberFormat("en-US")

interface XIVAPICharacter {
Character: {
Avatar: string
ID: number
Name: string
ClassJobs: {
ClassID: number
Level: number
ExpLevel: number
}[]
}
}

const ORDINALS = ["First", "Second", "Third", "Fourth", "Fifth"]
const COLORS = ["#FFD700", "#C0C0C0", "#804000", "#0000A0", "#0000A0"] as Discord.HexColorString[]

Expand All @@ -172,24 +159,24 @@ interface History {
[charId: string]: number
}

function totalExpForToon(toon: XIVAPICharacter): number {
function totalExpForToon(toon: XIVCharacter): number {
let exp = 0
const classesCounted: Set<number> = new Set()
for (const job of toon.Character.ClassJobs) {
for (const job of toon.character.classJobs) {
// Dumb Arcanist workaround
if (classesCounted.has(job.ClassID)) {
if (classesCounted.has(job.classId)) {
continue
}
const cls = ADVENTURER_CLASSES[job.ClassID]
const cls = ADVENTURER_CLASSES[job.classId]
if (!cls) {
continue
}
if (job.Level === 0) {
if (job.level === 0) {
continue
}
const earned = expEarned(job.Level, cls.startsAt)
exp = exp + earned + job.ExpLevel
classesCounted.add(job.ClassID)
const earned = expEarned(job.level, cls.startsAt)
exp = exp + earned + job.expLevel
classesCounted.add(job.classId)
}
return exp
}
Expand Down Expand Up @@ -290,17 +277,17 @@ export class AmaroQuestFeature extends GlobalFeature {
return
}
let leaderboard: LeaderboardData[] = []
const dataPromises: Promise<XIVAPICharacter>[] = amaroQuesters
.map(id => getJSON(`https://xivapi.com/character/${id}`))
const dataPromises: Promise<XIVCharacter>[] = amaroQuesters
.map(id => getCharacterExpData(id))
try {
const data = await Promise.all(dataPromises)
for (const charData of data) {
const name = charData.Character.Name
const name = charData.character.name
const cumulativeExp = totalExpForToon(charData)
const url = `https://na.finalfantasyxiv.com/lodestone/character/${charData.Character.ID}/`
const avatarURL = charData.Character.Avatar
const prevExp = history[charData.Character.ID] ?? null
history[charData.Character.ID] = cumulativeExp
const url = `https://na.finalfantasyxiv.com/lodestone/character/${charData.character.id}/`
const avatarURL = charData.character.avatar
const prevExp = history[charData.character.id] ?? null
history[charData.character.id] = cumulativeExp
leaderboard.push({name, cumulativeExp, url, avatarURL, position: "", prevExp})
}
} catch (error) {
Expand Down
62 changes: 62 additions & 0 deletions src/util/lodestone/attributes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"STRENGTH": {
"selector": "table.character__param__list:nth-child(2) tr:nth-child(1) > td:nth-child(2)"
},
"DEXTERITY": {
"selector": "table.character__param__list:nth-child(2) tr:nth-child(2) > td:nth-child(2)"
},
"VITALITY": {
"selector": "table.character__param__list:nth-child(2) tr:nth-child(3) > td:nth-child(2)"
},
"INTELLIGENCE": {
"selector": "table.character__param__list:nth-child(2) tr:nth-child(4) > td:nth-child(2)"
},
"MIND": {
"selector": "table.character__param__list:nth-child(2) tr:nth-child(5) > td:nth-child(2)"
},
"CRITICAL_HIT_RATE": {
"selector": "table.character__param__list:nth-child(4) tr:nth-child(1) > td:nth-child(2)"
},
"DETERMINATION": {
"selector": "table.character__param__list:nth-child(4) tr:nth-child(2) > td:nth-child(2)"
},
"DIRECT_HIT_RATE": {
"selector": "table.character__param__list:nth-child(4) tr:nth-child(3) > td:nth-child(2)"
},
"DEFENSE": {
"selector": "table.character__param__list:nth-child(6) tr:nth-child(1) > td:nth-child(2)"
},
"MAGIC_DEFENSE": {
"selector": "table.character__param__list:nth-child(6) tr:nth-child(2) > td:nth-child(2)"
},
"ATTACK_POWER": {
"selector": "table.character__param__list:nth-child(8) tr:nth-child(1) > td:nth-child(2)"
},
"SKILL_SPEED": {
"selector": "table.character__param__list:nth-child(8) tr:nth-child(2) > td:nth-child(2)"
},
"ATTACK_MAGIC_POTENCY": {
"selector": "table.character__param__list:nth-child(10) tr:nth-child(1) > td:nth-child(2)"
},
"HEALING_MAGIC_POTENCY": {
"selector": "table.character__param__list:nth-child(10) tr:nth-child(2) > td:nth-child(2)"
},
"SPELL_SPEED": {
"selector": "table.character__param__list:nth-child(10) tr:nth-child(3) > td:nth-child(2)"
},
"TENACITY": {
"selector": "table.character__param__list:nth-child(12) tr:nth-child(1) > td:nth-child(2)"
},
"PIETY": {
"selector": "table.character__param__list:nth-child(12) tr:nth-child(2) > td:nth-child(2)"
},
"HP": {
"selector": ".character__param > ul:nth-child(1) > li:nth-child(1) > div:nth-child(1) > span:nth-child(2)"
},
"MP_GP_CP": {
"selector": ".character__param > ul:nth-child(1) > li:nth-child(2) > div:nth-child(1) > span:nth-child(2)"
},
"MP_GP_CP_PARAMETER_NAME": {
"selector": ".character__param > ul > li:nth-child(2) .character__param__text"
}
}
115 changes: 115 additions & 0 deletions src/util/lodestone/character.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
{
"ACTIVE_CLASSJOB": {
"selector": ".character__class_icon > img:nth-child(1)",
"attribute": "src"
},
"ACTIVE_CLASSJOB_LEVEL": {
"selector": ".character__class__data > p:nth-child(1)",
"regex": "LEVEL (?P<Level>\\d*)"
},
"AVATAR": {
"selector": ".frame__chara__face > img:nth-child(1)",
"attribute": "src"
},
"BIO": {
"selector": ".character__selfintroduction"
},
"CLASSJOB_ICONS": {
"ROOT": {
"selector": "li",
"multiple": true
},
"ICON": {
"selector": ".js__tooltip",
"attribute": "src"
}
},
"FREE_COMPANY": {
"ID": {
"selector": ".character__freecompany__name > h4:nth-child(2) > a:nth-child(1)",
"attribute": "href",
"regex": "/lodestone/freecompany/(?P<ID>.+)/"
},
"NAME": {
"selector": ".character__freecompany__name > h4:nth-child(2) > a:nth-child(1)"
},
"ICON_LAYERS": {
"BOTTOM": {
"selector": "div.character__freecompany__crest > div > img:nth-child(1)",
"attribute": "src"
},
"MIDDLE": {
"selector": "div.character__freecompany__crest > div > img:nth-child(2)",
"attribute": "src"
},
"TOP": {
"selector": "div.character__freecompany__crest > div > img:nth-child(3)",
"attribute": "src"
}
}
},
"GRAND_COMPANY": {
"selector": "div.character-block:nth-child(4) > div:nth-child(2) > p:nth-child(2)",
"regex": "(?P<Name>\\S*) \/ (?P<Rank>.*)"
},
"GUARDIAN_DEITY": {
"NAME": {
"selector": "p.character-block__name:nth-child(4)"
},
"ICON": {
"selector": "#character > div.character__content.selected > div.character__profile.clearfix > div.character__profile__data > div:nth-child(1) > div > div:nth-child(2) > img",
"attribute": "src"
}
},
"NAME": {
"selector": "div.frame__chara__box:nth-child(2) > .frame__chara__name"
},
"NAMEDAY": {
"selector": ".character-block__birth"
},
"PORTRAIT": {
"selector": ".js__image_popup > img:nth-child(1)",
"attribute": "src"
},
"PVP_TEAM": {
"NAME": {
"selector": ".character__pvpteam__name > h4:nth-child(2) > a:nth-child(1)",
"attribute": "href",
"regex": "/lodestone/pvpteam/(?P<ID>.+)/"
},
"ICON_LAYERS": {
"BOTTOM": {
"selector": ".character__pvpteam__crest__image img:nth-child(1)",
"attribute": "src"
},
"MIDDLE": {
"selector": ".character__pvpteam__crest__image img:nth-child(2)",
"attribute": "src"
},
"TOP": {
"selector": ".character__pvpteam__crest__image img:nth-child(3)",
"attribute": "src"
}
}
},
"RACE_CLAN_GENDER": {
"selector": "div.character-block:nth-child(1) > div:nth-child(2) > p:nth-child(2)",
"regex": "(?P<Race>.*)<br\\/?>(?P<Tribe>.*) \\/ (?P<Gender>.)"
},
"SERVER": {
"selector": "p.frame__chara__world",
"regex": "(?P<World>\\w*)\\s+\\[(?P<DC>\\w*)\\]"
},
"TITLE": {
"selector": ".frame__chara__title"
},
"TOWN": {
"NAME": {
"selector": "div.character-block:nth-child(3) > div:nth-child(2) > p:nth-child(2)"
},
"ICON": {
"selector": "#character > div.character__content.selected > div.character__profile.clearfix > div.character__profile__data > div:nth-child(1) > div > div:nth-child(3) > img",
"attribute": "src"
}
}
}
Loading

0 comments on commit 8539937

Please sign in to comment.