import { Injector } from "../src/backend/Injector/Injector"; import { FrontworkAdmin } from "../src/backend/Admin/Admin"; import { T2, Tiers } from "../src/backend/Types/Items"; import { RPCSocket, ConnectedSocket } from "rpclibrary"; import { FrontcraftIfc, Auth, User, FrontcraftFeatureIfc, Raid, Character, Rank, Class, Race, Spec, Signup } from "../src/backend/Types/Types"; import { SpecT } from "../src/backend/Types/PlayerSpecs"; import { ItemManager } from "src/backend/Components/Item/ItemManager"; type protoAccount = { name: string, pwHash?: string rank: Rank, race: Race, class: C, spec: SpecT[C] } const trialsAndUp = { ADMIN: true, Guildmaster: true, Officer: true, Classleader: true, Raider: true, Trial: true, Social: false, Guest: false } const adminsOnly = { ADMIN: true, Guildmaster: true, Officer: true, Classleader: false, Raider: false, Trial: false, Social: false, Guest: false } const defaultPermissions = [ { rpcname: 'signup', ...trialsAndUp }, { rpcname: 'reset', ...adminsOnly }, { rpcname: 'modifyPermissions', ...adminsOnly }, { rpcname: 'manageGuild', ...adminsOnly }, { rpcname: 'managePriorities', ...adminsOnly }, { rpcname: 'softreserveCurrency', ...adminsOnly }, { rpcname: 'manageRaid', ...adminsOnly }, { rpcname: 'manageUser', ...adminsOnly }] const testAccounts: protoAccount[] = [ { name: 'Rain', race: 'Human', class: 'Warrior', spec: 'Protection', rank: 'Guildmaster' }, { name: 'Celinda', class: 'Warrior', race: 'Night Elf', spec: 'Protection', rank: 'Officer' }, { name: 'Silver', class: 'Druid', race: 'Night Elf', spec: 'Restoration', rank: 'Trial' }, { name: 'Dagger', race: 'Dwarf', class: 'Rogue', spec: 'Assassination', rank: 'Classleader' }, { name: 'Hope', class: 'Paladin', race: 'Human', spec: 'Holy', rank: 'Classleader' }, { name: 'Shrekd', class: 'Warrior', race: 'Dwarf', spec: 'Fury', rank: 'Classleader' }, { name: 'Teeniweeni', class: 'Warlock', race: 'Gnome', spec: 'Demonology', rank: 'Classleader' }, { name: 'Hagibaba', class: 'Priest', race: 'Human', spec: 'Discipline', rank: 'Classleader' }, { name: 'Muffinbreak', class: 'Mage', race: 'Gnome', spec: 'Arcane', rank: 'Classleader' }, ] describe('Frontcraft', () => { let auth: Auth, adminUser: User, server: FrontworkAdmin, client: ConnectedSocket, adminClient: ConnectedSocket, raids: Raid[] = [], users: { [username in string]: { account: User, character: Character, auth: Auth, signup?: Signup, item?: string } } = {} const createAccount = (user: User) => { return client.UserManager.createUser(user) } const createAccountAndUser = async (acc: protoAccount) => { const account = await createAccount({ pwhash: 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', //sha256("a") rank: acc.rank, username: acc.name, }) const auth = await client.UserManager.login(acc.name, 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb') const id = await client.CharacterManager.getSpecId(acc.class, acc.spec) const char = await client.CharacterManager.createCharacter(auth.token.value, { charactername: acc.name, specid: id, userid: account.id!, race: acc.race }) return { account: account, character: char, auth: auth } } before(function (done) { this.timeout(10000); server = Injector.resolve(FrontworkAdmin) server.start().then((_server) => { RPCSocket.makeSocket(20000, 'localhost').then(_client => { client = _client createAccount({ pwhash: 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', //hash("a") rank: 'ADMIN', username: 'a', MC: 2 }).then(adminUser => { client.UserManager.login(adminUser.username, 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb').then(auth => { const sock = new RPCSocket( auth.port, "localhost" ) sock.connect(auth.token.value).then(cli => { adminClient = cli sock.hook('kick', () => { console.log("I got kicked"); }) sock.hook('getUserData', () => auth) sock.hook('navigate', (where: string) => { console.log("Nagivate client to " + where); }) sock.on('error', (e) => { console.log('Socket error', e) }) done() }) }) }) }) }).catch(done) }) after(() => { client.close() adminClient.close() server.stop() }) it('can set permissions', (done) => { Promise.all( defaultPermissions.map(perm => adminClient.modifyPermissions.setPermission(perm)), ).then(_ => { done() }) }) it('create raids', (done) => { let insertRaid = { description: "Test raid 1", title: 'BWL :D', start: Date.now().toString(), tier: 'BWL' } adminClient.manageRaid.createRaid(insertRaid).then(() => { client.RaidManager.getRaids().then((r) => { if (r[0].title === insertRaid.title && r[0].description === insertRaid.description && r[0].tier === "BWL") { raids.push(r[0]) done() } }).catch(done) }).catch(done) }) it('create users', (done) => { Promise.all(testAccounts.map(acc => createAccountAndUser(acc))).then(accs => { if (accs.length === testAccounts.length) { accs.forEach(acc => { users[acc.account.username] = acc }) done() } }).catch(done) }) it('should sign up', (done) => { Promise.all(Object.values(users).map((user) => adminClient.signup.sign(user.auth.token.value, user.character, raids[0], false, true, ""+Math.floor(Math.random()*10000)).catch(done) )).then(_ => { adminClient.signup.getSignups(raids[0]).then(s => { if (s.length == testAccounts.length) { s.forEach(sign => { users[sign.username].signup = sign }) done() } else { done("Unexpected number of signups: " + s.length) } }) }) }) it('calculate priorities', (done) => { const makePrio = async (itemname: string, spec?: Spec, race?: Race, mod: number = 0, description: string = "") => { let specid if (spec) specid = await client.CharacterManager.getSpecId(spec.class, spec.specname) await adminClient.managePriorities.setPriority(itemname, { specid: specid, race: race, modifier: mod, description: description }) } Promise.all([ makePrio( 'Quick Strike Ring', { class: 'Warrior', specname: 'Fury' }, undefined, 2, "str-to-ap bias" ), makePrio( 'Quick Strike Ring', { class: 'Druid', specname: 'Feral (DPS)' }, undefined, 2, "str-to-ap bias" ), makePrio( 'Bracers of Arcane Accuracy', { class: 'Warlock', specname: 'Demonology' }, undefined, 2, "hit bias" ), makePrio( 'Bracers of Arcane Accuracy', { class: 'Warlock', specname: 'Affliction' }, undefined, 2, "hit bias" ), makePrio( 'Bracers of Arcane Accuracy', { class: 'Warlock', specname: 'Destruction' }, undefined, 2, "hit bias" ), makePrio( 'Bracers of Arcane Accuracy', { class: 'Mage', specname: 'Arcane' }, undefined, 1, "hit bias" ), makePrio( 'Bracers of Arcane Accuracy', { class: 'Mage', specname: 'Frost' }, undefined, 1, "hit bias" ), makePrio( 'Bracers of Arcane Accuracy', { class: 'Mage', specname: 'Fire' }, undefined, 1, "hit bias" ), makePrio( 'Maladath, Runed Blade of the Black Flight', undefined, "Human", -2, "[1] Non-Human" ), makePrio( 'Maladath, Runed Blade of the Black Flight', { class: 'Rogue', specname: 'Combat' }, undefined, 2, "Weapon skill bias" ), makePrio( 'Maladath, Runed Blade of the Black Flight', { class: 'Warrior', specname: 'Fury' }, 'Human', 4, "+2 Fury Warrior (weapon skill bias), +2 to offset [1]" ), makePrio( 'Maladath, Runed Blade of the Black Flight', { class: 'Warrior', specname: 'Protection' }, 'Human', 5, "+3 Prot Warrior, +2 to offset [1]" ), makePrio( 'Cloak of Firemaw', { class: 'Rogue', specname: 'Assassination' }, undefined, 2, "agi-to-ap bias" ), makePrio( 'Cloak of Firemaw', { class: 'Rogue', specname: 'Combat' }, undefined, 2, "agi-to-ap bias" ), makePrio( 'Cloak of Firemaw', { class: 'Rogue', specname: 'Subtlety' }, undefined, 2, "agi-to-ap bias" ), makePrio( 'Band of Forced Concentration', { class: 'Warlock', specname: 'Demonology' }, undefined, 2, "hit bias" ), makePrio( 'Band of Forced Concentration', { class: 'Warlock', specname: 'Affliction' }, undefined, 2, "hit bias" ), makePrio( 'Band of Forced Concentration', { class: 'Warlock', specname: 'Destruction' }, undefined, 2, "hit bias" ), makePrio( 'Band of Forced Concentration', { class: 'Mage', specname: 'Arcane' }, undefined, 1, "hit bias" ), makePrio( 'Band of Forced Concentration', { class: 'Mage', specname: 'Frost' }, undefined, 1, "hit bias" ), makePrio( 'Band of Forced Concentration', { class: 'Mage', specname: 'Fire' }, undefined, 1, "hit bias" ), makePrio( 'Crul\'shorukh, Edge of Chaos', undefined, "Human", -2, "Non-human" ), makePrio( 'Crul\'shorukh, Edge of Chaos', { class: 'Warrior', specname: 'Fury' }, undefined, 2, "nice dps bias" ), makePrio( 'Drake Talon Pauldrons', { class: 'Warrior', specname:'Protection'}, undefined, 2, 'dodge + stats-to-threat bias' ), makePrio( 'Helm of Endless Rage', { class: 'Warrior', specname:'Protection'}, undefined, 2, 'stats-to-threat bias' ), makePrio( 'Drake Fang Talisman', { class: 'Warrior', specname: 'Protection' }, undefined, 5, "hit bias" ), makePrio( 'Drake Fang Talisman', { class: 'Rogue', specname: 'Assassination' }, undefined, 4, "hit bias" ), makePrio( 'Drake Fang Talisman', { class: 'Rogue', specname: 'Combat' }, undefined, 4, "hit bias" ), makePrio( 'Drake Fang Talisman', { class: 'Rogue', specname: 'Subtlety' }, undefined, 4, "hit bias" ), makePrio( 'Drake Fang Talisman', { class: 'Warrior', specname: 'Fury' }, undefined, 2, "hit bias" ), makePrio( 'Drake Fang Talisman', { class: 'Druid', specname: 'Feral (DPS)' }, undefined, 2, "hit bias" ), makePrio( 'Circle of Applied Force', { class: 'Warrior', specname: 'Fury' }, undefined, 2, "str-to-ap bias" ), makePrio( 'Circle of Applied Force', { class: 'Druid', specname: 'Feral (DPS)' }, undefined, 3, "str-to-ap bias + agi-to-ap bias" ), makePrio( 'Empowered Leggings', { class: 'Paladin', specname: 'Holy' }, undefined, 2, "crit bias" ), makePrio( 'Empowered Leggings', { class: 'Druid', specname: 'Restoration' }, undefined, 2, "crit bias" ), makePrio( 'Boots of the Shadow Flame', { class: 'Rogue', specname: 'Assassination' }, undefined, 2, "hit bias" ), makePrio( 'Boots of the Shadow Flame', { class: 'Rogue', specname: 'Combat' }, undefined, 2, "hit bias" ), makePrio( 'Boots of the Shadow Flame', { class: 'Rogue', specname: 'Subtlety' }, undefined, 2, "hit bias" ), makePrio( 'Boots of the Shadow Flame', { class: 'Druid', specname: 'Feral (DPS)' }, undefined, 2, "hit bias" ), makePrio( 'Neltharion\'s Tear', { class: 'Warlock', specname: 'Demonology' }, undefined, 4, "hit bias" ), makePrio( 'Neltharion\'s Tear', { class: 'Warlock', specname: 'Affliction' }, undefined, 4, "hit bias" ), makePrio( 'Neltharion\'s Tear', { class: 'Warlock', specname: 'Destruction' }, undefined, 4, "hit bias" ), makePrio( 'Neltharion\'s Tear', { class: 'Mage', specname: 'Arcane' }, undefined, 2, "hit bias" ), makePrio( 'Neltharion\'s Tear', { class: 'Mage', specname: 'Frost' }, undefined, 2, "hit bias" ), makePrio( 'Neltharion\'s Tear', { class: 'Mage', specname: 'Fire' }, undefined, 2, "hit bias" ), makePrio( 'Cloak of Draconic Might', { class: 'Warrior', specname: 'Fury' }, undefined, 2, "str-to-ap bias" ), makePrio( 'Cloak of Draconic Might', { class: 'Druid', specname: 'Feral (DPS)' }, undefined, 3, "str-to-ap + agi-to-ap bias" ), ]).then(() => { const user = Object.values(users)[0] client.ItemManager.calculatePriorities("Maladath, Runed Blade of the Black Flight", user.character).then(sum => { if (sum === 3) done() else console.log("Expected prio on maladath to be 4, but was:", sum, user.character); }) }) }) it('buy token', (done) => { Promise.all(Object.values(users).map(async (user) => { const itemname = "Maladath, Runed Blade of the Black Flight" //T1[Math.floor(T1.length*Math.random())] const modifier = await client.ItemManager.calculatePriorities(itemname, user.character) const token = await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!) users[user.account.username].item = itemname if (!token) return false return modifier + 2 === token.level })).then(success => { if (success.reduce((prev, curr) => prev && curr, true)) done() }) }) it('not buy token without currency', (done) => { const user = Object.values(users)[0] const itemname = "Maladath, Runed Blade of the Black Flight" client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, user.signup!).then(token => { if (!token) done() else { console.log("Unexpected token", token); } }) }) it('upgrade token', (done) => { const user = Object.values(users)[0] const itemname = "Maladath, Runed Blade of the Black Flight" client.ItemManager.getItem(itemname).then(async item => { await adminClient.softreserveCurrency.incrementCurrency(user.account, item!.tier, 2) const before = await client.ItemManager.getToken(user.character, item!) if (!before || before.level !== 5) { console.log("expected level to be 5", before ? before.level : '?'); return } done() }) }) it('should buy more tokens', (done) => { Promise.all(Object.values(users).map(async (user) => { await adminClient.softreserveCurrency.incrementCurrency(user.account, raids[0].tier, 1) return await client.ItemManager .buyToken( user.auth.token.value, user.character.charactername, T2[Math.floor(T2.length * Math.random())], user.signup! ) })).then(_ => { done() }) }) it('start raid', (done) => { client.RaidManager.getRaids().then((r) => { adminClient.manageRaid.startRaid(raids[0]).then(async data => { const dbRaids = await client.RaidManager.getRaids() if (dbRaids.length === 0) { await client.UserManager.getUser(testAccounts[0].name).then(dbUser => { if (dbUser && dbUser.BWL === 1) { adminClient.signup.getSignups(raids[0]).then(signups => { if (signups.length === 0) { done() } else { console.log(signups); } }) } else { console.log("Bad user currency", dbUser); } }) } }) }) }) it('reset system', (done) => { adminClient.reset.wipeCurrencyAndItems().then(() => { client.UserManager.getUser(testAccounts[0].name).then(user => { if (user && user.MC === 1) { client.ItemManager.getTokens(users[testAccounts[0].name.toLowerCase()].character, ['BWL'], true).then(tokens => { if (tokens!.length === 0) { done() } else { console.log(tokens); } }) } else { console.log(user) } }) }) }) it('implements loot system correctly', (done) => { const ONE_WEEK = 4800000000 const Raid = (week: number, tier: string) => { return { description: tier + " Test raid 1", title: tier, start: (week * ONE_WEEK + Date.now()).toString(), tier: tier } } const user = Object.values(users)[0] const createRaid = adminClient.manageRaid.createRaid const sign = async (raid: Raid, late = false) => await adminClient.signup.sign(user.auth.token.value, user.character, raid, late, false) const buyToken = async (signup: Signup, itemname: string) => await client.ItemManager.buyToken(user.auth.token.value, user.character.charactername, itemname, signup) const getCurrency = async (tier: Tiers) => { const dbUser = await client.UserManager.getUser(user.account.username) return dbUser[tier] } createRaid(Raid(0, 'BWL')).then(async (BWL0: Raid) => { const T2_0 = await client.ItemManager.getItem(T2[0]) const signupBWL0 = await sign(BWL0) let BWL = await getCurrency(BWL0.tier) let token = await buyToken(signupBWL0, T2[0]) const BWLAfter = await getCurrency(BWL0.tier) if (!token || BWL - BWLAfter != 1) { console.log("Bad Token status", BWL0, signupBWL0, BWL, BWLAfter) done(new Error("Bad Token status 0")) return } let reserves = await client.ItemManager.getTokens(user.character, [BWL0.tier], true) let streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false) if (reserves!.length != 1){ console.log("Expected reserves to be of length 1", reserves); done(new Error("Bad token status")) } if(streaks!.length != 0){ console.log("Expected streaks to be of length 0", streaks); done(new Error("Bad token status")) } if(reserves![0].itemname !== T2_0!.itemname){ console.log("Expected reserve to to be of item "+T2_0!.itemname, reserves![0]); done(new Error("Bad token status")) } if(reserves![0].level !== 2){ console.log("Expected reserve to to be of level "+2, reserves![0].level); done(new Error("Bad Token status")) } await adminClient.manageRaid.startRaid(BWL0) reserves = await client.ItemManager.getTokens(user.character, [BWL0.tier], true) streaks = await client.ItemManager.getTokens(user.character, [BWL0.tier], false) if (reserves!.length != 0 || streaks!.length != 1 || streaks![0].itemname !== T2[0] || streaks![0].level !== 1) { console.log("Bad Token status 2", reserves, streaks); done(new Error("Bad Token status 2")) return } const BWL1 = await createRaid(Raid(1, 'BWL')) let signupBWL1 = await sign(BWL1) BWL = await getCurrency(BWL1.tier) await adminClient.manageRaid.adminUnsign(user.character, BWL1) let afterUnsign = await getCurrency(BWL1.tier) if (BWL !== afterUnsign) { console.log("Expected currency to be equal", BWL, afterUnsign) done(new Error("Expected currency to be equal")) return } signupBWL1 = await sign(BWL1) BWL = await getCurrency(BWL1.tier) await buyToken(signupBWL1, T2[1]) await adminClient.manageRaid.adminUnsign(user.character, BWL1) afterUnsign = await getCurrency(BWL1.tier) if (BWL !== afterUnsign) { console.log("Expected currency to be equal", BWL, afterUnsign) done(new Error("Expected currency to be equal")) return } signupBWL1 = await sign(BWL1) await buyToken(signupBWL1, T2[1]) reserves = await client.ItemManager.getTokens(user.character, [BWL1.tier], true) streaks = await client.ItemManager.getTokens(user.character, [BWL1.tier], false) if (reserves!.length != 1 || streaks!.length != 0 || reserves![0].itemname !== T2[1] || reserves![0].level !== 2) { console.log("Bad Token status 3", reserves, streaks); done(new Error("Bad Token status 3")) return } BWL = await getCurrency(BWL1.tier) const data = await adminClient.manageRaid.startRaid(BWL1) const afterStart = await getCurrency(BWL1.tier) if (BWL != 0 || afterStart != 1) { console.log("Wrong currency values", BWL, afterStart) done(new Error("Wrong currency values")) return } done() }).catch(e => { console.log(e); done(e) }) }) })