ogame-bot-api
Version:
Api to create a bot for ogame
120 lines (112 loc) • 4.5 kB
text/typescript
import { Upgrade, ResourceList, Status, BuildingLight, BuildingType, BuildingList } from "../types";
import { stringToStatus, stringToResourceType, getEmptyResourceList } from "../typesHelper";
import { Page, ElementHandle } from 'puppeteer';
import { openPannel } from "./pannel";
const COST_SELECTOR = '[class=costs]';
const getBuildingUpgradeUrl = async (status: Status, elem: ElementHandle<Element>): Promise<string | undefined> => {
if (status === 'on') {
return await elem.evaluate(e => {
const button = e.querySelector('button');
if (!button) return undefined;
return button.getAttribute('data-target');
});
}
return undefined;
};
// Page should have upgrade pannel open
const getUpgradeCosts = async (page: Page): Promise<ResourceList> => {
const costElem = await page.$(COST_SELECTOR);
const resourcesElem = await costElem.$$('[class*=resource]');
const costs = getEmptyResourceList();
await Promise.all(resourcesElem.map(async resourceElem => {
const { value, classname } = await resourceElem.evaluate(elem => ({
value: Number(elem.getAttribute('data-value')),
classname: elem.getAttribute('class'),
}));
const resource = stringToResourceType(classname.split(' ').find(c => stringToResourceType(c)));
if (!resource) throw new Error(`Can't find resource in ${classname}`);
costs[resource] = value;
}));
return costs;
};
const parseDateInterval = (time: string): number => {
let total = 0;
let offset = time.length - 1;
let factor = 0;
let streak = 0;
let currNb = 0;
while (offset >= 0) {
const c = time.charAt(offset);
if (isNaN(Number(c))) {
total += currNb * factor;
factor = 0;
streak = 0;
currNb = 0;
} else {
const nb = Number(c);
currNb += nb * (10 ** streak);
streak += 1;
}
if (c === 'S') factor = 1;
if (c === 'M') factor = 60;
if (c === 'D') factor = 60 * 24;
if (c === 'Y') factor = 60 * 24 * 365;
offset -= 1;
}
return total;
};
// Page should have upgrade pannel open
const getUpgradeTime = async (page: Page): Promise<number> => {
const buildTimeDiv = await page.$('[class="build_duration"]');
const timeElem = await buildTimeDiv.$('time');
const timeString = await timeElem.evaluate(e => e.getAttribute('datetime'));
return parseDateInterval(timeString);
};
const loadUpgrade = async (status: Status, id: number, elem: ElementHandle<Element>, page: Page): Promise<Upgrade> => {
await openPannel(page, elem, id);
return {
costs: await getUpgradeCosts(page),
url: await getBuildingUpgradeUrl(status, elem),
time: await getUpgradeTime(page),
};
};
export const loadBuildingLight = async (elem: ElementHandle<Element>, page: Page): Promise<BuildingLight> => {
const id = Number(await elem.evaluate(e => e.getAttribute('data-technology')));
const status = stringToStatus(await elem.evaluate(e => e.getAttribute('data-status')));
const level = await elem.evaluate(e => {
let levelElem = e.querySelector('[class=level]');
if (!levelElem) levelElem = e.querySelector('[class=amount]');
return Number(levelElem.getAttribute('data-value')) + Number(levelElem.getAttribute('data-bonus'));
});
const building: BuildingLight = {
id,
status,
level,
upgrade: await loadUpgrade(status, id, elem, page),
};
return building;
};
export async function loadBuildings<T extends BuildingType>(
page: Page,
allTypes: T[],
silenceError: boolean = false,
selector: string = "[data-technology]",
): Promise<BuildingList<T>> {
const elems = await page.$$(selector);
const buildings: BuildingList<T> = {};
for (const elem of elems) {
const classnames = (await elem.evaluate(e => e.getAttribute('class'))).split(' ');
const type: T | undefined = allTypes.find(t => classnames.some(c => c.toLowerCase() === t.toLowerCase()));
if (!type) {
if (!silenceError) console.error(`Unkown building type ${classnames} not in ${allTypes}`);
continue;
}
const building = await loadBuildingLight(elem, page);
buildings[type] = {
...building,
type,
__elem: elem,
};
}
return buildings;
}