Add village resources view to dashboard
This commit is contained in:
		| @@ -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); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user