Add fast resource transfer management

This commit is contained in:
Anton Vakhrushev 2020-05-08 21:00:47 +03:00
parent f648f7dd5a
commit 304c192ab0
8 changed files with 79 additions and 50 deletions

View File

@ -4,7 +4,6 @@ import { Resources } from '../Core/Resources';
import { Coordinates, Village } from '../Core/Village';
import { grabVillageResources } from '../Page/ResourcesBlock';
import { grabActiveVillageId, grabVillageList } from '../Page/VillageBlock';
import { SendResourcesTask } from '../Task/SendResourcesTask';
import { aroundMinutes, timestamp } from '../utils';
import { VillageStorage } from '../Storage/VillageStorage';
import { Args } from '../Queue/Args';
@ -16,34 +15,18 @@ const TIMEOUT = 15;
@registerAction
export class SendResourcesAction extends ActionController {
async run(args: Args, task: Task): Promise<any> {
const resources = Resources.fromObject(args.resources || err('No resources'));
const coordinates = Coordinates.fromObject(args.coordinates || err('No coordinates'));
console.log('Send', resources, 'to', coordinates);
const recipientVillage = args.targetVillageId
? this.findRecipientVillageById(args.targetVillageId)
: this.findRecipientVillage(coordinates);
const readyToTransfer = this.getResourcesForTransfer(recipientVillage.id).min(resources);
const readyToTransfer = this.getResourcesForTransfer(recipientVillage.id);
const remainingResources = resources.sub(readyToTransfer).max(Resources.zero());
console.log('Total res', resources);
console.log('To transfer res', readyToTransfer);
console.log('Remaining res', remainingResources);
if (!remainingResources.empty()) {
console.log('Schedule next', remainingResources);
this.scheduler.scheduleTask(
SendResourcesTask.name,
{
...args,
resources: remainingResources,
},
timestamp() + aroundMinutes(TIMEOUT)
);
}
// Schedule recurrent task
this.scheduler.scheduleTask(task.name, task.args, timestamp() + aroundMinutes(TIMEOUT));
fillSendResourcesForm(readyToTransfer, coordinates);
clickSendButton();

View File

@ -41,6 +41,8 @@ interface GameState {
removeTask(taskId: string): void;
refreshVillages(): void;
pause(): void;
scheduleResourceTransferTasks(fromVillageId: number, toVillageId: number): void;
dropResourceTransferTasks(fromVillageId: number, toVillageId: number): void;
}
export class ControlPanel {
@ -101,6 +103,14 @@ export class ControlPanel {
pause() {
executionState.setExecutionSettings({ pauseTs: timestamp() + 120 });
},
scheduleResourceTransferTasks(fromVillageId: number, toVillageId: number): void {
scheduler.scheduleResourceTransferTasks(fromVillageId, toVillageId);
},
dropResourceTransferTasks(fromVillageId: number, toVillageId: number): void {
scheduler.dropResourceTransferTasks(fromVillageId, toVillageId);
},
};
state.refresh();
@ -109,11 +119,7 @@ export class ControlPanel {
state.refresh();
}, 3000);
DataStorage.onChange(
_.debounce(() => {
state.refresh();
}, 500)
);
DataStorage.onChange(() => state.refresh());
const getBuildingsInQueue = () =>
this.scheduler

View File

@ -172,7 +172,15 @@
class="village-quick-link"
:class="{ active: villageState.shipment.includes(s.id) }"
:href="marketPath(villageState.village, s.village)"
:title="'Отправить ресурсы из ' + villageState.village.name + ' в ' + s.village.name"
:title="
'Отправить ресурсы из ' +
villageState.village.name +
' в ' +
s.village.name +
'(shift+click - настроить отправку)'
"
v-on:click.prevent.shift.exact="setupResourceTransfer(villageState, s)"
v-on:click.prevent.exact="goToMarket(villageState.village, s.village)"
>$->{{ s.village.name }}</a
>
<a class="village-quick-link" :href="quartersPath(villageState.village)">Казармы</a>
@ -253,6 +261,20 @@ export default {
}
return secondsToTime(value.seconds);
},
goToMarket(fromVillage, toVillage) {
window.location.assign(this.marketPath(fromVillage, toVillage));
},
setupResourceTransfer(villageState, toVillageState) {
villageState.shipment.includes(toVillageState.id)
? this.dropResourceTransferTasks(villageState.id, toVillageState.id)
: this.scheduleResourceTransferTasks(villageState.id, toVillageState.id);
},
scheduleResourceTransferTasks(fromVillageId, toVillageId) {
this.shared.scheduleResourceTransferTasks(fromVillageId, toVillageId);
},
dropResourceTransferTasks(fromVillageId, toVillageId) {
this.shared.dropResourceTransferTasks(fromVillageId, toVillageId);
},
},
};
</script>

View File

