| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- import { allItems, _Tiers, Tiers } from "../../Types/Items";
- import { Inject, Injectable } from "../../Injector/ServiceDecorator";
- import { ItemManagerFeatureIfc, ItemManagerIfc } from "./RPCInterface";
- import { FrontworkComponent } from "../../Types/FrontworkComponent";
- import { TableDefinitionExporter } from "../../Types/Interfaces";
- import { TableDefiniton, Item, User, Character, SRToken, SRPriority, Spec, Signup, Raid, Stats } from "../../Types/Types";
- import { IAdmin } from "../../Admin/Interface";
- import { IItemManager } from "./Interface";
- import { IUserManager } from "../User/Interface";
- import { ICharacterManager } from "../Character/Interface";
- import { IPubSub } from "../PubSub/Interface";
- import { IRaidManager } from "../Raid/Interface";
- import { getLogger } from "frontblock-generic/Types";
-
- const fetch = require('node-fetch')
- const xml2js = require('xml2js');
- const parser = new xml2js.Parser(/* options */);
-
- @Injectable(IItemManager)
- export class ItemManager
- implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefinitionExporter, IItemManager {
- name = "ItemManager" as "ItemManager";
-
- @Inject(IAdmin)
- private admin: IAdmin
-
- @Inject(IUserManager)
- private userManager: IUserManager
-
- @Inject(ICharacterManager)
- private character: ICharacterManager
-
- @Inject(IPubSub)
- private pubsub: IPubSub<any>
-
- @Inject(IRaidManager)
- private raidManager: IRaidManager
-
- exportRPCs = () => [
- this.getItems,
- this.getItem,
- this.buyToken,
- this.calculatePriorities,
- this.getToken,
- this.getTokens,
- this.getAllPriorities
- ]
-
- exportRPCFeatures = () => [{
- name: 'managePriorities' as 'managePriorities',
- exportRPCs: () => [
- this.setPriority,
- this.deletePriority
- ],
- }, {
- name: 'reset' as 'reset',
- exportRPCs: () => [
- this.wipeCurrencyAndItems
- ]
- }]
-
- notifyRaid = async (raid: Raid | { id: number }) => {
- await this.notifyRaids()
- const data = await this.raidManager.getRaidData(<Raid>raid)
- await this.pubsub.publish("" + raid.id, data)
- }
-
- notifyRaids = async () => {
- await this.pubsub.publish('raids', undefined)
- }
-
- wipeCurrencyAndItems = async () => {
- await Promise.all([
- this.userManager.wipeCurrency(),
- Promise.all(_Tiers.map(tier => this.admin.knex(tier + 'tokens').where(true).del()))
- ])
- }
-
- getItems = async (): Promise<Item[]> => await this.admin.knex.select('*').from('items')
-
- getItem = async (name: string, tier?:Tiers): Promise<Item | undefined> => {
- let item = await this.admin.knex('items').select('*').where('itemname', '=', name).first()
- if(!item){
- item = await this.fetchItem(name, tier)
- if (!item)
- return
-
- await this.admin
- .knex('items')
- .insert({
- ...item,
- stats: JSON.stringify(item.stats)
- })
-
- return this.getItem(name, tier)
- }
-
- item.stats = JSON.parse(item.stats)
- return item
- }
-
- fetchItem = async (name: string, tier?:Tiers): Promise<Item | undefined> => {
- const res = await fetch('https://classic.wowhead.com/item=' + name + '&xml');
- const txt = await res.text();
- const r = await parser.parseStringPromise(txt);
- try{
- if(!r.wowhead.item || !r.wowhead.item[0])
- return
-
- const j = JSON.parse('{'+r.wowhead.item[0].json[0]+"}")
- if(!tier){
- if(j.sourcemore && Number.isInteger(j.sourcemore[0].t) && j.sourcemore[0].t > 0){
- tier = _Tiers[j.sourcemore[0].t-1]
- }else{
- tier = "MC"
- }
- }
- const stats = JSON.parse('{'+r.wowhead.item[0].jsonEquip[0]+"}")
-
- const item = <Item>{
- itemname: r.wowhead.item[0].name[0],
- iconname: r.wowhead.item[0].icon[0]._,
- url: r.wowhead.item[0].link[0],
- quality: r.wowhead.item[0].quality[0]._,
- tooltip: r.wowhead.item[0].htmlTooltip[0],
- stats: toStats(stats),
- tier: tier
- }
- return item
-
- }catch(e){
- getLogger('ItemManager', 'error').error(name, e);
- }
- }
-
- getTableDefinitions(): TableDefiniton[] {
- return [
- ...['null', ..._Tiers].map(tier => {
- return {
- name: tier + 'tokens',
- tableBuilder: (table) => {
- table.primary(['characterid', 'itemname'])
- table.integer("characterid")
- table.foreign("characterid").references("id").inTable('characters')
- table.string("itemname")
- table.foreign("itemname").references("itemname").inTable('items')
- table.string("signupid").nullable()
- table.foreign("signupid").references("id").inTable('signups').onDelete('SET NULL')
- table.integer("level").defaultTo(1)
- }
- }
- }), {
- name: 'priorities',
- tableBuilder: (table) => {
- table.increments('id').primary()
- table.string('itemname')
- table.foreign('itemname').references('itemname').inTable('items')
- table.string('race').nullable()
- table.integer('specid').nullable()
- table.foreign('specid').references('id').inTable('specs')
- table.integer('modifier')
- table.string('description').nullable()
- }
- }, {
- name: 'items',
- tableBuilder: (table) => {
- table.string('itemname').unique().notNullable().primary()
- table.string('iconname').notNullable()
- table.string('url').notNullable()
- table.string('quality').defaultTo('Epic').notNullable()
- table.boolean('hidden').defaultTo(false).notNullable()
- table.string('tooltip').notNullable()
- table.enu('tier', _Tiers).notNullable()
- table.json('stats').notNullable()
- }
- }]
- }
-
- buyToken = async (usertoken: string, charactername: string, itemname: string, signup: Signup): Promise<(SRToken & Character & Item) | undefined> => {
- const record = this.userManager.getUserRecordByToken(usertoken)
- const character = await this.character.getCharacterByName(charactername)
-
- if (!record || !character || record.user.username !== character.username) return
-
- const item = await this.getItem(itemname)
- if (!item) return
-
- const currency = await this.userManager.getCurrency(record.user, item.tier)
- if (currency < 1) return
-
- const streaks = await this.getTokens(character, [item.tier], false)
- const activeTokens = await this.getTokens(character, [item.tier], true)
-
- await this.userManager.decrementCurrency(record.user, item.tier, 1)
- const modifier = await this.calculatePriorities(itemname, character)
-
- const tx = await this.admin.knex.transaction()
-
- if (streaks.length > 0) {
- const myStreak = streaks.find(token => token.itemname === itemname)
- if (myStreak) {
- //getLogger('ItemManager').debug('update signupid and increment level')
- await this.admin
- .knex(item.tier + 'tokens')
- .transacting(tx)
- .where({
- characterid: character.id,
- itemname: item.itemname
- })
- .update({
- signupid: signup.id,
- level: myStreak.level + 1
- })
-
- }
-
- //getLogger('ItemManager').debug('delete streaks')
- await Promise.all(streaks.map(async s => await this.admin
- .knex(item.tier + 'tokens')
- .transacting(tx)
- .where({
- itemname: s.itemname,
- characterid: character.id,
- signupid: null
- })
- .del()
- ))
-
- if (myStreak) {
- await tx.commit()
- await this.notifyRaid({ id: signup.raidid })
-
- return await this.getToken(character, item)
- }
- }
-
- const matchingReserve = activeTokens.find(token => token.itemname === itemname)
- if (matchingReserve) {
- //getLogger('ItemManager').debug('upgrade reserve')
- await this.admin
- .knex(item.tier + 'tokens')
- .transacting(tx)
- .increment('level')
- .where({
- signupid: signup.id,
- characterid: character.id,
- itemname: item.itemname
- })
- } else {
- //getLogger('ItemManager').debug('new reserve')
- await this.admin
- .knex(item.tier + 'tokens')
- .transacting(tx)
- .insert({
- characterid: character.id,
- itemname: item.itemname,
- level: 1 + modifier,
- signupid: signup.id
- })
- }
- await tx.commit()
- await this.notifyRaid({ id: signup.raidid })
-
- return await this.getToken(character, item)
- }
-
- getAllPriorities = async (): Promise<(SRPriority & Spec & Item)[]> => this.admin
- .knex('priorities as p')
- .join('items as i', 'p.itemname', '=', 'i.itemname')
- .leftJoin('specs as s', 'p.specid', '=', 's.id')
- .select('*')
-
- deletePriority = async (priority: SRPriority): Promise<void> => {
- await this.admin.knex('priorities')
- .where(priority)
- .del()
- }
-
- setPriority = async (itemname: string, priority: SRPriority): Promise<void> => {
- const item = await this.getItem(itemname)
-
- await this.admin
- .knex('priorities')
- .insert(<SRPriority>{
- itemname: item!.itemname,
- ...priority
- })
- }
-
- getPriorities = async (itemname: string): Promise<SRPriority[]> => {
- return await this.admin
- .knex('priorities as p')
- .where('p.itemname', '=', itemname)
- .select('*')
- }
-
- calculatePriorities = async (itemname: string, character: Character): Promise<number> => {
- const rules: SRPriority[] = await this.admin
- .knex('priorities as p')
- .select('*')
- .join('items as i', 'i.itemname', '=', 'p.itemname')
- .where('p.itemname', '=', itemname)
-
- return rules.map(rule => {
- if (rule.specid && rule.race) {
- if (rule.specid === character.specid && rule.race === character.race)
- return rule.modifier
- else
- return 0
- }
-
- if (rule.specid) {
- if (rule.specid === character.specid)
- return rule.modifier
- else
- return 0
- }
-
- if (rule.race) {
- if (rule.race === character.race)
- return rule.modifier
- else
- return 0
- }
- return 0
- }).reduce((prev, curr) => prev + curr, 0)
- }
-
- getToken = async (character: Character, item: Item, valid = true): Promise<(SRToken & Character & Item) | undefined> => {
- return await this.admin
- .knex(item.tier + 'tokens as t')
- .select('*')
- .join('characters as c', 'c.id', '=', 't.characterid')
- .join('items as i', 'i.itemname', '=', 't.itemname')
- .where({
- characterid: character.id,
- "i.itemname": item.itemname
- })
- .andWhere(function () {
- if (valid) {
- this.whereNotNull('t.signupid')
- } else {
- this.whereNull('t.signupid')
- }
- })
- .first()
- }
-
- getTokens = async (character: Character, tiers: Tiers[], valid = true): Promise<(SRToken & Character & Item)[]> => {
- const ret = await Promise.all(tiers.map(async tier => {
- return await this.admin
- .knex(tier + 'tokens as t')
- .select('*')
- .join('characters as c', 'c.id', '=', 't.characterid')
- .join('items as i', 'i.itemname', '=', 't.itemname')
- .where({
- characterid: character.id,
- })
- .andWhere(function () {
- if (valid) {
- this.whereNotNull('t.signupid')
- } else {
- this.whereNull('t.signupid')
- }
- })
- }))
- return ret.flat()
- }
-
- countItems = async (): Promise<number> => {
- const count = await this.admin
- .knex('items')
- .count('*');
-
- return <number>count[0]['count(*)']
- }
-
- private initialized = false
- initialize = async () => {
- if (this.initialized) return
- this.initialized = true
-
- const itemTiers = allItems
-
- const countCache = await this.countItems()
-
- if (countCache != Object.values(itemTiers).flat().length) {
- await Promise.all(
- Object.entries(itemTiers)
- .map((kv: [string, string[]]) => Promise.all(
- kv[1].map(i => this.getItem(i, kv[0] as Tiers) )
- ))
- )
- }
- }
- }
-
- function toStats(obj:any){
- if(!obj) obj = {}
- return {
- stamina: obj.sta || 0,
- agility: obj.agi || 0,
- strength: obj.str || 0,
- intellect: obj.int || 0,
- spirit: obj.spi || 0,
-
- attackpower: obj.atkpwr || 0,
-
- meleehit: obj.mlehitpct || 0,
- meleecrit: obj.mlecritstrkpct || 0,
-
- rangeattackpower: obj.rgdatkpwr || 0,
- rangehit: obj.rgdhitpct || 0,
- rangecrit: obj.rgdcritstrkpct || 0,
-
- spellpower: obj.splpwr || 0,
- spellhit: obj.splhitpct || 0,
- spellcrit: obj.splcritstrkpct || 0,
- heal: obj.splheal || 0,
-
- frostspellpower: obj.frosplpwr || 0,
- firespellpower: obj.firsplpwr || 0,
- naturespellpower: obj.natsplpwr || 0,
- shadowspellpower: obj.shasplpwr || 0,
- arcanespellpower: obj.arcsplpwr || 0,
-
- fireresist: obj.firres || 0,
- arcaneresist: obj.arcres || 0,
- frostresist: obj.frores || 0,
- natureresist: obj.natres || 0,
- shadowresist: obj.shares || 0,
-
- armor: obj.armor || 0,
- defense: obj.def || 0,
- block: obj.blockpct || 0,
- blockvalue: obj.blockamount || 0,
- dodge: obj.dodgepct || 0,
- parry: obj.parrypct || 0,
- } as Stats
-
- }
|