diff --git a/src/engine/action/pipe/task/queueable-task.ts b/src/engine/action/pipe/task/queueable-task.ts new file mode 100644 index 000000000..8610ff6ce --- /dev/null +++ b/src/engine/action/pipe/task/queueable-task.ts @@ -0,0 +1,100 @@ +import { ActorTask } from '@engine/task/impl'; +import { Actor, Player } from '@engine/world/actor'; +import { ObjectInteractionAction } from '../object-interaction.action'; +import { ItemOnObjectAction } from '../item-on-object.action'; +import { ActionHook } from '@engine/action/hook'; +import { Task } from '@engine/task'; + +/** + * The result of running a callback function will be recorded here so that the + * `QueueableTask` can make a choice to continue looping and/or to enqueue + * the desired task. + */ +export interface QueueableTaskEval { + callbackResult: boolean; + shouldContinueLooping: boolean; +} + +/** + * All actions supported by this plugin task. + */ +type ObjectAction = ObjectInteractionAction | ItemOnObjectAction; + +/** + * An ActionHook for a supported ObjectAction. + */ +type ObjectActionHook = ActionHook void>; + +/** + * The data unique to the action being executed (i.e. excluding shared data) + */ +type ObjectActionData = Omit; + +/** + * Allows any arbitrary base task to be queued at the next tick. Useful for + * queuing random movements, as well as other things. + * + * Can loop infinitely based on the result of the passed in `callback` function. +*/ +export class QueueableTask extends ActorTask { + /** + * The plugins to execute when the actor arrives at the object. + */ + private plugins: ObjectActionHook[]; + + private data: ObjectActionData; + + private task: Task | null; + + private callback: () => QueueableTaskEval; + + constructor(plugins: ObjectActionHook[], actor: Player | Actor, callback: () => QueueableTaskEval, task: Task | null, data: ObjectActionData) { + super( + actor, + ); + + this.plugins = plugins; + this.data = data; + this.task = task; + this.callback = callback; + } + + /** + * Executed every tick. Depending on the callback value, this task can stop + * future executions. + */ + public execute(): void { + const ev = this.callback(); + if (!ev.callbackResult) { + if (!ev.shouldContinueLooping) { + this.stop() + } + return; + } + + if (this.task) { + this.actor.enqueueBaseTask(this.task) + } + + // call the relevant plugins - setting this.shouldStop allows control + // of further ticks and handlers to be processed + this.plugins.forEach(plugin => { + if (!plugin || !plugin.handler) { + return; + } + + const action = { + player: this.actor, + ...this.data + } as TAction; + + plugin.handler(action); + }); + + + if (!ev.shouldContinueLooping) { + this.stop(); + return + } + } +} diff --git a/src/engine/world/actor/actor.ts b/src/engine/world/actor/actor.ts index 990b40e8c..0f28d4e71 100644 --- a/src/engine/world/actor/actor.ts +++ b/src/engine/world/actor/actor.ts @@ -13,6 +13,8 @@ import { Pathfinding } from './pathfinding'; import { ActorMetadata } from './metadata'; import { Task, TaskScheduler } from '@engine/task'; import { logger } from '@runejs/common'; +import { ObjectConfig } from '@runejs/filestore'; +import { QueueableTask } from '@engine/action/pipe/task/queueable-task'; export type ActorType = 'player' | 'npc'; @@ -333,13 +335,19 @@ export abstract class Actor { } public canMove(): boolean { - return !this.busy; + // In the future, there will undoubtedly be various reasons for the + // actor to not be able to move, but for now we are returning true. + return true; } public initiateRandomMovement(): void { - // this used to use `setInterval` but will need rewriting to be synced with ticks - // see https://github.com/runejs/server/issues/417 - // this.randomMovementInterval = setInterval(() => this.moveSomewhere(), 1000); + this.enqueueBaseTask(new QueueableTask([], this, () => { + this.moveSomewhere(); + return { + callbackResult: true, + shouldContinueLooping: true, + }; + }, null, { cacheOriginal: false, objectConfig: this as unknown as ObjectConfig })) // TODO: this needs to be better } public moveSomewhere(): void { diff --git a/src/engine/world/actor/npc.ts b/src/engine/world/actor/npc.ts index 159b3c7cb..fef7837d9 100644 --- a/src/engine/world/actor/npc.ts +++ b/src/engine/world/actor/npc.ts @@ -212,7 +212,7 @@ export class Npc extends Actor { if(this.metadata.following) { return false; } - return this.updateFlags.faceActor === undefined && this.updateFlags.animation === undefined; + return this.updateFlags.faceActor === null && this.updateFlags.animation === null; } /**