Add village resources view to dashboard
This commit is contained in:
parent
29b55158d6
commit
fc75b007c8
@ -1,6 +1,6 @@
|
||||
import { Args } from '../Common';
|
||||
import { Task } from '../Storage/TaskQueue';
|
||||
import { GameState } from '../Storage/GameState';
|
||||
import { DataStorage } from '../Storage/DataStorage';
|
||||
import { Scheduler } from '../Scheduler';
|
||||
|
||||
const actionMap: { [name: string]: Function | undefined } = {};
|
||||
@ -9,20 +9,18 @@ export function registerAction(constructor: Function) {
|
||||
actionMap[constructor.name] = constructor;
|
||||
}
|
||||
|
||||
export function createAction(name: string, state: GameState, scheduler: Scheduler): ActionController | undefined {
|
||||
export function createAction(name: string, scheduler: Scheduler): ActionController | undefined {
|
||||
const storedFunction = actionMap[name];
|
||||
if (storedFunction === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const constructor = (storedFunction as unknown) as typeof ActionController;
|
||||
return new constructor(state, scheduler);
|
||||
return new constructor(scheduler);
|
||||
}
|
||||
|
||||
export class ActionController {
|
||||
protected state: GameState;
|
||||
protected scheduler: Scheduler;
|
||||
constructor(state: GameState, scheduler: Scheduler) {
|
||||
this.state = state;
|
||||
constructor(scheduler: Scheduler) {
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
|
@ -8,10 +8,10 @@ import { HeroAllResources } from '../Game';
|
||||
@registerAction
|
||||
export class BalanceHeroResourcesAction extends ActionController {
|
||||
async run(args: Args, task: Task): Promise<any> {
|
||||
const resources = grabResources().asList();
|
||||
const resourcesAsList = grabResources().asList();
|
||||
const currentType = grabCurrentHeroResource();
|
||||
|
||||
const sorted = resources.sort((x, y) => x.value - y.value);
|
||||
const sorted = resourcesAsList.sort((x, y) => x.value - y.value);
|
||||
const min = sorted[0];
|
||||
const max = sorted[sorted.length - 1];
|
||||
const delta = max.value - min.value;
|
||||
|
@ -16,6 +16,6 @@ export class GrabHeroAttributesAction extends ActionController {
|
||||
let normalized = text.replace(/[^0-9]/g, '');
|
||||
|
||||
const value = getNumber(normalized);
|
||||
this.state.set('hero', { health: value });
|
||||
// this.state.set('hero', { health: value });
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export class SendOnAdventureAction extends ActionController {
|
||||
adventures.sort((x, y) => x.level - y.level);
|
||||
|
||||
const easiest = adventures.shift();
|
||||
const hero = this.state.get('hero') || {};
|
||||
const hero = { health: 0 };
|
||||
|
||||
console.log('EASIEST', easiest);
|
||||
console.log('HERO', hero);
|
||||
|
16
src/Action/StoreVillageState.ts
Normal file
16
src/Action/StoreVillageState.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ActionController, registerAction } from './ActionController';
|
||||
import { Args } from '../Common';
|
||||
import { Task } from '../Storage/TaskQueue';
|
||||
import { grabResources } from '../Page/ResourcesBlock';
|
||||
import { grabActiveVillageId } from '../Page/VillageBlock';
|
||||
import { VillageState } from '../Storage/VillageState';
|
||||
|
||||
@registerAction
|
||||
export class StoreVillageState extends ActionController {
|
||||
async run(args: Args, task: Task): Promise<any> {
|
||||
const villageId = grabActiveVillageId();
|
||||
const resources = grabResources();
|
||||
const state = new VillageState(villageId);
|
||||
state.storeResources(resources);
|
||||
}
|
||||
}
|
@ -5,6 +5,8 @@
|
||||
<task-list></task-list>
|
||||
<hr class="separator" />
|
||||
<quick-actions></quick-actions>
|
||||
<hr class="separator" />
|
||||
<village-state-list></village-state-list>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
@ -13,14 +15,18 @@
|
||||
import Header from './Header';
|
||||
import TaskList from './TaskList';
|
||||
import QuickActions from './QuickActions';
|
||||
import VillageStateList from './VillageStateList';
|
||||
export default {
|
||||
components: {
|
||||
hdr: Header,
|
||||
'task-list': TaskList,
|
||||
'quick-actions': QuickActions,
|
||||
'village-state-list': VillageStateList,
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
return {
|
||||
shared: this.$root.$data,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
40
src/Dashboard/Components/VillageStateList.vue
Normal file
40
src/Dashboard/Components/VillageStateList.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<section>
|
||||
<table class="village-table">
|
||||
<tr v-for="village in shared.villages" :key="village.id">
|
||||
<td>{{ village.id }} - {{ village.name }}</td>
|
||||
<td>Д: {{ resources(village.id).lumber }}</td>
|
||||
<td>Г: {{ resources(village.id).clay }}</td>
|
||||
<td>Ж: {{ resources(village.id).iron }}</td>
|
||||
<td>З: {{ resources(village.id).crop }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
shared: this.$root.$data,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
resources(id) {
|
||||
return this.shared.getVillageResources(id);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.village-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.village-table td {
|
||||
border-top: 1px solid #ddd;
|
||||
padding: 4px;
|
||||
}
|
||||
</style>
|
@ -3,7 +3,7 @@ import { getNumber, toNumber, uniqId, waitForLoad } from '../utils';
|
||||
import { Scheduler } from '../Scheduler';
|
||||
import { BuildPage } from '../Page/BuildPage';
|
||||
import { UpgradeBuildingTask } from '../Task/UpgradeBuildingTask';
|
||||
import { grabActiveVillage, grabActiveVillageId } from '../Page/VillageBlock';
|
||||
import { grabActiveVillage, grabActiveVillageId, grabVillageList } from '../Page/VillageBlock';
|
||||
import {
|
||||
grabResourceDeposits,
|
||||
onResourceSlotCtrlClick,
|
||||
@ -14,6 +14,8 @@ import Vue from 'vue';
|
||||
import DashboardApp from './Components/DashboardApp.vue';
|
||||
import { ResourcesToLevel } from '../Task/ResourcesToLevel';
|
||||
import { Logger } from '../Logger';
|
||||
import { Resources } from '../Game';
|
||||
import { VillageState } from '../Storage/VillageState';
|
||||
|
||||
interface QuickAction {
|
||||
label: string;
|
||||
@ -45,6 +47,7 @@ export class Dashboard {
|
||||
const state = {
|
||||
name: 'Dashboard',
|
||||
village: grabActiveVillage(),
|
||||
villages: grabVillageList(),
|
||||
version: this.version,
|
||||
taskList: this.scheduler.getTaskItems(),
|
||||
quickActions: quickActions,
|
||||
@ -57,6 +60,11 @@ export class Dashboard {
|
||||
scheduler.removeTask(taskId);
|
||||
this.taskList = scheduler.getTaskItems();
|
||||
},
|
||||
|
||||
getVillageResources(villageId): Resources {
|
||||
const state = new VillageState(villageId);
|
||||
return state.getResources();
|
||||
},
|
||||
};
|
||||
|
||||
setInterval(() => state.refreshTasks(), 1000);
|
||||
|
@ -2,6 +2,7 @@ import * as URLParse from 'url-parse';
|
||||
|
||||
const SESSION_KEY = 'travian_automation_mode';
|
||||
const SESSION_VALUE = 'command_execution';
|
||||
const MODE_PARAMETER_NAME = 'auto-management';
|
||||
|
||||
export class ModeDetector {
|
||||
isAuto(): boolean {
|
||||
@ -14,7 +15,7 @@ export class ModeDetector {
|
||||
|
||||
private isAutoByLocation(): boolean {
|
||||
const p = new URLParse(window.location.href, true);
|
||||
return p.query['auto-management'] !== undefined;
|
||||
return p.query[MODE_PARAMETER_NAME] !== undefined;
|
||||
}
|
||||
|
||||
private isAutoBySession(): boolean {
|
||||
|
@ -8,23 +8,21 @@ import { TaskQueueRenderer } from './TaskQueueRenderer';
|
||||
import { createAction } from './Action/ActionController';
|
||||
import { createTask } from './Task/TaskController';
|
||||
import { SendOnAdventureTask } from './Task/SendOnAdventureTask';
|
||||
import { GameState } from './Storage/GameState';
|
||||
import { BalanceHeroResourcesTask } from './Task/BalanceHeroResourcesTask';
|
||||
import { Logger } from './Logger';
|
||||
import { BuildBuildingTask } from './Task/BuildBuildingTask';
|
||||
import { GrabVillageState } from './Task/GrabVillageState';
|
||||
|
||||
export class Scheduler {
|
||||
private readonly version: string;
|
||||
private taskQueue: TaskQueue;
|
||||
private actionQueue: ActionQueue;
|
||||
private gameState: GameState;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(version: string) {
|
||||
this.version = version;
|
||||
this.taskQueue = new TaskQueue();
|
||||
this.actionQueue = new ActionQueue();
|
||||
this.gameState = new GameState();
|
||||
this.logger = new Logger(this.constructor.name);
|
||||
}
|
||||
|
||||
@ -38,6 +36,7 @@ export class Scheduler {
|
||||
|
||||
this.scheduleUniqTask(3600, SendOnAdventureTask.name);
|
||||
this.scheduleUniqTask(1200, BalanceHeroResourcesTask.name);
|
||||
this.scheduleUniqTask(300, GrabVillageState.name);
|
||||
|
||||
while (true) {
|
||||
await this.doTaskProcessingStep();
|
||||
@ -52,7 +51,7 @@ export class Scheduler {
|
||||
private scheduleUniqTask(seconds: number, name: string, args: Args = {}) {
|
||||
const taskScheduler = () => {
|
||||
if (!this.taskQueue.hasNamed(name)) {
|
||||
this.taskQueue.push(name, args, timestamp() + 10 * 60);
|
||||
this.taskQueue.push(name, args, timestamp() + 5 * 60);
|
||||
}
|
||||
};
|
||||
taskScheduler();
|
||||
@ -90,7 +89,7 @@ export class Scheduler {
|
||||
}
|
||||
|
||||
private async processActionCommand(cmd: Command, task: Task) {
|
||||
const actionController = createAction(cmd.name, this.gameState, this);
|
||||
const actionController = createAction(cmd.name, this);
|
||||
this.logger.log('PROCESS ACTION', cmd.name, actionController);
|
||||
if (actionController) {
|
||||
await actionController.run(cmd.args, task);
|
||||
|
43
src/Storage/DataStorage.ts
Normal file
43
src/Storage/DataStorage.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { Logger } from '../Logger';
|
||||
|
||||
const NAMESPACE = 'travian:v1';
|
||||
|
||||
function join(...parts: Array<string>) {
|
||||
return parts.map(p => p.replace(/[:]+$/g, '').replace(/^[:]+/g, '')).join(':');
|
||||
}
|
||||
|
||||
export class DataStorage {
|
||||
private readonly logger;
|
||||
private readonly name: string;
|
||||
|
||||
constructor(name: string) {
|
||||
this.name = name;
|
||||
this.logger = new Logger(this.constructor.name);
|
||||
}
|
||||
|
||||
get(key: string): any {
|
||||
const fullKey = join(NAMESPACE, this.name, key);
|
||||
this.logger.log('GET', key);
|
||||
try {
|
||||
const serialized = localStorage.getItem(fullKey);
|
||||
return JSON.parse(serialized || '"null"');
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
has(key: string): boolean {
|
||||
const fullKey = join(NAMESPACE, this.name, key);
|
||||
return localStorage.getItem(fullKey) !== null;
|
||||
}
|
||||
|
||||
set(key: string, value: any) {
|
||||
const fullKey = join(NAMESPACE, this.name, key);
|
||||
let serialized = JSON.stringify(value);
|
||||
this.logger.log('SET', fullKey, serialized);
|
||||
localStorage.setItem(fullKey, serialized);
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
import { Logger } from '../Logger';
|
||||
|
||||
const NAMESPACE = 'game_state:v1';
|
||||
|
||||
function join(x: string, y: string) {
|
||||
return x.replace(/[:]+$/g, '') + ':' + y.replace(/^[:]+/g, '');
|
||||
}
|
||||
|
||||
export class GameState {
|
||||
private readonly logger;
|
||||
|
||||
constructor() {
|
||||
this.logger = new Logger(this.constructor.name);
|
||||
}
|
||||
|
||||
get(key: string): any {
|
||||
this.logger.log('GET', key);
|
||||
try {
|
||||
const serialized = localStorage.getItem(join(NAMESPACE, key));
|
||||
return JSON.parse(serialized || 'null');
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
has(key: string): boolean {
|
||||
return localStorage.getItem(join(NAMESPACE, key)) === null;
|
||||
}
|
||||
|
||||
set(key: string, value: any) {
|
||||
let serialized = JSON.stringify(value);
|
||||
this.logger.log('SET', key, serialized);
|
||||
localStorage.setItem(join(NAMESPACE, key), serialized);
|
||||
}
|
||||
}
|
19
src/Storage/VillageState.ts
Normal file
19
src/Storage/VillageState.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { DataStorage } from './DataStorage';
|
||||
import { Resources } from '../Game';
|
||||
|
||||
export class VillageState {
|
||||
private storage: DataStorage;
|
||||
constructor(villageId: number) {
|
||||
this.storage = new DataStorage(`village.${villageId}`);
|
||||
}
|
||||
|
||||
storeResources(resources: Resources) {
|
||||
this.storage.set('res', resources);
|
||||
}
|
||||
|
||||
getResources(): Resources {
|
||||
let plain = this.storage.get('res');
|
||||
let res = new Resources(0, 0, 0, 0, 0, 0);
|
||||
return Object.assign(res, plain) as Resources;
|
||||
}
|
||||
}
|
32
src/Task/GrabVillageState.ts
Normal file
32
src/Task/GrabVillageState.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { Args, Command } from '../Common';
|
||||
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
|
||||
import { GoToPageAction } from '../Action/GoToPageAction';
|
||||
import { path } from '../utils';
|
||||
import { Task } from '../Storage/TaskQueue';
|
||||
import { TaskController, registerTask } from './TaskController';
|
||||
import { grabVillageList } from '../Page/VillageBlock';
|
||||
import { StoreVillageState } from '../Action/StoreVillageState';
|
||||
|
||||
@registerTask
|
||||
export class GrabVillageState extends TaskController {
|
||||
async run(task: Task) {
|
||||
const args: Args = { ...task.args, taskId: task.id };
|
||||
|
||||
const actions: Array<Command> = [];
|
||||
|
||||
const villages = grabVillageList();
|
||||
for (let village of villages) {
|
||||
actions.push(
|
||||
new Command(GoToPageAction.name, {
|
||||
...args,
|
||||
path: path('/dorf1.php', { newdid: village.id }),
|
||||
})
|
||||
);
|
||||
actions.push(new Command(StoreVillageState.name, args));
|
||||
}
|
||||
|
||||
actions.push(new Command(CompleteTaskAction.name, args));
|
||||
|
||||
this.scheduler.scheduleActions(actions);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user