reldens
Version:
Reldens - MMORPG Platform
218 lines (200 loc) • 8.31 kB
JavaScript
/**
*
* Reldens - ObjectsManager
*
*/
const { Logger, sc } = require('@reldens/utils');
class ObjectsManager
{
constructor(props)
{
this.config = props.config;
this.events = sc.get(props, 'events', false);
this.roomId = sc.get(props, 'roomId', false);
this.roomName = sc.get(props, 'roomName', false);
if(!this.events){
Logger.error('EventsManager undefined in ObjectsManager.');
}
this.dataServer = sc.get(props, 'dataServer', false);
if(!this.dataServer){
Logger.error('DataServer undefined in ObjectsManager.');
}
// room objects is just the list of the objects in the storage:
this.roomObjectsData = false;
// room objects by layer and title are each object instance plus the data from the storage:
this.roomObjects = false;
this.roomObjectsByLayer = {};
this.preloadAssets = {};
this.objectsAnimationsData = {};
this.listenMessages = false;
this.listenMessagesObjects = {};
}
async loadObjectsByRoomId(roomId)
{
if(this.roomObjectsData){
return this.roomObjectsData;
}
let objectsRepository = this.dataServer.getEntity('objects');
objectsRepository.sortBy = 'tile_index';
this.roomObjectsData = await objectsRepository.loadByWithRelations(
'room_id',
roomId,
['parent_room', 'objects_assets', 'objects_animations', 'objects_stats.[parent_stat]']
);
}
async generateObjects()
{
if(!this.roomObjectsData || 0 === this.roomObjectsData.length){
return this.roomObjects;
}
this.roomObjects = {};
// @NOTE: allow null index for multiple objects of the same type.
for(let objectData of this.roomObjectsData){
await this.generateObjectFromObjectData(objectData);
}
}
async generateObjectFromObjectData(objectData)
{
// @NOTE: these classes are coming from the theme/plugins/objects/server.js file.
let objClass = this.config.getWithoutLogs('server/customClasses/objects/'+objectData.object_class_key, false);
let objectClassTypes = this.config?.configList?.server?.objectsClassTypes;
if(!objClass && objectClassTypes && objectData.class_type){
let objClassData = sc.get(objectClassTypes, objectData.class_type, false);
if(objClassData){
objClass = objClassData.classInstance;
}
}
if(!objClass){
Logger.error('ObjectManager object class type not found.', objectData);
return false;
}
let objProps = Object.assign(
{config: this.config, events: this.events, dataServer: this.dataServer},
objectData
);
this.prepareInitialStats(objProps);
try {
let objectInstance = new objClass(objProps);
this.attachToAnimations(objectInstance);
if(objectInstance.multiple){
objectInstance.objProps = objProps;
let subObjClass = false;
if(objectClassTypes && objectInstance.childObjectType){
let objClassData = sc.get(objectClassTypes, objectInstance.childObjectType, false);
if(objClassData){
subObjClass = objClassData.classInstance;
}
}
if(objectInstance.childObjectType && !subObjClass){
Logger.error('ObjectManager sub-object class type not found.', {
objectClassKey: objectData.object_class_key,
childObjectType: objectInstance.childObjectType
});
return false;
}
objectInstance.classInstance = subObjClass;
}
this.enrichWithMultipleAnimationsData(objectData, objectInstance);
this.attachToMessagesListeners(objectInstance, objectData);
this.prepareAssetsPreload(objectData);
await this.runAdditionalSetup(objectInstance, objectData);
this.events.emit('reldens.afterRunAdditionalSetup', {
objectInstance,
objectData,
objectsManager: this
});
this.roomObjects[objectInstance.objectIndex] = objectInstance;
if(!this.roomObjectsByLayer[objectData.layer_name]){
this.roomObjectsByLayer[objectData.layer_name] = {};
}
this.roomObjectsByLayer[objectData.layer_name][objectData.id] = objectInstance;
return objectInstance;
} catch (error) {
Logger.error('Error while generating object.', error, objectData);
return false;
}
}
prepareInitialStats(objProps)
{
let stats = sc.get(objProps, 'objects_stats', []);
if(0 === stats.length){
return;
}
if(!objProps.initialStats){
objProps.initialStats = {};
}
for(let stat of stats){
objProps.initialStats[stat.parent_stat.key] = stat.value;
}
}
async runAdditionalSetup(objectInstance, objectData)
{
if(!sc.isObjectFunction(objectInstance, 'runAdditionalSetup')){
return false;
}
objectInstance.runAdditionalSetup({objectsManager: this, objectData});
}
prepareAssetsPreload(objectData)
{
if(!objectData.objects_assets){
return false;
}
for(let asset of objectData.objects_assets){
// @NOTE: assets can be different types, sprite sheets, images, atlas, etc. We push them
// here to later send these to the client along with the sceneData.
this.preloadAssets[(asset.object_id || '')+(asset.object_asset_id || '')] = asset;
}
}
attachToMessagesListeners(objectInstance, objectData)
{
// prepare object for room messages:
if(!sc.hasOwn(objectInstance, 'listenMessages')){
return false;
}
this.listenMessages = true;
this.listenMessagesObjects[objectData.id] = objectInstance;
}
enrichWithMultipleAnimationsData(objectData, objectInstance)
{
if(!objectData.objects_animations){
return false;
}
objectInstance.multipleAnimations = {};
for(let anim of objectData.objects_animations){
// @NOTE: assets can be different types, sprite sheets, images, atlas, etc.
// We push them here to later send these to the client along with the sceneData.
objectInstance.multipleAnimations[anim.animationKey] = sc.toJson(anim.animationData);
}
}
attachToAnimations(objectInstance)
{
// if the result is an animation instance then we can include it in the list to send it to the client:
if(sc.hasOwn(objectInstance, 'isAnimation') || sc.hasOwn(objectInstance, 'hasAnimation')){
this.objectsAnimationsData[objectInstance.objectIndex] = objectInstance.clientParams;
}
}
/**
* The object instance is created when the world is created since we don't need to overload the server by creating
* every object defined if it is not going to be used.
*/
getObjectData(objectIndex)
{
if(sc.hasOwn(this.roomObjects, objectIndex)){
return this.roomObjects[objectIndex];
}
return false;
}
removeObjectData(rewardObject)
{
this.removeFromPreloadAssetsArray(rewardObject.objects_assets);
delete this.roomObjects[rewardObject.objectIndex];
delete this.objectsAnimationsData[rewardObject.objectIndex];
}
removeFromPreloadAssetsArray(objectAssets)
{
for(let objectAsset of objectAssets){
delete this.preloadAssets[(objectAsset.object_id || '')+(objectAsset.object_asset_id || '')];
}
}
}
module.exports.ObjectsManager = ObjectsManager;