diff --git a/src/Action/CheckBuildingRemainingTimeAction.ts b/src/Action/CheckBuildingRemainingTimeAction.ts index d2decff..5035607 100644 --- a/src/Action/CheckBuildingRemainingTimeAction.ts +++ b/src/Action/CheckBuildingRemainingTimeAction.ts @@ -1,7 +1,7 @@ import ActionController from './ActionController'; import { Args } from '../Common'; import { Task } from '../Storage/TaskQueue'; -import { TryLaterError } from '../Errors'; +import { BuildingQueueFullError } from '../Errors'; export default class CheckBuildingRemainingTimeAction extends ActionController { static NAME = 'check_building_remaining_time'; @@ -11,7 +11,7 @@ export default class CheckBuildingRemainingTimeAction extends ActionController { if (timer.length === 1) { const remainingSeconds = Number(timer.attr('value')); if (remainingSeconds > 0) { - throw new TryLaterError( + throw new BuildingQueueFullError( remainingSeconds + 1, 'Building queue is full' ); diff --git a/src/Dashboard.ts b/src/Dashboard.ts index a12d259..99d79bc 100644 --- a/src/Dashboard.ts +++ b/src/Dashboard.ts @@ -1,5 +1,5 @@ import * as URLParse from 'url-parse'; -import { markPage, sleepShort, uniqId } from './utils'; +import { markPage, uniqId, waitForLoad } from './utils'; import Scheduler from './Scheduler'; import UpgradeBuildingTask from './Task/UpgradeBuildingTask'; import { Command } from './Common'; @@ -15,8 +15,7 @@ export default class Dashboard { } async run() { - await this.load(); - await sleepShort(); + await waitForLoad(); const p = new URLParse(window.location.href, true); this.log('PARSED LOCATION', p); @@ -77,10 +76,6 @@ export default class Dashboard { }); } - private async load() { - return new Promise(resolve => jQuery(resolve)); - } - private log(...args) { console.log('SCHEDULER:', ...args); } diff --git a/src/Errors.ts b/src/Errors.ts index 15b590f..832d9b4 100644 --- a/src/Errors.ts +++ b/src/Errors.ts @@ -10,3 +10,14 @@ export class TryLaterError extends Error { Object.setPrototypeOf(this, TryLaterError.prototype); } } + +export class BuildingQueueFullError extends Error { + readonly seconds: number; + readonly id: TaskId; + constructor(seconds: number, id: TaskId, msg: string = '') { + super(msg); + this.id = id; + this.seconds = seconds; + Object.setPrototypeOf(this, TryLaterError.prototype); + } +} diff --git a/src/Scheduler.ts b/src/Scheduler.ts index dac50de..f5e470c 100644 --- a/src/Scheduler.ts +++ b/src/Scheduler.ts @@ -1,7 +1,7 @@ import { markPage, sleepShort, timestamp } from './utils'; import UpgradeBuildingTask from './Task/UpgradeBuildingTask'; import UpgradeBuildingAction from './Action/UpgradeBuildingAction'; -import { TryLaterError } from './Errors'; +import { BuildingQueueFullError, TryLaterError } from './Errors'; import { TaskQueue, TaskList, Task, TaskId } from './Storage/TaskQueue'; import ActionQueue from './Storage/ActionQueue'; import { Args, Command } from './Common'; @@ -143,6 +143,14 @@ export default class Scheduler { this.actionQueue.clear(); this.taskQueue.postpone(task.id, timestamp() + e.seconds); } + if (e instanceof BuildingQueueFullError) { + console.warn('BUILDING QUEUE FULL, TRY ALL AFTER', e.seconds); + this.actionQueue.clear(); + this.taskQueue.modify( + t => t.cmd.name === UpgradeBuildingTask.NAME, + t => t.withTime(timestamp() + e.seconds) + ); + } } } diff --git a/src/Storage/TaskQueue.ts b/src/Storage/TaskQueue.ts index e8dd552..72411d5 100644 --- a/src/Storage/TaskQueue.ts +++ b/src/Storage/TaskQueue.ts @@ -49,6 +49,12 @@ export class TaskQueue { return readyItems[0]; } + modify(predicate: (t: Task) => boolean, modifier: (t: Task) => Task) { + const [matched, other] = this.split(predicate); + const modified = matched.map(modifier); + this.flushItems(modified.concat(other)); + } + complete(id: TaskId) { const [_, items] = this.shiftTask(id); this.flushItems(items); @@ -68,10 +74,21 @@ export class TaskQueue { } private shiftTask(id: TaskId): [Task | undefined, TaskList] { - const items = this.getItems(); - const task = items.find(t => t.id === id); - const tail = items.filter(t => t.id !== id); - return [task, tail]; + const [a, b] = this.split(t => t.id === id); + return [a.shift(), b]; + } + + private split(predicate: (t: Task) => boolean): [TaskList, TaskList] { + const matched: TaskList = []; + const other: TaskList = []; + this.getItems().forEach(t => { + if (predicate(t)) { + matched.push(t); + } else { + other.push(t); + } + }); + return [matched, other]; } private getItems(): TaskList { diff --git a/src/utils.ts b/src/utils.ts index f08d7e2..420d89a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -18,6 +18,10 @@ export async function sleepLong() { return await sleep(ms); } +export async function waitForLoad() { + return new Promise(resolve => jQuery(resolve)); +} + export function uniqId(): string { return 'id' + smallIdGenerator(); }