Add ability to postpone all building tasks when queue is full
This commit is contained in:
		| @@ -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' | ||||
|                 ); | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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(); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user