diff --git a/src/Action/ActionController.ts b/src/Action/ActionController.ts
index 7c3026c..bcefabe 100644
--- a/src/Action/ActionController.ts
+++ b/src/Action/ActionController.ts
@@ -5,7 +5,7 @@ import { aroundMinutes } from '../utils';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
import { VillageStorage } from '../Storage/VillageStorage';
-import { VillageStateRepository } from '../VillageState';
+import { VillageFactory } from '../VillageFactory';
const actionMap: { [name: string]: Function | undefined } = {};
@@ -16,22 +16,22 @@ export function registerAction(constructor: Function) {
export function createActionHandler(
name: string,
scheduler: Scheduler,
- villageStateRepository: VillageStateRepository
+ villageFactory: VillageFactory
): ActionController | undefined {
const storedFunction = actionMap[name];
if (storedFunction === undefined) {
return undefined;
}
const constructor = (storedFunction as unknown) as typeof ActionController;
- return new constructor(scheduler, villageStateRepository);
+ return new constructor(scheduler, villageFactory);
}
export class ActionController {
- protected scheduler: Scheduler;
- protected villageStateRepository: VillageStateRepository;
- constructor(scheduler: Scheduler, villageStateRepository: VillageStateRepository) {
+ protected readonly scheduler: Scheduler;
+ protected readonly villageFactory: VillageFactory;
+ constructor(scheduler: Scheduler, villageFactory: VillageFactory) {
this.scheduler = scheduler;
- this.villageStateRepository = villageStateRepository;
+ this.villageFactory = villageFactory;
}
async run(args: Args, task: Task) {}
diff --git a/src/Action/BalanceHeroResourcesAction.ts b/src/Action/BalanceHeroResourcesAction.ts
index 7a19520..7682312 100644
--- a/src/Action/BalanceHeroResourcesAction.ts
+++ b/src/Action/BalanceHeroResourcesAction.ts
@@ -18,7 +18,7 @@ export class BalanceHeroResourcesAction extends ActionController {
return;
}
- const thisVillageState = this.villageStateRepository.getVillageState(thisVillageId);
+ const thisVillageState = this.villageFactory.createState(thisVillageId);
const requirements = [
thisVillageState.required.balance,
diff --git a/src/Action/ClickButtonAction.ts b/src/Action/ClickButtonAction.ts
index 494711c..ef616e0 100644
--- a/src/Action/ClickButtonAction.ts
+++ b/src/Action/ClickButtonAction.ts
@@ -1,5 +1,5 @@
import { ActionController, registerAction } from './ActionController';
-import { AbortTaskError, taskError } from '../Errors';
+import { taskError } from '../Errors';
import { Args } from '../Queue/Args';
import { Task } from '../Queue/TaskProvider';
diff --git a/src/Action/SendResourcesAction.ts b/src/Action/SendResourcesAction.ts
index e54dabd..e782de5 100644
--- a/src/Action/SendResourcesAction.ts
+++ b/src/Action/SendResourcesAction.ts
@@ -18,8 +18,8 @@ export class SendResourcesAction extends ActionController {
const coordinates = Coordinates.fromObject(args.coordinates || taskError('No coordinates'));
- const senderVillage = this.villageStateRepository.getVillageState(senderVillageId);
- const recipientVillage = this.villageStateRepository.getVillageState(targetVillageId);
+ const senderVillage = this.villageFactory.createState(senderVillageId);
+ const recipientVillage = this.villageFactory.createState(targetVillageId);
const readyToTransfer = this.getResourcesForTransfer(senderVillage, recipientVillage);
diff --git a/src/Action/UpgradeResourceToLevel.ts b/src/Action/UpgradeResourceToLevel.ts
index 4a1a6d5..09aa7e0 100644
--- a/src/Action/UpgradeResourceToLevel.ts
+++ b/src/Action/UpgradeResourceToLevel.ts
@@ -1,5 +1,5 @@
import { ActionController, registerAction } from './ActionController';
-import { AbortTaskError, ActionError, taskError, TryLaterError } from '../Errors';
+import { ActionError, taskError, TryLaterError } from '../Errors';
import { grabResourceDeposits } from '../Page/SlotBlock';
import { UpgradeBuildingTask } from '../Task/UpgradeBuildingTask';
import { ResourceDeposit } from '../Game';
diff --git a/src/Container.ts b/src/Container.ts
index 06de00e..7f22ee6 100644
--- a/src/Container.ts
+++ b/src/Container.ts
@@ -8,9 +8,8 @@ import { DataStorageTaskProvider } from './Queue/DataStorageTaskProvider';
import { Statistics } from './Statistics';
import { StatisticsStorage } from './Storage/StatisticsStorage';
import { VillageRepository } from './VillageRepository';
-import { VillageStateRepository } from './VillageState';
import { LogStorage } from './Storage/LogStorage';
-import { VillageControllerFactory } from './VillageControllerFactory';
+import { VillageFactory } from './VillageFactory';
import { GrabberManager } from './Grabber/GrabberManager';
export class Container {
@@ -42,15 +41,15 @@ export class Container {
return this._statistics;
}
- private _villageControllerFactory: VillageControllerFactory | undefined;
+ private _villageFactory: VillageFactory | undefined;
- get villageControllerFactory(): VillageControllerFactory {
- this._villageControllerFactory =
- this._villageControllerFactory ||
+ get villageFactory(): VillageFactory {
+ this._villageFactory =
+ this._villageFactory ||
(() => {
- return new VillageControllerFactory(this.villageRepository);
+ return new VillageFactory(this.villageRepository);
})();
- return this._villageControllerFactory;
+ return this._villageFactory;
}
private _scheduler: Scheduler | undefined;
@@ -68,31 +67,20 @@ export class Container {
taskQueue,
actionQueue,
this.villageRepository,
- this.villageControllerFactory,
+ this.villageFactory,
new ConsoleLogger(Scheduler.name)
);
})();
return this._scheduler;
}
- private _villageStateRepository: VillageStateRepository | undefined;
-
- get villageStateRepository(): VillageStateRepository {
- this._villageStateRepository =
- this._villageStateRepository ||
- (() => {
- return new VillageStateRepository(this.villageRepository, this.villageControllerFactory);
- })();
- return this._villageStateRepository;
- }
-
private _grabberManager: GrabberManager | undefined;
get grabberManager(): GrabberManager {
this._grabberManager =
this._grabberManager ||
(() => {
- return new GrabberManager(this.villageControllerFactory);
+ return new GrabberManager(this.villageFactory);
})();
return this._grabberManager;
}
@@ -110,8 +98,7 @@ export class Container {
return new Executor(
this.version,
this.scheduler,
- this.villageStateRepository,
- this.villageControllerFactory,
+ this.villageFactory,
this.grabberManager,
this.statistics,
logger
@@ -126,12 +113,7 @@ export class Container {
this._controlPanel =
this._controlPanel ||
(() => {
- return new ControlPanel(
- this.version,
- this.scheduler,
- this.villageStateRepository,
- this.villageControllerFactory
- );
+ return new ControlPanel(this.version, this.scheduler, this.villageFactory);
})();
return this._controlPanel;
}
diff --git a/src/ControlPanel.ts b/src/ControlPanel.ts
index 93347bb..7efdedd 100644
--- a/src/ControlPanel.ts
+++ b/src/ControlPanel.ts
@@ -18,11 +18,11 @@ import { ConsoleLogger, Logger } from './Logger';
import { DataStorage } from './DataStorage';
import { getBuildingPageAttributes, isBuildingPage } from './Page/PageDetectors';
import { ExecutionStorage } from './Storage/ExecutionStorage';
-import { VillageState, VillageStateRepository } from './VillageState';
+import { VillageState } from './VillageState';
import { Task } from './Queue/TaskProvider';
import { Action } from './Queue/ActionQueue';
import { createStore } from './DashboardView/Store';
-import { VillageControllerFactory } from './VillageControllerFactory';
+import { VillageFactory } from './VillageFactory';
Vue.use(Vuex);
@@ -52,20 +52,13 @@ interface GameState {
export class ControlPanel {
private readonly version: string;
private readonly scheduler: Scheduler;
- private readonly villageStateRepository: VillageStateRepository;
private readonly logger: Logger;
- private villageControllerFactory: VillageControllerFactory;
+ private readonly villageFactory: VillageFactory;
- constructor(
- version: string,
- scheduler: Scheduler,
- villageStateRepository: VillageStateRepository,
- villageControllerFactory: VillageControllerFactory
- ) {
+ constructor(version: string, scheduler: Scheduler, villageFactory: VillageFactory) {
this.version = version;
this.scheduler = scheduler;
- this.villageStateRepository = villageStateRepository;
- this.villageControllerFactory = villageControllerFactory;
+ this.villageFactory = villageFactory;
this.logger = new ConsoleLogger(this.constructor.name);
}
@@ -78,7 +71,7 @@ export class ControlPanel {
const villageId = grabActiveVillageId();
const scheduler = this.scheduler;
- const villageStateRepository = this.villageStateRepository;
+ const villageFactory = this.villageFactory;
const executionState = new ExecutionStorage();
@@ -106,7 +99,7 @@ export class ControlPanel {
},
refreshVillages() {
- this.villageStates = villageStateRepository.getAllVillageStates();
+ this.villageStates = villageFactory.getAllVillageStates();
for (let state of this.villageStates) {
if (state.village.active) {
this.activeVillageState = state;
@@ -136,8 +129,8 @@ export class ControlPanel {
DataStorage.onChange(() => state.refresh());
const getBuildingsInQueue = () =>
- this.villageControllerFactory
- .create(villageId)
+ this.villageFactory
+ .createTaskCollection(villageId)
.getTasks()
.filter(t => t.name === UpgradeBuildingTask.name)
.map(t => t.args.buildId || 0);
@@ -163,21 +156,21 @@ export class ControlPanel {
const buildPage = new BuildingPageController(
this.scheduler,
getBuildingPageAttributes(),
- this.villageControllerFactory.create(villageId)
+ this.villageFactory.createController(villageId)
);
buildPage.run();
}
- this.createControlPanel(state, villageStateRepository);
+ this.createControlPanel(state, villageFactory);
}
- private createControlPanel(gameState: GameState, villageStateRepository: VillageStateRepository) {
+ private createControlPanel(gameState: GameState, villageFactory: VillageFactory) {
const appId = `app-${uniqId()}`;
jQuery('body').prepend(`
`);
new Vue({
el: `#${appId}`,
data: gameState,
- store: createStore(villageStateRepository),
+ store: createStore(villageFactory),
render: h => h(DashboardApp),
});
}
diff --git a/src/DashboardView/Store.ts b/src/DashboardView/Store.ts
index 932b774..cccf914 100644
--- a/src/DashboardView/Store.ts
+++ b/src/DashboardView/Store.ts
@@ -1,9 +1,9 @@
import Vuex from 'vuex';
import { LogStorage } from '../Storage/LogStorage';
-import { VillageStateRepository } from '../VillageState';
import { VillageSettings, VillageSettingsDefaults } from '../Core/Village';
import { getNumber, notify } from '../utils';
import { VillageStorage } from '../Storage/VillageStorage';
+import { VillageFactory } from '../VillageFactory';
export enum Mutations {
showLogs = 'showLogs',
@@ -22,7 +22,7 @@ export enum Actions {
SaveVillageSettings = 'save_village_settings',
}
-export function createStore(villageStateRepository: VillageStateRepository) {
+export function createStore(villageFactory: VillageFactory) {
const store = new Vuex.Store({
state: {
views: {
@@ -74,7 +74,7 @@ export function createStore(villageStateRepository: VillageStateRepository) {
},
actions: {
[Actions.OpenVillageEditor]({ commit }, { villageId }) {
- const state = villageStateRepository.getVillageState(villageId);
+ const state = villageFactory.createState(villageId);
const settings = state.settings;
commit(Mutations.SetVillageSettings, {
villageId: state.id,
diff --git a/src/Executor.ts b/src/Executor.ts
index 923cd52..a4fbf5b 100644
--- a/src/Executor.ts
+++ b/src/Executor.ts
@@ -10,8 +10,8 @@ import { ExecutionStorage } from './Storage/ExecutionStorage';
import { Action } from './Queue/ActionQueue';
import { Task } from './Queue/TaskProvider';
import { createTaskHandler } from './Task/TaskMap';
-import { VillageStateRepository } from './VillageState';
-import { VillageControllerFactory } from './VillageControllerFactory';
+import { VillageStateFactory } from './VillageState';
+import { VillageFactory } from './VillageFactory';
export interface ExecutionSettings {
pauseTs: number;
@@ -20,8 +20,7 @@ export interface ExecutionSettings {
export class Executor {
private readonly version: string;
private readonly scheduler: Scheduler;
- private readonly villageStateRepository: VillageStateRepository;
- private villageControllerFactory: VillageControllerFactory;
+ private villageFactory: VillageFactory;
private grabberManager: GrabberManager;
private statistics: Statistics;
private executionState: ExecutionStorage;
@@ -30,16 +29,14 @@ export class Executor {
constructor(
version: string,
scheduler: Scheduler,
- villageStateRepository: VillageStateRepository,
- villageControllerFactory: VillageControllerFactory,
+ villageFactory: VillageFactory,
grabberManager: GrabberManager,
statistics: Statistics,
logger: Logger
) {
this.version = version;
this.scheduler = scheduler;
- this.villageStateRepository = villageStateRepository;
- this.villageControllerFactory = villageControllerFactory;
+ this.villageFactory = villageFactory;
this.grabberManager = grabberManager;
this.statistics = statistics;
this.executionState = new ExecutionStorage();
@@ -109,7 +106,7 @@ export class Executor {
}
private async processActionCommand(action: Action, task: Task) {
- const actionHandler = createActionHandler(action.name, this.scheduler, this.villageStateRepository);
+ const actionHandler = createActionHandler(action.name, this.scheduler, this.villageFactory);
this.logger.info('Process action', action.name, actionHandler);
if (actionHandler) {
this.statistics.incrementAction(timestamp());
diff --git a/src/Grabber/BuildingContractGrabber.ts b/src/Grabber/BuildingContractGrabber.ts
index 8228c52..a24b91b 100644
--- a/src/Grabber/BuildingContractGrabber.ts
+++ b/src/Grabber/BuildingContractGrabber.ts
@@ -20,7 +20,7 @@ export class BuildingContractGrabber extends Grabber {
const contract = grabContractResources();
- this.controller.updateResources(contract, {
+ this.taskCollection.updateResources(contract, {
type: ContractType.UpgradeBuilding,
buildId: building.buildId,
});
diff --git a/src/Grabber/ForgePageGrabber.ts b/src/Grabber/ForgePageGrabber.ts
index 131db7c..c5836a4 100644
--- a/src/Grabber/ForgePageGrabber.ts
+++ b/src/Grabber/ForgePageGrabber.ts
@@ -20,7 +20,7 @@ export class ForgePageGrabber extends Grabber {
const contracts = grabImprovementContracts();
for (let { resources, unitId } of contracts) {
- this.controller.updateResources(resources, {
+ this.taskCollection.updateResources(resources, {
type: ContractType.ImproveTrooper,
buildId,
unitId,
@@ -29,8 +29,7 @@ export class ForgePageGrabber extends Grabber {
}
private grabTimer(): void {
- const storage = this.controller.getStorage();
const seconds = grabRemainingSeconds();
- storage.storeQueueTaskEnding(ProductionQueue.UpgradeUnit, seconds ? seconds + timestamp() : 0);
+ this.storage.storeQueueTaskEnding(ProductionQueue.UpgradeUnit, seconds ? seconds + timestamp() : 0);
}
}
diff --git a/src/Grabber/Grabber.ts b/src/Grabber/Grabber.ts
index db0adc1..8919e93 100644
--- a/src/Grabber/Grabber.ts
+++ b/src/Grabber/Grabber.ts
@@ -1,10 +1,13 @@
-import { VillageController } from '../VillageController';
+import { VillageTaskCollection } from '../VillageTaskCollection';
+import { VillageStorage } from '../Storage/VillageStorage';
export abstract class Grabber {
- protected controller: VillageController;
+ protected taskCollection: VillageTaskCollection;
+ protected storage: VillageStorage;
- constructor(controller: VillageController) {
- this.controller = controller;
+ constructor(taskCollection: VillageTaskCollection, storage: VillageStorage) {
+ this.taskCollection = taskCollection;
+ this.storage = storage;
}
abstract grab(): void;
diff --git a/src/Grabber/GrabberManager.ts b/src/Grabber/GrabberManager.ts
index 0b9632d..ac272ff 100644
--- a/src/Grabber/GrabberManager.ts
+++ b/src/Grabber/GrabberManager.ts
@@ -6,12 +6,12 @@ import { MarketPageGrabber } from './MarketPageGrabber';
import { BuildingContractGrabber } from './BuildingContractGrabber';
import { ForgePageGrabber } from './ForgePageGrabber';
import { GuildHallPageGrabber } from './GuildHallPageGrabber';
-import { VillageControllerFactory } from '../VillageControllerFactory';
+import { VillageFactory } from '../VillageFactory';
export class GrabberManager {
- private factory: VillageControllerFactory;
+ private factory: VillageFactory;
- constructor(factory: VillageControllerFactory) {
+ constructor(factory: VillageFactory) {
this.factory = factory;
}
@@ -23,15 +23,16 @@ export class GrabberManager {
}
private createGrabbers(): Array {
- const controller = this.factory.getActive();
+ const storage = this.factory.createStorageForActiveVillage();
+ const taskCollection = this.factory.createTaskCollectionForActiveVillage();
const grabbers: Array = [];
- grabbers.push(new VillageResourceGrabber(controller));
- grabbers.push(new VillageOverviewPageGrabber(controller));
- grabbers.push(new HeroPageGrabber(controller));
- grabbers.push(new MarketPageGrabber(controller));
- grabbers.push(new BuildingContractGrabber(controller));
- grabbers.push(new ForgePageGrabber(controller));
- grabbers.push(new GuildHallPageGrabber(controller));
+ grabbers.push(new VillageResourceGrabber(taskCollection, storage));
+ grabbers.push(new VillageOverviewPageGrabber(taskCollection, storage));
+ grabbers.push(new HeroPageGrabber(taskCollection, storage));
+ grabbers.push(new MarketPageGrabber(taskCollection, storage));
+ grabbers.push(new BuildingContractGrabber(taskCollection, storage));
+ grabbers.push(new ForgePageGrabber(taskCollection, storage));
+ grabbers.push(new GuildHallPageGrabber(taskCollection, storage));
return grabbers;
}
}
diff --git a/src/Grabber/GuildHallPageGrabber.ts b/src/Grabber/GuildHallPageGrabber.ts
index e11fa05..60663d8 100644
--- a/src/Grabber/GuildHallPageGrabber.ts
+++ b/src/Grabber/GuildHallPageGrabber.ts
@@ -11,7 +11,6 @@ export class GuildHallPageGrabber extends Grabber {
}
const seconds = grabRemainingSeconds();
- const storage = this.controller.getStorage();
- storage.storeQueueTaskEnding(ProductionQueue.Celebration, seconds ? seconds + timestamp() : 0);
+ this.storage.storeQueueTaskEnding(ProductionQueue.Celebration, seconds ? seconds + timestamp() : 0);
}
}
diff --git a/src/Grabber/MarketPageGrabber.ts b/src/Grabber/MarketPageGrabber.ts
index 973cab5..7d000f9 100644
--- a/src/Grabber/MarketPageGrabber.ts
+++ b/src/Grabber/MarketPageGrabber.ts
@@ -8,7 +8,6 @@ export class MarketPageGrabber extends Grabber {
return;
}
- const storage = this.controller.getStorage();
- storage.storeIncomingMerchants(grabIncomingMerchants());
+ this.storage.storeIncomingMerchants(grabIncomingMerchants());
}
}
diff --git a/src/Grabber/VillageOverviewPageGrabber.ts b/src/Grabber/VillageOverviewPageGrabber.ts
index d9d18ed..ee1ebb4 100644
--- a/src/Grabber/VillageOverviewPageGrabber.ts
+++ b/src/Grabber/VillageOverviewPageGrabber.ts
@@ -12,13 +12,12 @@ export class VillageOverviewPageGrabber extends Grabber {
return;
}
- const storage = this.controller.getStorage();
- storage.storeResourcesPerformance(grabResourcesPerformance());
- storage.storeBuildingQueueInfo(this.grabBuildingQueueInfoOrDefault());
+ this.storage.storeResourcesPerformance(grabResourcesPerformance());
+ this.storage.storeBuildingQueueInfo(this.grabBuildingQueueInfoOrDefault());
const buildingQueueInfo = this.grabBuildingQueueInfoOrDefault();
const buildingEndTime = buildingQueueInfo.seconds ? buildingQueueInfo.seconds + timestamp() : 0;
- storage.storeQueueTaskEnding(ProductionQueue.Building, buildingEndTime);
+ this.storage.storeQueueTaskEnding(ProductionQueue.Building, buildingEndTime);
}
private grabBuildingQueueInfoOrDefault() {
diff --git a/src/Grabber/VillageResourceGrabber.ts b/src/Grabber/VillageResourceGrabber.ts
index 5fa6f81..7f88ead 100644
--- a/src/Grabber/VillageResourceGrabber.ts
+++ b/src/Grabber/VillageResourceGrabber.ts
@@ -3,8 +3,7 @@ import { grabVillageResources, grabVillageResourceStorage } from '../Page/Resour
export class VillageResourceGrabber extends Grabber {
grab(): void {
- const storage = this.controller.getStorage();
- storage.storeResources(grabVillageResources());
- storage.storeResourceStorage(grabVillageResourceStorage());
+ this.storage.storeResources(grabVillageResources());
+ this.storage.storeResourceStorage(grabVillageResourceStorage());
}
}
diff --git a/src/Scheduler.ts b/src/Scheduler.ts
index efb977b..0b36091 100644
--- a/src/Scheduler.ts
+++ b/src/Scheduler.ts
@@ -12,8 +12,9 @@ import { ImmutableTaskList, Task, TaskId, uniqTaskId, withTime } from './Queue/T
import { MARKET_ID } from './Core/Buildings';
import { VillageRepositoryInterface } from './VillageRepository';
import { isProductionTask } from './Core/ProductionQueue';
-import { VillageControllerFactory } from './VillageControllerFactory';
+import { VillageFactory } from './VillageFactory';
import { RunVillageProductionTask } from './Task/RunVillageProductionTask';
+import { VillageNotFound } from './Errors';
export interface NextExecution {
task?: Task;
@@ -24,14 +25,14 @@ export class Scheduler {
private taskQueue: TaskQueue;
private actionQueue: ActionQueue;
private villageRepository: VillageRepositoryInterface;
- private villageControllerFactory: VillageControllerFactory;
+ private villageControllerFactory: VillageFactory;
private logger: Logger;
constructor(
taskQueue: TaskQueue,
actionQueue: ActionQueue,
villageRepository: VillageRepositoryInterface,
- villageControllerFactory: VillageControllerFactory,
+ villageControllerFactory: VillageFactory,
logger: Logger
) {
this.taskQueue = taskQueue;
@@ -96,13 +97,13 @@ export class Scheduler {
private replaceTask(task: Task): Task | undefined {
if (task.name === RunVillageProductionTask.name && task.args.villageId) {
const villageId = task.args.villageId;
- const controller = this.villageControllerFactory.create(villageId);
+ const controller = this.villageControllerFactory.createController(villageId);
const villageTask = controller.getReadyProductionTask();
if (villageTask) {
this.removeTask(task.id);
const newTask = new Task(villageTask.id, 0, villageTask.name, {
...villageTask.args,
- villageId: controller.villageId,
+ villageId: controller.getVillageId(),
});
this.taskQueue.add(newTask);
return newTask;
@@ -113,7 +114,7 @@ export class Scheduler {
scheduleTask(name: string, args: Args, ts?: number | undefined): void {
if (isProductionTask(name) && args.villageId) {
- const controller = this.villageControllerFactory.create(args.villageId);
+ const controller = this.villageControllerFactory.createController(args.villageId);
controller.addTask(name, args);
} else {
this.logger.info('Schedule task', name, args, ts);
@@ -143,7 +144,7 @@ export class Scheduler {
const task = this.taskQueue.findById(taskId);
const villageId = task ? task.args.villageId : undefined;
if (villageId) {
- const controller = this.villageControllerFactory.create(villageId);
+ const controller = this.villageControllerFactory.createController(villageId);
controller.removeTask(taskId);
}
this.removeTask(taskId);
@@ -156,7 +157,7 @@ export class Scheduler {
}
if (isProductionTask(task.name) && task.args.villageId) {
- const controller = this.villageControllerFactory.create(task.args.villageId);
+ const controller = this.villageControllerFactory.createController(task.args.villageId);
controller.postponeTask(taskId, seconds);
this.removeTask(taskId);
} else {
@@ -186,7 +187,7 @@ export class Scheduler {
this.dropResourceTransferTasks(fromVillageId, toVillageId);
const village = this.villageRepository.all().find(v => v.id === toVillageId);
if (!village) {
- throw new Error('No village');
+ throw new VillageNotFound(`Village ${toVillageId} not found`);
}
this.scheduleTask(SendResourcesTask.name, {
villageId: fromVillageId,
diff --git a/src/Storage/LogStorage.ts b/src/Storage/LogStorage.ts
index 95fc124..881b76d 100644
--- a/src/Storage/LogStorage.ts
+++ b/src/Storage/LogStorage.ts
@@ -1,5 +1,4 @@
import { DataStorage } from '../DataStorage';
-import { ActionStatistics, StatisticsStorageInterface } from '../Statistics';
import { LogStorageInterface, StorageLogRecord } from '../Logger';
const NAMESPACE = 'logs.v1';
diff --git a/src/Storage/VillageStorage.ts b/src/Storage/VillageStorage.ts
index 0a9e4ed..3c7fd89 100644
--- a/src/Storage/VillageStorage.ts
+++ b/src/Storage/VillageStorage.ts
@@ -112,41 +112,7 @@ export class VillageStorage {
});
}
- addTask(task: Task): void {
- const tasks = this.getTasks();
- tasks.push(task);
- this.storeTaskList(tasks);
- }
-
- modifyTasks(predicate: (t: Task) => boolean, modifier: (t: Task) => Task): number {
- const [matched, other] = this.split(predicate);
- const modified = matched.map(modifier);
- const modifiedCount = modified.length;
- this.storeTaskList(modified.concat(other));
- return modifiedCount;
- }
-
- removeTasks(predicate: (t: Task) => boolean): number {
- const [_, other] = this.split(predicate);
- const result = other.length;
- this.storeTaskList(other);
- return result;
- }
-
- private split(predicate: (t: Task) => boolean): [TaskList, TaskList] {
- const matched: TaskList = [];
- const other: TaskList = [];
- this.getTasks().forEach(t => {
- if (predicate(t)) {
- matched.push(t);
- } else {
- other.push(t);
- }
- });
- return [matched, other];
- }
-
- private storeTaskList(tasks: Array): void {
+ storeTaskList(tasks: Array): void {
this.storage.set(TASK_LIST_KEY, tasks);
}
}
diff --git a/src/VillageController.ts b/src/VillageController.ts
index feab091..3b45118 100644
--- a/src/VillageController.ts
+++ b/src/VillageController.ts
@@ -1,93 +1,36 @@
-import { Task, TaskId, uniqTaskId, withResources, withTime } from './Queue/TaskProvider';
-import { VillageStorage } from './Storage/VillageStorage';
+import { VillageTaskCollection } from './VillageTaskCollection';
+import { Task, TaskId } from './Queue/TaskProvider';
import { Args } from './Queue/Args';
-import { isProductionTask, ProductionQueue, ProductionQueueTypes } from './Core/ProductionQueue';
-import { Resources } from './Core/Resources';
-import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
-import { ForgeImprovementTask } from './Task/ForgeImprovementTask';
-import { ContractType, ContractAttributes } from './Core/Contract';
-import { timestamp } from './utils';
-import { getProductionQueue } from './Task/TaskMap';
+import { VillageState } from './VillageState';
export class VillageController {
- private readonly _villageId: number;
- private readonly _storage: VillageStorage;
+ private readonly villageId: number;
+ private taskCollection: VillageTaskCollection;
+ private readonly state: VillageState;
- constructor(villageId: number, storage: VillageStorage) {
- this._villageId = villageId;
- this._storage = storage;
+ constructor(villageId: number, taskCollection: VillageTaskCollection, state: VillageState) {
+ this.villageId = villageId;
+ this.taskCollection = taskCollection;
+ this.state = state;
}
- get villageId() {
- return this._villageId;
- }
-
- getStorage(): VillageStorage {
- return this._storage;
- }
-
- addTask(name: string, args: Args) {
- if (!isProductionTask(name)) {
- throw new Error(`Task "${name}" is not production task`);
- }
- if (args.villageId !== this._villageId) {
- throw new Error(`Task village id (${args.villageId}) not equal controller village id (${this._villageId}`);
- }
- const task = new Task(uniqTaskId(), 0, name, { villageId: this._villageId, ...args });
- this._storage.addTask(task);
- }
-
- getTasks(): Array {
- return this._storage.getTasks();
- }
-
- removeTask(taskId: TaskId) {
- this._storage.removeTasks(t => t.id === taskId);
- }
-
- getTasksInProductionQueue(queue: ProductionQueue): Array {
- return this._storage.getTasks().filter(task => getProductionQueue(task.name) === queue);
+ getVillageId() {
+ return this.villageId;
}
getReadyProductionTask(): Task | undefined {
- let sortedTasks: Array = [];
- for (let queue of ProductionQueueTypes) {
- const tasks = this.getTasksInProductionQueue(queue);
- sortedTasks = sortedTasks.concat(tasks);
- }
- return sortedTasks.shift();
+ return this.taskCollection.getReadyProductionTask();
+ }
+
+ addTask(name: string, args: Args) {
+ this.taskCollection.addTask(name, args);
+ }
+
+ removeTask(taskId: TaskId) {
+ this.taskCollection.removeTask(taskId);
}
postponeTask(taskId: TaskId, seconds: number) {
- const modifyTime = withTime(timestamp() + seconds);
- this._storage.modifyTasks(task => task.id === taskId, modifyTime);
- }
-
- updateResources(resources: Resources, attr: ContractAttributes): void {
- if (attr.type === ContractType.UpgradeBuilding && attr.buildId) {
- const predicate = (t: Task) => t.name === UpgradeBuildingTask.name && t.args.buildId === attr.buildId;
- this._storage.modifyTasks(predicate, withResources(resources));
- }
- if (attr.type === ContractType.ImproveTrooper && attr.buildId && attr.unitId) {
- const predicate = (t: Task) =>
- t.name === ForgeImprovementTask.name &&
- t.args.buildId === attr.buildId &&
- t.args.unitId === attr.unitId;
- this._storage.modifyTasks(predicate, withResources(resources));
- }
- }
-
- getVillageRequiredResources(): Resources {
- const tasks = this._storage.getTasks().filter(t => t.args.resources);
- const first = tasks.shift();
- if (first && first.args.resources) {
- return Resources.fromObject(first.args.resources);
- }
- return Resources.zero();
- }
-
- getTotalVillageRequiredResources(): Resources {
- const tasks = this._storage.getTasks().filter(t => t.args.resources);
- return tasks.reduce((acc, t) => acc.add(t.args.resources!), Resources.zero());
+ this.taskCollection.postponeTask(taskId, seconds);
}
}
diff --git a/src/VillageControllerFactory.ts b/src/VillageControllerFactory.ts
deleted file mode 100644
index da46493..0000000
--- a/src/VillageControllerFactory.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { VillageController } from './VillageController';
-import { VillageStorage } from './Storage/VillageStorage';
-import { VillageRepository } from './VillageRepository';
-
-export class VillageControllerFactory {
- private villageRepository: VillageRepository;
-
- constructor(villageRepository: VillageRepository) {
- this.villageRepository = villageRepository;
- }
-
- create(villageId: number): VillageController {
- const village = this.villageRepository.get(villageId);
- return new VillageController(village.id, new VillageStorage(village.id));
- }
-
- getActive(): VillageController {
- const village = this.villageRepository.getActive();
- return this.create(village.id);
- }
-}
diff --git a/src/VillageFactory.ts b/src/VillageFactory.ts
new file mode 100644
index 0000000..fce1435
--- /dev/null
+++ b/src/VillageFactory.ts
@@ -0,0 +1,57 @@
+import { VillageController } from './VillageController';
+import { VillageStorage } from './Storage/VillageStorage';
+import { VillageRepository } from './VillageRepository';
+import { VillageTaskCollection } from './VillageTaskCollection';
+import { VillageState, VillageStateFactory } from './VillageState';
+
+export class VillageFactory {
+ private readonly villageRepository: VillageRepository;
+
+ constructor(villageRepository: VillageRepository) {
+ this.villageRepository = villageRepository;
+ }
+
+ createStorage(villageId: number): VillageStorage {
+ const village = this.villageRepository.get(villageId);
+ return new VillageStorage(village.id);
+ }
+
+ createStorageForActiveVillage(): VillageStorage {
+ const village = this.villageRepository.getActive();
+ return this.createStorage(village.id);
+ }
+
+ createTaskCollection(villageId: number): VillageTaskCollection {
+ const village = this.villageRepository.get(villageId);
+ return new VillageTaskCollection(village.id, this.createStorage(villageId));
+ }
+
+ createTaskCollectionForActiveVillage(): VillageTaskCollection {
+ const village = this.villageRepository.getActive();
+ return this.createTaskCollection(village.id);
+ }
+
+ createState(villageId: number): VillageState {
+ const village = this.villageRepository.get(villageId);
+ const stateFactory = new VillageStateFactory(
+ this.villageRepository,
+ (id: number) => this.createStorage(id),
+ (id: number) => this.createTaskCollection(id)
+ );
+ return stateFactory.getVillageState(village.id);
+ }
+
+ getAllVillageStates(): Array {
+ const stateFactory = new VillageStateFactory(
+ this.villageRepository,
+ (id: number) => this.createStorage(id),
+ (id: number) => this.createTaskCollection(id)
+ );
+ return stateFactory.getAllVillageStates();
+ }
+
+ createController(villageId: number): VillageController {
+ const village = this.villageRepository.get(villageId);
+ return new VillageController(village.id, this.createTaskCollection(village.id), this.createState(village.id));
+ }
+}
diff --git a/src/VillageState.ts b/src/VillageState.ts
index a67587d..c3c282e 100644
--- a/src/VillageState.ts
+++ b/src/VillageState.ts
@@ -7,8 +7,7 @@ import { VillageNotFound } from './Errors';
import { ProductionQueue, ProductionQueueTypes } from './Core/ProductionQueue';
import { Task } from './Queue/TaskProvider';
import { timestamp } from './utils';
-import { VillageControllerFactory } from './VillageControllerFactory';
-import { VillageController } from './VillageController';
+import { VillageTaskCollection } from './VillageTaskCollection';
interface VillageStorageState {
resources: Resources;
@@ -134,12 +133,12 @@ function taskResourceReducer(resources: Resources, task: Task) {
function createProductionQueueState(
queue: ProductionQueue,
- controller: VillageController
+ storage: VillageStorage,
+ taskCollection: VillageTaskCollection
): VillageProductionQueueState {
- const storage = controller.getStorage();
const resources = storage.getResources();
const performance = storage.getResourcesPerformance();
- const tasks = controller.getTasksInProductionQueue(queue);
+ const tasks = taskCollection.getTasksInProductionQueue(queue);
const firstTaskResources = tasks.slice(0, 1).reduce(taskResourceReducer, Resources.zero());
const allTaskResources = tasks.reduce(taskResourceReducer, Resources.zero());
@@ -156,33 +155,36 @@ function createProductionQueueState(
};
}
-function createAllProductionQueueStates(controller: VillageController) {
+function createAllProductionQueueStates(storage: VillageStorage, taskCollection: VillageTaskCollection) {
let result: { [queue: string]: VillageProductionQueueState } = {};
for (let queue of ProductionQueueTypes) {
- result[queue] = createProductionQueueState(queue, controller);
+ result[queue] = createProductionQueueState(queue, storage, taskCollection);
}
return result;
}
-function calcFrontierResources(controller: VillageController): Resources {
+function calcFrontierResources(taskCollection: VillageTaskCollection): Resources {
let result = Resources.zero();
for (let queue of ProductionQueueTypes) {
- const tasks = controller.getTasksInProductionQueue(queue);
+ const tasks = taskCollection.getTasksInProductionQueue(queue);
const firstTaskResources = tasks.slice(0, 1).reduce(taskResourceReducer, Resources.zero());
result = result.add(firstTaskResources);
}
return result;
}
-function createVillageOwnState(village: Village, controller: VillageController): VillageOwnState {
- const storage = controller.getStorage();
+function createVillageOwnState(
+ village: Village,
+ storage: VillageStorage,
+ taskCollection: VillageTaskCollection
+): VillageOwnState {
const resources = storage.getResources();
const resourceStorage = storage.getResourceStorage();
const performance = storage.getResourcesPerformance();
const buildQueueInfo = storage.getBuildingQueueInfo();
- const requiredResources = controller.getVillageRequiredResources();
- const frontierResources = calcFrontierResources(controller);
- const totalRequiredResources = controller.getTotalVillageRequiredResources();
+ const requiredResources = taskCollection.getVillageRequiredResources();
+ const frontierResources = calcFrontierResources(taskCollection);
+ const totalRequiredResources = taskCollection.getTotalVillageRequiredResources();
return {
id: village.id,
@@ -196,18 +198,22 @@ function createVillageOwnState(village: Village, controller: VillageController):
buildRemainingSeconds: buildQueueInfo.seconds,
incomingResources: calcIncomingResources(storage),
settings: storage.getSettings(),
- queues: createAllProductionQueueStates(controller),
+ queues: createAllProductionQueueStates(storage, taskCollection),
};
}
function createVillageOwnStates(
villages: Array,
- villageControllerFactory: VillageControllerFactory
+ storageFactory: VillageStorageFactory,
+ taskCollectionFactory: VillageTaskCollectionFactory
): VillageOwnStateDictionary {
const result: VillageOwnStateDictionary = {};
for (let village of villages) {
- const villageController = villageControllerFactory.create(village.id);
- result[village.id] = createVillageOwnState(village, villageController);
+ result[village.id] = createVillageOwnState(
+ village,
+ storageFactory(village.id),
+ taskCollectionFactory(village.id)
+ );
}
return result;
}
@@ -226,27 +232,42 @@ function createVillageState(state: VillageOwnState, ownStates: VillageOwnStateDi
function getVillageStates(
villages: Array,
- villageControllerFactory: VillageControllerFactory
+ storageFactory: VillageStorageFactory,
+ taskCollectionFactory: VillageTaskCollectionFactory
): Array {
- const ownStates = createVillageOwnStates(villages, villageControllerFactory);
+ const ownStates = createVillageOwnStates(villages, storageFactory, taskCollectionFactory);
return villages.map(village => createVillageState(ownStates[village.id], ownStates));
}
-export class VillageStateRepository {
- private villageRepository: VillageRepositoryInterface;
- private villageControllerFactory: VillageControllerFactory;
+interface VillageStorageFactory {
+ (villageId: number): VillageStorage;
+}
- constructor(villageRepository: VillageRepositoryInterface, villageControllerFactory: VillageControllerFactory) {
+interface VillageTaskCollectionFactory {
+ (villageId: number): VillageTaskCollection;
+}
+
+export class VillageStateFactory {
+ private readonly villageRepository: VillageRepositoryInterface;
+ private readonly storageFactory: VillageStorageFactory;
+ private readonly taskCollectionFactory: VillageTaskCollectionFactory;
+
+ constructor(
+ villageRepository: VillageRepositoryInterface,
+ storageFactory: VillageStorageFactory,
+ taskCollectionFactory: VillageTaskCollectionFactory
+ ) {
this.villageRepository = villageRepository;
- this.villageControllerFactory = villageControllerFactory;
+ this.storageFactory = storageFactory;
+ this.taskCollectionFactory = taskCollectionFactory;
}
getAllVillageStates(): Array {
- return getVillageStates(this.villageRepository.all(), this.villageControllerFactory);
+ return getVillageStates(this.villageRepository.all(), this.storageFactory, this.taskCollectionFactory);
}
getVillageState(villageId: number): VillageState {
- const states = getVillageStates(this.villageRepository.all(), this.villageControllerFactory);
+ const states = getVillageStates(this.villageRepository.all(), this.storageFactory, this.taskCollectionFactory);
const needle = states.find(s => s.id === villageId);
if (!needle) {
throw new VillageNotFound(`Village ${villageId} not found`);
diff --git a/src/VillageTaskCollection.ts b/src/VillageTaskCollection.ts
new file mode 100644
index 0000000..68c8c25
--- /dev/null
+++ b/src/VillageTaskCollection.ts
@@ -0,0 +1,116 @@
+import { VillageStorage } from './Storage/VillageStorage';
+import { Task, TaskId, TaskList, uniqTaskId, withResources, withTime } from './Queue/TaskProvider';
+import { Args } from './Queue/Args';
+import { isProductionTask, ProductionQueue, ProductionQueueTypes } from './Core/ProductionQueue';
+import { getProductionQueue } from './Task/TaskMap';
+import { timestamp } from './utils';
+import { Resources } from './Core/Resources';
+import { ContractAttributes, ContractType } from './Core/Contract';
+import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
+import { ForgeImprovementTask } from './Task/ForgeImprovementTask';
+
+export class VillageTaskCollection {
+ private readonly storage: VillageStorage;
+ private readonly villageId: number;
+
+ constructor(villageId: number, storage: VillageStorage) {
+ this.villageId = villageId;
+ this.storage = storage;
+ }
+
+ getTasks(): Array {
+ return this.storage.getTasks();
+ }
+
+ private modifyTasks(predicate: (t: Task) => boolean, modifier: (t: Task) => Task): number {
+ const [matched, other] = this.split(predicate);
+ const modified = matched.map(modifier);
+ const modifiedCount = modified.length;
+ this.storage.storeTaskList(modified.concat(other));
+ return modifiedCount;
+ }
+
+ private removeTasks(predicate: (t: Task) => boolean): number {
+ const [_, other] = this.split(predicate);
+ const result = other.length;
+ this.storage.storeTaskList(other);
+ return result;
+ }
+
+ private split(predicate: (t: Task) => boolean): [TaskList, TaskList] {
+ const matched: TaskList = [];
+ const other: TaskList = [];
+ this.getTasks().forEach(t => {
+ if (predicate(t)) {
+ matched.push(t);
+ } else {
+ other.push(t);
+ }
+ });
+ return [matched, other];
+ }
+
+ addTask(name: string, args: Args) {
+ if (!isProductionTask(name)) {
+ throw new Error(`Task "${name}" is not production task`);
+ }
+ if (args.villageId !== this.villageId) {
+ throw new Error(`Task village id (${args.villageId}) not equal controller village id (${this.villageId}`);
+ }
+ const task = new Task(uniqTaskId(), 0, name, { villageId: this.villageId, ...args });
+
+ const tasks = this.getTasks();
+ tasks.push(task);
+ this.storage.storeTaskList(tasks);
+ }
+
+ removeTask(taskId: TaskId) {
+ this.removeTasks(t => t.id === taskId);
+ }
+
+ getTasksInProductionQueue(queue: ProductionQueue): Array {
+ return this.storage.getTasks().filter(task => getProductionQueue(task.name) === queue);
+ }
+
+ getReadyProductionTask(): Task | undefined {
+ let sortedTasks: Array = [];
+ for (let queue of ProductionQueueTypes) {
+ const tasks = this.getTasksInProductionQueue(queue);
+ sortedTasks = sortedTasks.concat(tasks);
+ }
+ return sortedTasks.shift();
+ }
+
+ postponeTask(taskId: TaskId, seconds: number) {
+ const modifyTime = withTime(timestamp() + seconds);
+ this.modifyTasks(task => task.id === taskId, modifyTime);
+ }
+
+ updateResources(resources: Resources, attr: ContractAttributes): void {
+ if (attr.type === ContractType.UpgradeBuilding && attr.buildId) {
+ const predicate = (t: Task) => t.name === UpgradeBuildingTask.name && t.args.buildId === attr.buildId;
+ this.modifyTasks(predicate, withResources(resources));
+ }
+ if (attr.type === ContractType.ImproveTrooper && attr.buildId && attr.unitId) {
+ const predicate = (t: Task) =>
+ t.name === ForgeImprovementTask.name &&
+ t.args.buildId === attr.buildId &&
+ t.args.unitId === attr.unitId;
+ this.modifyTasks(predicate, withResources(resources));
+ }
+ }
+
+ getVillageRequiredResources(): Resources {
+ const tasks = this.storage.getTasks().filter(t => t.args.resources);
+ const first = tasks.shift();
+ if (first && first.args.resources) {
+ return Resources.fromObject(first.args.resources);
+ }
+ return Resources.zero();
+ }
+
+ getTotalVillageRequiredResources(): Resources {
+ const tasks = this.storage.getTasks().filter(t => t.args.resources);
+ return tasks.reduce((acc, t) => acc.add(t.args.resources!), Resources.zero());
+ }
+}