Fix insert build tasks, so order is matter
This commit is contained in:
parent
db16c54137
commit
57ccf14553
@ -1,13 +1,14 @@
|
||||
import { ActionController, registerAction } from './ActionController';
|
||||
import { Args } from '../Common';
|
||||
import { Task } from '../Storage/TaskQueue';
|
||||
import { BuildingQueueFullError } from '../Errors';
|
||||
import { BuildingQueueFullError, GrabError } from '../Errors';
|
||||
import { grabActiveVillageId, grabBuildingQueueInfo } from '../Page/VillageBlock';
|
||||
import { BuildingQueueInfo } from '../Game';
|
||||
|
||||
@registerAction
|
||||
export class CheckBuildingRemainingTimeAction extends ActionController {
|
||||
async run(args: Args, task: Task): Promise<any> {
|
||||
const info = grabBuildingQueueInfo();
|
||||
const info = this.grabBuildingQueueInfoOrDefault();
|
||||
if (info.seconds > 0) {
|
||||
throw new BuildingQueueFullError(
|
||||
task.id,
|
||||
@ -17,4 +18,15 @@ export class CheckBuildingRemainingTimeAction extends ActionController {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private grabBuildingQueueInfoOrDefault() {
|
||||
try {
|
||||
return grabBuildingQueueInfo();
|
||||
} catch (e) {
|
||||
if (e instanceof GrabError) {
|
||||
return new BuildingQueueInfo(0);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import { clickUpgradeButton } from '../Page/BuildingPage';
|
||||
import { grabResourceDeposits } from '../Page/SlotBlock';
|
||||
import { UpgradeBuildingTask } from '../Task/UpgradeBuildingTask';
|
||||
import { ResourceDeposit } from '../Game';
|
||||
import { aroundMinutes } from '../utils';
|
||||
|
||||
@registerAction
|
||||
export class UpgradeResourceToLevel extends ActionController {
|
||||
@ -35,19 +36,16 @@ export class UpgradeResourceToLevel extends ActionController {
|
||||
task.args.buildId === dep.buildId
|
||||
);
|
||||
|
||||
const available = deposits
|
||||
.sort((x, y) => x.level - y.level)
|
||||
.filter(dep => dep.ready)
|
||||
.filter(isDepositTaskNotInQueue);
|
||||
const notUpgraded = deposits.sort((x, y) => x.level - y.level).filter(isDepositTaskNotInQueue);
|
||||
|
||||
if (available.length === 0) {
|
||||
throw new TryLaterError(task.id, 10 * 60, 'No available deposits');
|
||||
if (notUpgraded.length === 0) {
|
||||
throw new TryLaterError(task.id, aroundMinutes(10), 'No available deposits');
|
||||
}
|
||||
|
||||
const targetDep = available[0];
|
||||
for (let dep of notUpgraded) {
|
||||
this.scheduler.scheduleTask(UpgradeBuildingTask.name, { villageId, buildId: dep.buildId });
|
||||
}
|
||||
|
||||
this.scheduler.scheduleTask(UpgradeBuildingTask.name, { villageId, buildId: targetDep.buildId });
|
||||
|
||||
throw new TryLaterError(task.id, 20 * 60, 'Sleep for next round');
|
||||
throw new TryLaterError(task.id, aroundMinutes(10), 'Sleep for next round');
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { ResourcesInterface } from './Game';
|
||||
|
||||
export interface Args {
|
||||
villageId?: number;
|
||||
buildId?: number;
|
||||
categoryId?: number;
|
||||
buildTypeId?: number;
|
||||
resources?: ResourcesInterface;
|
||||
[name: string]: any;
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,14 @@ export function numberToResourceType(typeAsNumber: number): ResourceType {
|
||||
|
||||
export type ResourceList = Array<{ num: number; type: ResourceType; value: number }>;
|
||||
|
||||
export class Resources {
|
||||
export interface ResourcesInterface {
|
||||
lumber: number;
|
||||
clay: number;
|
||||
iron: number;
|
||||
crop: number;
|
||||
}
|
||||
|
||||
export class Resources implements ResourcesInterface {
|
||||
readonly lumber: number;
|
||||
readonly clay: number;
|
||||
readonly iron: number;
|
||||
|
@ -4,7 +4,7 @@ import { Scheduler } from '../Scheduler';
|
||||
import { TrainTroopTask } from '../Task/TrainTroopTask';
|
||||
import { grabActiveVillageId } from './VillageBlock';
|
||||
import { ConsoleLogger, Logger } from '../Logger';
|
||||
import { createBuildButton, createUpgradeButton } from './BuildingPage';
|
||||
import { createBuildButton, createUpgradeButton, grabContractResources } from './BuildingPage';
|
||||
import { BuildBuildingTask } from '../Task/BuildBuildingTask';
|
||||
|
||||
const QUARTERS_ID = 19;
|
||||
@ -38,14 +38,16 @@ export class BuildPage {
|
||||
const buildId = this.buildId;
|
||||
const categoryId = this.categoryId;
|
||||
const villageId = grabActiveVillageId();
|
||||
this.scheduler.scheduleTask(BuildBuildingTask.name, { villageId, buildId, categoryId, buildTypeId });
|
||||
const resources = grabContractResources();
|
||||
this.scheduler.scheduleTask(BuildBuildingTask.name, { villageId, buildId, categoryId, buildTypeId, resources });
|
||||
notify(`Building ${buildId} scheduled`);
|
||||
}
|
||||
|
||||
private onScheduleUpgradeBuilding() {
|
||||
const buildId = this.buildId;
|
||||
const villageId = grabActiveVillageId();
|
||||
this.scheduler.scheduleTask(UpgradeBuildingTask.name, { villageId, buildId });
|
||||
const resources = grabContractResources();
|
||||
this.scheduler.scheduleTask(UpgradeBuildingTask.name, { villageId, buildId, resources });
|
||||
notify(`Upgrading ${buildId} scheduled`);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { GrabError } from '../Errors';
|
||||
import { getNumber, trimPrefix, uniqId } from '../utils';
|
||||
import { Resources } from '../Game';
|
||||
|
||||
export function clickBuildButton(typeId: number) {
|
||||
const section = jQuery(`#contract_building${typeId}`);
|
||||
@ -27,6 +28,11 @@ export function createBuildButton(onClickHandler: (buildTypeId: number) => void)
|
||||
});
|
||||
}
|
||||
|
||||
export function hasUpgradeButton(): boolean {
|
||||
const btn = jQuery('.upgradeButtonsContainer .section1 button.green.build');
|
||||
return btn.length === 1;
|
||||
}
|
||||
|
||||
export function clickUpgradeButton() {
|
||||
const btn = jQuery('.upgradeButtonsContainer .section1 button.green.build');
|
||||
if (btn.length !== 1) {
|
||||
@ -45,3 +51,17 @@ export function createUpgradeButton(onClickHandler: () => void) {
|
||||
onClickHandler();
|
||||
});
|
||||
}
|
||||
|
||||
export function grabContractResources(): Resources {
|
||||
const $els = jQuery('#contract .resource');
|
||||
if ($els.length === 0) {
|
||||
throw new GrabError('No resource contract element');
|
||||
}
|
||||
const grab = n =>
|
||||
getNumber(
|
||||
jQuery($els.get(n))
|
||||
.find('.value')
|
||||
.text()
|
||||
);
|
||||
return new Resources(grab(0), grab(1), grab(2), grab(3));
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ function grabVillageInfo($el): Village {
|
||||
export function grabResourcesPerformance(): Resources {
|
||||
const $el = jQuery('#production');
|
||||
if ($el.length !== 1) {
|
||||
throw new GrabError();
|
||||
throw new GrabError('No production element');
|
||||
}
|
||||
|
||||
const $nums = $el.find('td.num');
|
||||
@ -63,7 +63,7 @@ export function grabResourcesPerformance(): Resources {
|
||||
export function grabBuildingQueueInfo(): BuildingQueueInfo {
|
||||
const timer = jQuery('.buildDuration .timer');
|
||||
if (timer.length !== 1) {
|
||||
throw new GrabError();
|
||||
throw new GrabError('No building queue timer element');
|
||||
}
|
||||
|
||||
const remainingSeconds = getNumber(timer.attr('value'));
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { timestamp } from './utils';
|
||||
import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
|
||||
import { TaskId, TaskList, TaskQueue } from './Storage/TaskQueue';
|
||||
import { Task, TaskId, TaskList, TaskQueue } from './Storage/TaskQueue';
|
||||
import { Args, Command } from './Common';
|
||||
import { SendOnAdventureTask } from './Task/SendOnAdventureTask';
|
||||
import { BalanceHeroResourcesTask } from './Task/BalanceHeroResourcesTask';
|
||||
@ -50,7 +50,17 @@ export class Scheduler {
|
||||
|
||||
scheduleTask(name: string, args: Args): void {
|
||||
this.logger.log('PUSH TASK', name, args);
|
||||
this.taskQueue.push(name, args, timestamp());
|
||||
const villageId = args.villageId;
|
||||
if (isBuildingTask(name)) {
|
||||
this.taskQueue.insertAfterLast(
|
||||
t => isBuildingTask(t.name) && sameVillage(villageId, t.args),
|
||||
name,
|
||||
args,
|
||||
timestamp()
|
||||
);
|
||||
} else {
|
||||
this.taskQueue.push(name, args, timestamp());
|
||||
}
|
||||
}
|
||||
|
||||
completeTask(id: TaskId) {
|
||||
@ -69,11 +79,7 @@ export class Scheduler {
|
||||
|
||||
postponeBuildingsInVillage(villageId: number, seconds: number) {
|
||||
this.taskQueue.modify(
|
||||
t => t.name === BuildBuildingTask.name && t.args.villageId === villageId,
|
||||
t => t.withTime(timestamp() + seconds)
|
||||
);
|
||||
this.taskQueue.modify(
|
||||
t => t.name === UpgradeBuildingTask.name && t.args.villageId === villageId,
|
||||
t => isBuildingTask(t.name) && sameVillage(villageId, t.args),
|
||||
t => t.withTime(timestamp() + seconds)
|
||||
);
|
||||
}
|
||||
@ -86,3 +92,11 @@ export class Scheduler {
|
||||
this.actionQueue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
function isBuildingTask(taskName: string) {
|
||||
return taskName === BuildBuildingTask.name || taskName === UpgradeBuildingTask.name;
|
||||
}
|
||||
|
||||
function sameVillage(villageId: number | undefined, args: Args) {
|
||||
return villageId !== undefined && args.villageId === villageId;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ import { StateGrabber } from './StateGrabber';
|
||||
import { grabActiveVillageId, grabBuildingQueueInfo, grabResourcesPerformance } from '../Page/VillageBlock';
|
||||
import { VillageState } from './VillageState';
|
||||
import { parseLocation } from '../utils';
|
||||
import { GrabError } from '../Errors';
|
||||
import { BuildingQueueInfo } from '../Game';
|
||||
|
||||
export class VillageOverviewPageGrabber extends StateGrabber {
|
||||
grab(): void {
|
||||
@ -13,6 +15,17 @@ export class VillageOverviewPageGrabber extends StateGrabber {
|
||||
const villageId = grabActiveVillageId();
|
||||
const state = new VillageState(villageId);
|
||||
state.storeResourcesPerformance(grabResourcesPerformance());
|
||||
state.storeBuildingQueueInfo(grabBuildingQueueInfo());
|
||||
state.storeBuildingQueueInfo(this.grabBuildingQueueInfoOrDefault());
|
||||
}
|
||||
|
||||
private grabBuildingQueueInfoOrDefault() {
|
||||
try {
|
||||
return grabBuildingQueueInfo();
|
||||
} catch (e) {
|
||||
if (e instanceof GrabError) {
|
||||
return new BuildingQueueInfo(0);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,15 @@ export class TaskQueue {
|
||||
return task;
|
||||
}
|
||||
|
||||
insertAfterLast(predicate: (t: Task) => boolean, name: string, args: Args, ts: number): Task {
|
||||
const id = uniqTaskId();
|
||||
const task = new Task(id, ts, name, args);
|
||||
this.logger.log('INSERT AFTER TASK', id, ts, name, args);
|
||||
const items = insertTaskAfter(task, this.getItems(), predicate);
|
||||
this.flushItems(items);
|
||||
return task;
|
||||
}
|
||||
|
||||
get(ts: number): Task | undefined {
|
||||
const readyItems = this.getItems().filter(t => t.ts <= ts);
|
||||
if (readyItems.length === 0) {
|
||||
@ -133,3 +142,27 @@ export class TaskQueue {
|
||||
this.storage.set(QUEUE_NAME, normalized);
|
||||
}
|
||||
}
|
||||
|
||||
function insertTaskAfter(task: Task, tasks: TaskList, predicate: (t: Task) => boolean): TaskList {
|
||||
const queuedTaskIndex = findLastIndex(tasks, predicate);
|
||||
if (queuedTaskIndex === undefined) {
|
||||
tasks.push(task);
|
||||
return tasks;
|
||||
}
|
||||
const queuedTask = tasks[queuedTaskIndex];
|
||||
let insertedTask = task.withTime(Math.max(task.ts, queuedTask.ts + 1));
|
||||
tasks.splice(queuedTaskIndex, 0, insertedTask);
|
||||
return tasks;
|
||||
}
|
||||
|
||||
function findLastIndex(tasks: TaskList, predicate: (t: Task) => boolean): number | undefined {
|
||||
const count = tasks.length;
|
||||
const indexInReversed = tasks
|
||||
.slice()
|
||||
.reverse()
|
||||
.findIndex(predicate);
|
||||
if (indexInReversed < 0) {
|
||||
return undefined;
|
||||
}
|
||||
return count - 1 - indexInReversed;
|
||||
}
|
||||
|
@ -22,6 +22,12 @@ export async function sleepLong() {
|
||||
return await sleep(ms);
|
||||
}
|
||||
|
||||
export function aroundMinutes(minutes: number) {
|
||||
const seconds = minutes * 60;
|
||||
const delta = Math.floor(seconds * 0.9);
|
||||
return seconds - delta + Math.floor(Math.random() * 2 * delta);
|
||||
}
|
||||
|
||||
export async function waitForLoad() {
|
||||
return new Promise(resolve => jQuery(resolve));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user