Improve hero balance action
This commit is contained in:
parent
18f43c3931
commit
d1a2128411
@ -1,10 +1,11 @@
|
||||
import { Scheduler } from '../Scheduler';
|
||||
import { ActionError, TryLaterError } from '../Errors';
|
||||
import { AbortTaskError, TryLaterError } from '../Errors';
|
||||
import { grabActiveVillageId } from '../Page/VillageBlock';
|
||||
import { aroundMinutes } from '../utils';
|
||||
import { Args } from '../Queue/Args';
|
||||
import { Task } from '../Queue/TaskProvider';
|
||||
import { VillageStorage } from '../Storage/VillageStorage';
|
||||
import { VillageStateRepository } from '../VillageState';
|
||||
|
||||
const actionMap: { [name: string]: Function | undefined } = {};
|
||||
|
||||
@ -12,29 +13,35 @@ export function registerAction(constructor: Function) {
|
||||
actionMap[constructor.name] = constructor;
|
||||
}
|
||||
|
||||
export function createActionHandler(name: string, scheduler: Scheduler): ActionController | undefined {
|
||||
export function createActionHandler(
|
||||
name: string,
|
||||
scheduler: Scheduler,
|
||||
villageStateRepository: VillageStateRepository
|
||||
): ActionController | undefined {
|
||||
const storedFunction = actionMap[name];
|
||||
if (storedFunction === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const constructor = (storedFunction as unknown) as typeof ActionController;
|
||||
return new constructor(scheduler);
|
||||
return new constructor(scheduler, villageStateRepository);
|
||||
}
|
||||
|
||||
export function err(msg: string): never {
|
||||
throw new ActionError(msg);
|
||||
export function taskError(msg: string): never {
|
||||
throw new AbortTaskError(msg);
|
||||
}
|
||||
|
||||
export class ActionController {
|
||||
protected scheduler: Scheduler;
|
||||
constructor(scheduler: Scheduler) {
|
||||
protected villageStateRepository: VillageStateRepository;
|
||||
constructor(scheduler: Scheduler, villageStateRepository: VillageStateRepository) {
|
||||
this.scheduler = scheduler;
|
||||
this.villageStateRepository = villageStateRepository;
|
||||
}
|
||||
|
||||
async run(args: Args, task: Task) {}
|
||||
|
||||
ensureSameVillage(args: Args, task: Task) {
|
||||
let villageId = args.villageId || err('Undefined village id');
|
||||
let villageId = args.villageId || taskError('Undefined village id');
|
||||
const activeVillageId = grabActiveVillageId();
|
||||
if (villageId !== activeVillageId) {
|
||||
throw new TryLaterError(aroundMinutes(1), 'Not same village');
|
||||
|
@ -1,15 +1,11 @@
|
||||
import { ActionController, registerAction } from './ActionController';
|
||||
import { grabVillageResources, grabVillageResourceStorage } from '../Page/ResourcesBlock';
|
||||
import { changeHeroResource, grabCurrentHeroResource } from '../Page/HeroPage';
|
||||
import { grabActiveVillageId, grabVillageList } from '../Page/VillageBlock';
|
||||
import { grabActiveVillageId } from '../Page/VillageBlock';
|
||||
import { HeroStorage } from '../Storage/HeroStorage';
|
||||
import { calcHeroResource } from '../Core/HeroBalance';
|
||||
import { HeroAllResources } from '../Core/Hero';
|
||||
import { Args } from '../Queue/Args';
|
||||
import { Task } from '../Queue/TaskProvider';
|
||||
import { Resources } from '../Core/Resources';
|
||||
import { createVillageStates } from '../VillageState';
|
||||
import { ActionError } from '../Errors';
|
||||
|
||||
@registerAction
|
||||
export class BalanceHeroResourcesAction extends ActionController {
|
||||
@ -22,13 +18,7 @@ export class BalanceHeroResourcesAction extends ActionController {
|
||||
return;
|
||||
}
|
||||
|
||||
const villages = grabVillageList();
|
||||
const villageStates = createVillageStates(villages, this.scheduler);
|
||||
const thisVillageState = villageStates.find(s => s.id === thisVillageId);
|
||||
|
||||
if (!thisVillageState) {
|
||||
throw new ActionError(`State for village ${thisVillageId} not found`);
|
||||
}
|
||||
const thisVillageState = this.villageStateRepository.getVillageState(thisVillageId);
|
||||
|
||||
const requirements = [
|
||||
thisVillageState.required.balance,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ActionController, err, registerAction } from './ActionController';
|
||||
import { ActionController, taskError, registerAction } from './ActionController';
|
||||
import { GrabError, TryLaterError } from '../Errors';
|
||||
import { clickBuildButton } from '../Page/BuildingPage/BuildingPage';
|
||||
import { aroundMinutes } from '../utils';
|
||||
@ -11,7 +11,7 @@ export class BuildBuildingAction extends ActionController {
|
||||
try {
|
||||
this.ensureSameVillage(args, task);
|
||||
this.ensureBuildingQueueIsEmpty();
|
||||
const buildTypeId = args.buildTypeId || err('Undefined build type id');
|
||||
const buildTypeId = args.buildTypeId || taskError('Undefined build type id');
|
||||
clickBuildButton(buildTypeId);
|
||||
} catch (e) {
|
||||
if (e instanceof GrabError) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ActionController, err, registerAction } from './ActionController';
|
||||
import { ActionController, taskError, registerAction } from './ActionController';
|
||||
import { GrabError, TryLaterError } from '../Errors';
|
||||
import { aroundMinutes } from '../utils';
|
||||
import { Args } from '../Queue/Args';
|
||||
@ -10,7 +10,7 @@ export class ForgeImprovementAction extends ActionController {
|
||||
async run(args: Args, task: Task): Promise<any> {
|
||||
try {
|
||||
this.ensureSameVillage(args, task);
|
||||
const unitId = args.unitId || err('No unitId in args');
|
||||
const unitId = args.unitId || taskError('No unitId in args');
|
||||
clickResearchButton(unitId);
|
||||
} catch (e) {
|
||||
if (e instanceof GrabError) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ActionController, err, registerAction } from './ActionController';
|
||||
import { ActionController, taskError, registerAction } from './ActionController';
|
||||
import { AbortTaskError, TryLaterError } from '../Errors';
|
||||
import { Resources } from '../Core/Resources';
|
||||
import { Coordinates, Village } from '../Core/Village';
|
||||
@ -15,7 +15,7 @@ const TIMEOUT = 15;
|
||||
@registerAction
|
||||
export class SendResourcesAction extends ActionController {
|
||||
async run(args: Args, task: Task): Promise<any> {
|
||||
const coordinates = Coordinates.fromObject(args.coordinates || err('No coordinates'));
|
||||
const coordinates = Coordinates.fromObject(args.coordinates || taskError('No coordinates'));
|
||||
|
||||
const recipientVillage = args.targetVillageId
|
||||
? this.findRecipientVillageById(args.targetVillageId)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ActionController, err, registerAction } from './ActionController';
|
||||
import { ActionController, taskError, registerAction } from './ActionController';
|
||||
import { TryLaterError } from '../Errors';
|
||||
import { aroundMinutes, randomInRange } from '../utils';
|
||||
import { Args } from '../Queue/Args';
|
||||
@ -10,9 +10,9 @@ import { Resources } from '../Core/Resources';
|
||||
@registerAction
|
||||
export class TrainTrooperAction extends ActionController {
|
||||
async run(args: Args, task: Task): Promise<any> {
|
||||
const troopId = args.troopId || err('No troop id');
|
||||
const trainCount = args.trainCount || err('No troop train count');
|
||||
const troopResources = args.troopResources || err('No troop resources');
|
||||
const troopId = args.troopId || taskError('No troop id');
|
||||
const trainCount = args.trainCount || taskError('No troop train count');
|
||||
const troopResources = args.troopResources || taskError('No troop resources');
|
||||
|
||||
const availableCount = getAvailableCount(troopId);
|
||||
const desiredCount = randomInRange(3, 12);
|
||||
|
@ -8,6 +8,7 @@ import { DataStorageTaskProvider } from './Queue/DataStorageTaskProvider';
|
||||
import { Statistics } from './Statistics';
|
||||
import { StatisticsStorage } from './Storage/StatisticsStorage';
|
||||
import { VillageRepository, VillageRepositoryInterface } from './VillageRepository';
|
||||
import { VillageStateRepository } from './VillageState';
|
||||
|
||||
export class Container {
|
||||
private readonly version: string;
|
||||
@ -16,7 +17,7 @@ export class Container {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
private _villageRepository: VillageRepositoryInterface | undefined;
|
||||
private _villageRepository: VillageRepository | undefined;
|
||||
|
||||
get villageRepository(): VillageRepository {
|
||||
this._villageRepository =
|
||||
@ -27,6 +28,17 @@ export class Container {
|
||||
return this._villageRepository;
|
||||
}
|
||||
|
||||
private _statistics: Statistics | undefined;
|
||||
|
||||
get statistics(): Statistics {
|
||||
this._statistics =
|
||||
this._statistics ||
|
||||
(() => {
|
||||
return new Statistics(new StatisticsStorage());
|
||||
})();
|
||||
return this._statistics;
|
||||
}
|
||||
|
||||
private _scheduler: Scheduler | undefined;
|
||||
|
||||
get scheduler(): Scheduler {
|
||||
@ -41,13 +53,24 @@ export class Container {
|
||||
return this._scheduler;
|
||||
}
|
||||
|
||||
private _villageStateRepository: VillageStateRepository | undefined;
|
||||
|
||||
get villageStateRepository(): VillageStateRepository {
|
||||
this._villageStateRepository =
|
||||
this._villageStateRepository ||
|
||||
(() => {
|
||||
return new VillageStateRepository(this.villageRepository, this.scheduler);
|
||||
})();
|
||||
return this._villageStateRepository;
|
||||
}
|
||||
|
||||
private _executor: Executor | undefined;
|
||||
|
||||
get executor(): Executor {
|
||||
this._executor =
|
||||
this._executor ||
|
||||
(() => {
|
||||
return new Executor(this.version, this.scheduler, this.statistics);
|
||||
return new Executor(this.version, this.scheduler, this.villageStateRepository, this.statistics);
|
||||
})();
|
||||
return this._executor;
|
||||
}
|
||||
@ -58,19 +81,8 @@ export class Container {
|
||||
this._controlPanel =
|
||||
this._controlPanel ||
|
||||
(() => {
|
||||
return new ControlPanel(this.version, this.scheduler);
|
||||
return new ControlPanel(this.version, this.scheduler, this.villageStateRepository);
|
||||
})();
|
||||
return this._controlPanel;
|
||||
}
|
||||
|
||||
private _statistics: Statistics | undefined;
|
||||
|
||||
get statistics(): Statistics {
|
||||
this._statistics =
|
||||
this._statistics ||
|
||||
(() => {
|
||||
return new Statistics(new StatisticsStorage());
|
||||
})();
|
||||
return this._statistics;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { notify, parseLocation, timestamp, uniqId, waitForLoad } from './utils';
|
||||
import { Scheduler } from './Scheduler';
|
||||
import { BuildingPageController } from './Page/BuildingPageController';
|
||||
import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
|
||||
import { grabActiveVillageId, grabVillageList } from './Page/VillageBlock';
|
||||
import { grabActiveVillageId } from './Page/VillageBlock';
|
||||
import {
|
||||
grabResourceDeposits,
|
||||
onBuildingSlotCtrlClick,
|
||||
@ -17,7 +17,7 @@ import { ConsoleLogger, Logger } from './Logger';
|
||||
import { DataStorage } from './DataStorage';
|
||||
import { getBuildingPageAttributes, isBuildingPage } from './Page/PageDetectors';
|
||||
import { ExecutionStorage } from './Storage/ExecutionStorage';
|
||||
import { createVillageStates, VillageState } from './VillageState';
|
||||
import { VillageState, VillageStateRepository } from './VillageState';
|
||||
import { Task } from './Queue/TaskProvider';
|
||||
import { Action } from './Queue/ActionQueue';
|
||||
|
||||
@ -47,11 +47,13 @@ interface GameState {
|
||||
export class ControlPanel {
|
||||
private readonly version: string;
|
||||
private readonly scheduler: Scheduler;
|
||||
private readonly villageStateRepository: VillageStateRepository;
|
||||
private readonly logger: Logger;
|
||||
|
||||
constructor(version: string, scheduler: Scheduler) {
|
||||
constructor(version: string, scheduler: Scheduler, villageStateRepository: VillageStateRepository) {
|
||||
this.version = version;
|
||||
this.scheduler = scheduler;
|
||||
this.villageStateRepository = villageStateRepository;
|
||||
this.logger = new ConsoleLogger(this.constructor.name);
|
||||
}
|
||||
|
||||
@ -64,6 +66,7 @@ export class ControlPanel {
|
||||
const villageId = grabActiveVillageId();
|
||||
|
||||
const scheduler = this.scheduler;
|
||||
const villageStateRepository = this.villageStateRepository;
|
||||
|
||||
const executionState = new ExecutionStorage();
|
||||
|
||||
@ -91,7 +94,7 @@ export class ControlPanel {
|
||||
},
|
||||
|
||||
refreshVillages() {
|
||||
this.villageStates = createVillageStates(grabVillageList(), scheduler);
|
||||
this.villageStates = villageStateRepository.getAllVillageStates();
|
||||
for (let state of this.villageStates) {
|
||||
if (state.village.active) {
|
||||
this.activeVillageState = state;
|
||||
|
@ -5,6 +5,13 @@ export class GrabError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export class VillageNotFound extends Error {
|
||||
constructor(msg: string = '') {
|
||||
super(msg);
|
||||
Object.setPrototypeOf(this, VillageNotFound.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
export class ActionError extends Error {
|
||||
constructor(msg: string = '') {
|
||||
super(msg);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { markPage, sleepMicro, timestamp, waitForLoad } from './utils';
|
||||
import { AbortTaskError, ActionError, GrabError, TryLaterError } from './Errors';
|
||||
import { AbortTaskError, ActionError, GrabError, TryLaterError, VillageNotFound } from './Errors';
|
||||
import { TaskQueueRenderer } from './TaskQueueRenderer';
|
||||
import { createActionHandler } from './Action/ActionController';
|
||||
import { ConsoleLogger, Logger } from './Logger';
|
||||
@ -10,6 +10,7 @@ import { ExecutionStorage } from './Storage/ExecutionStorage';
|
||||
import { Action } from './Queue/ActionQueue';
|
||||
import { Task } from './Queue/TaskProvider';
|
||||
import { createTaskHandler } from './Task/TaskMap';
|
||||
import { VillageStateRepository } from './VillageState';
|
||||
|
||||
export interface ExecutionSettings {
|
||||
pauseTs: number;
|
||||
@ -18,14 +19,21 @@ export interface ExecutionSettings {
|
||||
export class Executor {
|
||||
private readonly version: string;
|
||||
private readonly scheduler: Scheduler;
|
||||
private readonly villageStateRepository: VillageStateRepository;
|
||||
private grabbers: GrabberManager;
|
||||
private statistics: Statistics;
|
||||
private executionState: ExecutionStorage;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(version: string, scheduler: Scheduler, statistics: Statistics) {
|
||||
constructor(
|
||||
version: string,
|
||||
scheduler: Scheduler,
|
||||
villageStateRepository: VillageStateRepository,
|
||||
statistics: Statistics
|
||||
) {
|
||||
this.version = version;
|
||||
this.scheduler = scheduler;
|
||||
this.villageStateRepository = villageStateRepository;
|
||||
this.grabbers = new GrabberManager(scheduler);
|
||||
this.statistics = statistics;
|
||||
this.executionState = new ExecutionStorage();
|
||||
@ -97,7 +105,7 @@ export class Executor {
|
||||
}
|
||||
|
||||
private async processActionCommand(cmd: Action, task: Task) {
|
||||
const actionHandler = createActionHandler(cmd.name, this.scheduler);
|
||||
const actionHandler = createActionHandler(cmd.name, this.scheduler, this.villageStateRepository);
|
||||
this.logger.info('PROCESS ACTION', cmd.name, actionHandler);
|
||||
if (cmd.args.taskId !== task.id) {
|
||||
throw new ActionError(`Action task id ${cmd.args.taskId} not equal current task id ${task.id}`);
|
||||
@ -125,24 +133,30 @@ export class Executor {
|
||||
this.scheduler.clearActions();
|
||||
|
||||
if (err instanceof AbortTaskError) {
|
||||
this.logger.warn('ABORT TASK', task.id, 'MSG', err.message);
|
||||
this.logger.warn('Abort task', task.id, 'MSG', err.message);
|
||||
this.scheduler.removeTask(task.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err instanceof VillageNotFound) {
|
||||
this.logger.error('Village not found, abort task', task.id, 'msg', err.message);
|
||||
this.scheduler.removeTask(task.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err instanceof TryLaterError) {
|
||||
this.logger.warn('TRY', task.id, 'AFTER', err.seconds, 'MSG', err.message);
|
||||
this.logger.warn('Try', task.id, 'after', err.seconds, 'msg', err.message);
|
||||
this.scheduler.postponeTask(task.id, err.seconds);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err instanceof ActionError) {
|
||||
this.logger.error('ACTION ABORTED', err.message);
|
||||
if (err instanceof GrabError) {
|
||||
this.logger.error('Layout element not found, abort action', err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err instanceof GrabError) {
|
||||
this.logger.error('ELEMENT NOT FOUND, ACTION ABORTED', err.message);
|
||||
if (err instanceof ActionError) {
|
||||
this.logger.error('Abort action', err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ import { Scheduler } from './Scheduler';
|
||||
import { Resources } from './Core/Resources';
|
||||
import { VillageStorage } from './Storage/VillageStorage';
|
||||
import { calcGatheringTimings, GatheringTime } from './Core/GatheringTimings';
|
||||
import { VillageRepositoryInterface } from './VillageRepository';
|
||||
import { VillageNotFound } from './Errors';
|
||||
|
||||
interface StorageBalance {
|
||||
resources: Resources;
|
||||
@ -127,7 +129,30 @@ function createVillageState(
|
||||
return { ...state, commitments, shipment: villageIds };
|
||||
}
|
||||
|
||||
export function createVillageStates(villages: Array<Village>, scheduler: Scheduler): Array<VillageState> {
|
||||
function getVillageStates(villages: Array<Village>, scheduler: Scheduler): Array<VillageState> {
|
||||
const ownStates = createVillageOwnStates(villages, scheduler);
|
||||
return villages.map(village => createVillageState(ownStates[village.id], ownStates, scheduler));
|
||||
}
|
||||
|
||||
export class VillageStateRepository {
|
||||
private villageRepository: VillageRepositoryInterface;
|
||||
private scheduler: Scheduler;
|
||||
|
||||
constructor(villageRepository: VillageRepositoryInterface, scheduler: Scheduler) {
|
||||
this.villageRepository = villageRepository;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
getAllVillageStates(): Array<VillageState> {
|
||||
return getVillageStates(this.villageRepository.all(), this.scheduler);
|
||||
}
|
||||
|
||||
getVillageState(villageId: number): VillageState {
|
||||
const states = getVillageStates(this.villageRepository.all(), this.scheduler);
|
||||
const needle = states.find(s => s.id === villageId);
|
||||
if (!needle) {
|
||||
throw new VillageNotFound(`Village ${villageId} not found`);
|
||||
}
|
||||
return needle;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user