@ -5,23 +5,17 @@ import { IncomingMerchant } from '../../Core/Market';
import { grabResourcesFromList } from './BuildingPage';
interface SendResourcesClickHandler {
(resources: Resources, crd: Coordinates, scale: number): void;
(resources: Resources, crd: Coordinates): void;
}
export function createSendResourcesButton(onClickHandler: SendResourcesClickHandler) {
const id1 = uniqId();
const id10 = uniqId();
const id100 = uniqId();
const id1000 = uniqId();
const id = uniqId();
jQuery('#button').before(`<div style="padding: 8px">
<a id="${id1}" href="#">Отправить</a> /
<a id="${id10}" href="#">x10</a> /
<a id="${id100}" href="#">x100</a> /
<a id="${id1000}" href="#">x1000</a>
<a id="${id}" href="#">Отправить</a> /
</div>`);
const createHandler = (handler: SendResourcesClickHandler, scale: number) => (evt: JQuery.Event) => {
const createHandler = () => (evt: JQuery.Event) => {
evt.preventDefault();
const sendSelect = jQuery('#send_select');
const resources = new Resources(
@ -31,13 +25,10 @@ export function createSendResourcesButton(onClickHandler: SendResourcesClickHand
getNumber(sendSelect.find('#r4').val())
);
const crd = new Coordinates(getNumber(jQuery('#xCoordInput').val()), getNumber(jQuery('#yCoordInput').val()));
onClickHandler(resources, crd, scale);
onClickHandler(resources, crd);
};
jQuery(`#${id1}`).on('click', createHandler(onClickHandler, 1));
jQuery(`#${id10}`).on('click', createHandler(onClickHandler, 10));
jQuery(`#${id100}`).on('click', createHandler(onClickHandler, 100));
jQuery(`#${id1000}`).on('click', createHandler(onClickHandler, 1000));
jQuery(`#${id}`).on('click', createHandler());
}
export function grabMerchantsInfo() {

View File

@ -56,7 +56,7 @@ export class BuildingPageController {
}
if (isMarketSendResourcesPage()) {
createSendResourcesButton((res, crd, scale) => this.onSendResources(res, crd, scale));
createSendResourcesButton((res, crd) => this.onSendResources(res, crd));
}
if (isForgePage()) {
@ -99,7 +99,7 @@ export class BuildingPageController {
notify(`Training ${count} troopers scheduled`);
}
private onSendResources(resources: Resources, coordinates: Coordinates, scale: number) {
private onSendResources(resources: Resources, coordinates: Coordinates) {
const villageId = grabActiveVillageId();
const targetVillage = grabVillageList().find(v => v.crd.eq(coordinates));
this.scheduler.scheduleTask(SendResourcesTask.name, {
@ -108,10 +108,9 @@ export class BuildingPageController {
buildTypeId: this.attributes.buildTypeId,
buildId: this.attributes.buildId,
tabId: this.attributes.tabId,
resources: resources.scale(scale),
coordinates,
});
notify(`Send resources ${JSON.stringify(resources)} from ${villageId} to ${JSON.stringify(coordinates)}`);
notify(`Send resources from ${villageId} to ${JSON.stringify(coordinates)}`);
}
private onResearch(resources: Resources, unitId: number) {

View File

@ -42,9 +42,11 @@ export class TaskQueue {
return modifiedCount;
}
remove(id: TaskId) {
const [_, items] = this.shiftTask(id);
this.flushItems(items);
remove(predicate: (t: Task) => boolean): number {
const [_, other] = this.split(predicate);
const result = other.length;
this.flushItems(other);
return result;
}
seeItems(): ImmutableTaskList {

View File

@ -13,6 +13,8 @@ import { Args } from './Queue/Args';
import { ImmutableTaskList, Task, TaskId } from './Queue/TaskProvider';
import { ForgeImprovementTask } from './Task/ForgeImprovementTask';
import { getTaskType, TaskType } from './Task/TaskMap';
import { MARKET_ID } from './Core/Buildings';
import { grabVillageList } from './Page/VillageBlock';
export enum ContractType {
UpgradeBuilding,
@ -84,7 +86,7 @@ export class Scheduler {
}
removeTask(taskId: TaskId) {
this.taskQueue.remove(taskId);
this.taskQueue.remove(t => t.id === taskId);
this.actionQueue.clear();
}
@ -172,6 +174,30 @@ export class Scheduler {
return tasks.map(t => t.args.targetVillageId!);
}
dropResourceTransferTasks(fromVillageId: number, toVillageId: number): void {
this.taskQueue.remove(
t =>
t.name === SendResourcesTask.name &&
t.args.villageId === fromVillageId &&
t.args.targetVillageId === toVillageId
);
}
scheduleResourceTransferTasks(fromVillageId: number, toVillageId: number): void {
this.dropResourceTransferTasks(fromVillageId, toVillageId);
const village = grabVillageList().find(v => v.id === toVillageId);
if (!village) {
throw new Error('No village');
}
this.scheduleTask(SendResourcesTask.name, {
villageId: fromVillageId,
targetVillageId: toVillageId,
coordinates: village.crd,
buildTypeId: MARKET_ID,
tabId: 5,
});
}
private reorderVillageTasks(villageId: number) {
const tasks = this.taskQueue.seeItems();

View File

@ -24,7 +24,7 @@ describe('Task Queue', function() {
it('Can remove task by id', function() {
const provider = new ArrayTaskProvider([new Task('id1', 1, 'task1', {}), new Task('id2', 2, 'task2', {})]);
const queue = new TaskQueue(provider, new NullLogger());
queue.remove('id1');
queue.remove(t => t.id === 'id1');
const tasks = provider.getTasks();
expect(tasks).to.have.lengthOf(1);
expect(tasks[0].ts).to.be.equals(2);