Reference Source

src/collector.mjs

import { Logger } from './vendor/logger.min.mjs';

class CollectorSingleton {
	/**
	 * The version of the module.
	 */
	version = "VERSION_REPLACE_ME";
	/**
	 * The constructor of the Diob class
	 * @private
	 */
	static DiobConstructor = (() => {
		const protoDiob = VYLO.newDiob();
		const DiobConstructor = protoDiob.__proto__.constructor;
		VYLO.delDiob(protoDiob);
		return DiobConstructor;
	})();
	/**
	 * Collection limit on arrays.
	 * @private
	 * @type {number}
	 */
	collectionLimit = 20;
	/**
	 * Warning limit.
	 * @private
	 * @type {number}
	 */
	static WARNING_LIMIT = 200;
	/**
	 * A default collection to use.
	 * @private
	 * @type {Array}
	 */
	basicCollection = [];
	/**
	 * @private
	 */
	constructor() {
        /** The logger module this module uses to log errors / logs.
         * @private
         * @type {Object}
         */
        this.logger = new Logger();
        this.logger.registerType('Collector-Module', '#ff6600');
	}
	/**
	 * Sets the max collection limit of this module.
	 * @param {number} pLimit - The max limit of instances a collection can hold.
	 */
	setMaxLimit(pLimit) {
		if (typeof(pLimit) === 'number') {
			this.collectionLimit = Math.round(pLimit);
			if (this.collectionLimit > Collector.WARNING_LIMIT) {
				this.logger.prefix('Collector-Module').warn('Collector: This is a high value to use for a max limit in a collection! Only use this high of a value if you know what you are doing.')
			}
		}
	}
	/**
	 * Collects a instance into a collection.
	 * @param {Object} pCollected - The instance to collect.
	 * @param {Array} pCollection - The collection array to collect the instance to.
	 */
	collect(pCollected, pCollection) {
		const arrayCollected = Array.isArray(pCollected);
		// If there was nothing passed to be collected
		if (!pCollected) {
			this.logger.prefix('Collector-Module').error('Collector: There was nothing passed for the %cpCollected', 'font-weight: bold', 'parameter. Expecting a instance or an object.');
			return;
		}
		// If you are passing a empty object it will not be collected
		if (typeof(pCollected) === 'object' && !arrayCollected && !Object.keys(pCollected).length) {
			this.logger.prefix('Collector-Module').error('Collector: OOPS! %cpCollected', 'font-weight: bold', ' is an empty object and will NOT be collected.');
			return;
		}
		// If you are passing an object that is not a Diob or a Object, it will not be accepted. Vylocity types all have the type variable
		if (!pCollected.type && !arrayCollected) {
			this.logger.prefix('Collector-Module').error('Collector: OOPS! %cpCollected', 'font-weight: bold', ' is not a valid object It has no type.');
			return;
		}

		if (Array.isArray((pCollection))) {
			if (pCollection.includes(pCollected)) {
				this.logger.prefix('Collector-Module').error('Collector: OOPS! %cpCollected', 'font-weight: bold', 'already belongs to the provided collection.');
				return;
			}
			if (arrayCollected) {
				if (!pCollected.length) {
					this.logger.prefix('Collector-Module').error('Collector: OOPS! %cpCollected', 'font-weight: bold', 'is an array. But it contains nothing to recycle.');
					return;
				}
			}

			if (arrayCollected) {
				// If you try to collect a instance to be recycled and the collection you are recyling it to is full, it is deleted instead.
				if (pCollection.length >= this.collectionLimit) {
					for (let i = pCollected.length - 1; i >= 0; i--) {
						const instance = pCollected[i];
						if (instance instanceof CollectorSingleton.DiobConstructor) {
							this.cleanInstance(instance);
							VYLO.delDiob(instance);
						} else {
							this.cleanInstance(instance);
							VYLO.delObject(instance);
						}
					}
					return;
				// If this collectedArray has more instances than the collection can handle, the access is deleted
				} else if (pCollected.length + pCollection.length > this.collectionLimit) {
					const remainder = pCollected.length - (this.collectionLimit - pCollection.length);
					for (let c = remainder; c > 0; c--) {
						const instance = pCollected[c];
						if (instance instanceof CollectorSingleton.DiobConstructor) {
							pCollected.splice(c, 1);
							this.cleanInstance(instance);
							VYLO.delDiob(instance);
						} else {
							pCollected.splice(c, 1);
							this.cleanInstance(instance);
							VYLO.delObject(instance);
						}
					}
				}
				// The remaining instances that are in the collectedArray is now cleaned and processed and added to the collection
				for (let k = pCollected.length - 1; k >= 0; k--) {
					const instance = pCollected[k];
					if (typeof(instance.onCollected) === 'function') instance.onCollected();
					if (!pCollection.includes(instance)) pCollection.push(instance);
					this.cleanInstance(instance);
				}
				return;
			} else {
				// If you try to collect a instance to be recycled and the collection you are recyling it to is full, it is deleted instead.
				if (pCollection.length >= this.collectionLimit) {
					if (pCollected instanceof CollectorSingleton.DiobConstructor) {
						this.cleanInstance(pCollected);
						VYLO.delDiob(pCollected);
					} else {
						this.cleanInstance(pCollected);
						VYLO.delObject(pCollected);
					}
					return;
				}
				if (typeof(pCollected.onCollected) === 'function') pCollected.onCollected();
				if (!pCollection.includes(pCollected)) pCollection.push(pCollected);
				this.cleanInstance(pCollected);
				return;
			}
		} else {
			this.logger.prefix('Collector-Module').error('Collector: Invalid variable type passed for the %cpCollection', 'font-weight: bold', 'parameter. Expecting an array. Collect failed.');
		}
	}
	/**
	 * Gets diob instance(s) from the named ocllection and returns them. If no instances exist in the collection, a new one is created as a last resort.
	 * @param {string} pType - The diob type to find in the collection.
	 * @param {number} pNum - How many of the diob instances to get from the collection.
	 * @param {Array} pCollection - The collection to retrieve these instances from.
	 * @param  {...any} pRest - Remaining args to be passed into the new constructor of the diob or onDumped event
	 * @returns {Object} The diob instance that was 
	 */
	isInCollection(pType='Diob', pNum=1, pCollection=[], ...pRest) {
		const reuseArray = [];
		let added = 0;
		let quantity = pNum;
		// Objects do not have a baseType variable
		let isObject = !VYLO.Type.getVariable(pType, 'baseType');
		if (!pCollection.length) {
			for (let i = 0; i < pNum; i++) {
				if (isObject) {
					reuseArray.push(VYLO.newObject(pType, ...pRest));
				} else {
					reuseArray.push(VYLO.newDiob(pType, ...pRest));
				}
			}
			if (reuseArray.length === 1) return reuseArray.pop();
			return reuseArray;
		} else {
			for (let j = pCollection.length - 1; j >= 0; j--) {
				if (quantity) {
					let instanceInCollection = pCollection[j];
					if (instanceInCollection.type === pType) {
						// Remove it from the collection
						pCollection.splice(j, 1);
						// Add it to the array that you will be getting from this collection
						reuseArray.push(instanceInCollection);
						// Label that this instance is no longer considered to be collection
						instanceInCollection.collectorCollected = false;
						// If this instance has a `onDumped` function defined call it.
						if (typeof(instanceInCollection.onDumped) === 'function') instanceInCollection.onDumped(...pRest);
						added++;
						quantity--;
					}
				}
			}
			// If the amount of instances we were supposed to get is greater than the instances we have gotten from the array, we need to generate more.
			if (pNum > added) {
				const missingQuantity = pNum - added;
				for (let x = 0; x < missingQuantity; x++) {
					if (isObject) {
						reuseArray.push(VYLO.newObject(pType, ...pRest));
					} else {
						reuseArray.push(VYLO.newDiob(pType, ...pRest));
					}
				}
			}
				
			if (reuseArray.length === 1) return reuseArray.pop();
			return reuseArray;
		}
	}
	/**
	 * Cleans the diob instance so it can be reused from a fresh state
	 * @private
	 * @param {Object} pDiob - The diob instance to clean.
	 */
	cleanInstance(pDiob) {
		if (pDiob) {
			if (pDiob instanceof CollectorSingleton.DiobConstructor) {
				const isInterface = (pDiob.baseType === 'Interface' || pDiob.type === 'Interface' || VYLO.Type.getInheritances(pDiob.type).includes('Interface'));
				if (pDiob.color) {
					if (typeof(pDiob.color) === 'object' && pDiob.color.constructor === Object) {
						pDiob.color.tint = 0xFFFFFF;
						pDiob.color = pDiob.color;
					} else {
						pDiob.color = null;
					}
				}
				if (typeof(pDiob.scale) === 'object') {
					pDiob.scale.x = pDiob.scale.y = 1;
					pDiob.scale = pDiob.scale;
				} else {
					pDiob.scale = 1;
				}
				if (isInterface) {
					pDiob.hide();
					if (VYLO.World.getCodeType() !== 'server') {
						VYLO.Client.removeInterfaceElement(pDiob.getInterfaceName(), pDiob, true);
					}
				}
				pDiob.playAnimation();
				pDiob.setTransition();
				pDiob.angle = 0;
				pDiob.alpha = 1;
				pDiob.xPos = 0;
				pDiob.yPos = 0;
				if (!isInterface) {
					pDiob.mapName = null;
					// PINGABLE
					pDiob.setLoc();
				}
				pDiob.text = '';
				pDiob.composite = '';
				if (pDiob.baseType === 'Movable') pDiob.move();
				for (const o of pDiob.getOverlays()) pDiob.removeOverlay(o.type);
				for (const fN of pDiob.getFilters()) pDiob.removeFilter(fN);
			}
			pDiob.collectorCollected = true;
			pDiob.inTicker = null;
			if (typeof(pDiob.clean) === 'function') pDiob.clean();
		}
	}
}
export const Collector = new CollectorSingleton();