import { Telegram } from './Telegram.js';
import { Logger } from './Logger.js';
/**
* This class is the core of the messaging system for game entities and used by the
* {@link EntityManager}. The implementation can directly dispatch messages or use a
* delayed delivery for deferred communication. This can be useful if a game entity
* wants to inform itself about a particular event in the future.
*
* @author {@link https://github.com/Mugen87|Mugen87}
*/
class MessageDispatcher {
/**
* Constructs a new message dispatcher.
*/
constructor() {
/**
* A list of delayed telegrams.
* @type {Array<Telegram>}
* @readonly
*/
this.delayedTelegrams = new Array();
}
/**
* Delivers the message to the receiver.
*
* @param {Telegram} telegram - The telegram to deliver.
* @return {MessageDispatcher} A reference to this message dispatcher.
*/
deliver( telegram ) {
const receiver = telegram.receiver;
if ( receiver.handleMessage( telegram ) === false ) {
Logger.warn( 'YUKA.MessageDispatcher: Message not handled by receiver: %o', receiver );
}
return this;
}
/**
* Receives the raw telegram data and decides how to dispatch the telegram (with or without delay).
*
* @param {GameEntity} sender - The sender.
* @param {GameEntity} receiver - The receiver.
* @param {String} message - The actual message.
* @param {Number} delay - A time value in millisecond used to delay the message dispatching.
* @param {Object} data - An object for custom data.
* @return {MessageDispatcher} A reference to this message dispatcher.
*/
dispatch( sender, receiver, message, delay, data ) {
const telegram = new Telegram( sender, receiver, message, delay, data );
if ( delay <= 0 ) {
this.deliver( telegram );
} else {
this.delayedTelegrams.push( telegram );
}
return this;
}
/**
* Used to process delayed messages.
*
* @param {Number} delta - The time delta.
* @return {MessageDispatcher} A reference to this message dispatcher.
*/
dispatchDelayedMessages( delta ) {
let i = this.delayedTelegrams.length;
while ( i -- ) {
const telegram = this.delayedTelegrams[ i ];
telegram.delay -= delta;
if ( telegram.delay <= 0 ) {
this.deliver( telegram );
this.delayedTelegrams.pop();
}
}
return this;
}
/**
* Clears the internal state of this message dispatcher.
*
* @return {MessageDispatcher} A reference to this message dispatcher.
*/
clear() {
this.delayedTelegrams.length = 0;
return this;
}
/**
* Transforms this instance into a JSON object.
*
* @return {Object} The JSON object.
*/
toJSON() {
const data = {
type: this.constructor.name,
delayedTelegrams: new Array()
};
// delayed telegrams
for ( let i = 0, l = this.delayedTelegrams.length; i < l; i ++ ) {
const delayedTelegram = this.delayedTelegrams[ i ];
data.delayedTelegrams.push( delayedTelegram.toJSON() );
}
return data;
}
/**
* Restores this instance from the given JSON object.
*
* @param {Object} json - The JSON object.
* @return {MessageDispatcher} A reference to this message dispatcher.
*/
fromJSON( json ) {
this.clear();
const telegramsJSON = json.delayedTelegrams;
for ( let i = 0, l = telegramsJSON.length; i < l; i ++ ) {
const telegramJSON = telegramsJSON[ i ];
const telegram = new Telegram().fromJSON( telegramJSON );
this.delayedTelegrams.push( telegram );
}
return this;
}
/**
* Restores UUIDs with references to GameEntity objects.
*
* @param {Map<String,GameEntity>} entities - Maps game entities to UUIDs.
* @return {MessageDispatcher} A reference to this message dispatcher.
*/
resolveReferences( entities ) {
const delayedTelegrams = this.delayedTelegrams;
for ( let i = 0, l = delayedTelegrams.length; i < l; i ++ ) {
const delayedTelegram = delayedTelegrams[ i ];
delayedTelegram.resolveReferences( entities );
}
return this;
}
}
export { MessageDispatcher };