@reldens/items-system
Version:
Reldens - Items System
166 lines (148 loc) • 6.68 kB
JavaScript
/**
*
* Reldens - Items System - Receiver
*
* This class is meant to be extended and used to parse the data sent by the server and run the same actions but using
* different methods on the client side.
*
* Let's say you have an array of items in the server that you are sending to the client (see lib/server/sender.js).
* You will be sending specific item data depending on the action. This is because you usually don't need to send the
* full item data to the client. In the default Sender on this package we are sending just the item key and the id most
* of the time except for when we add the item itself at which point we need more details (like qty, uses, etc.).
*
* When you create an instance of this class you will need to pass a Manager instance in the constructor, this is
* because when a message is received this class will replicate the action that was executed in the server but in the
* client, this way you can use a new set of client-side custom classes (configured in this new Manager instance) to run
* your items.
*
* Wait, what? why? Well... In your server, your items will be objects that will have specific methods for server
* functions like persist your item data or run your item logic (following an authoritative server), but in your client,
* you won't need any of those and probably will need different methods (for example, to run items animations) and at
* the same time still keep a track of your items qty for display, that's where this class is useful.
*
*/
const ItemsManager = require('../manager');
const ItemsConst = require('../constants');
const ItemGroup = require('../item/group');
const { ErrorManager, Logger, sc } = require('@reldens/utils');
class Receiver
{
constructor(props)
{
if(!sc.hasOwn(props, 'owner')){
ErrorManager.error('Undefined owner.');
}
this.manager = sc.hasOwn(props, 'manager') ? props.manager : new ItemsManager(props);
this.actions = sc.hasOwn(props, 'actions') ? props.actions : {};
if(false === sc.get(props, 'avoidDefaults', false)){
this.setDefaultActions();
}
this.recieveErrorsLog = [];
}
setDefaultActions()
{
this.actions[ItemsConst.ACTION_SET_ITEMS] = 'onSetItems';
this.actions[ItemsConst.ACTION_SET_GROUPS] = 'onSetGroups';
this.actions[ItemsConst.ACTION_ADD] = 'onAddItem';
this.actions[ItemsConst.ACTION_REMOVE] = 'onRemoveItem';
this.actions[ItemsConst.ACTION_MODIFY_QTY] = 'onSetQty';
this.actions[ItemsConst.ACTION_EQUIP] = 'onEquipItem';
this.actions[ItemsConst.ACTION_UNEQUIP] = 'onUnequipItem';
this.actions[ItemsConst.ACTION_MOD_APPLIED] = 'onModifiersApplied';
this.actions[ItemsConst.ACTION_MOD_REVERTED] = 'onModifiersReverted';
this.actions[ItemsConst.ACTION_EXECUTING] = 'onExecuting';
this.actions[ItemsConst.ACTION_EXECUTED] = 'onExecuted';
}
processMessage(message)
{
// don't validate the message if the action prefix is not present or at the beginning of the message action:
let action = sc.get(message, 'act', '');
if(0 !== action.indexOf(ItemsConst.ACTIONS_PREF)){
return false;
}
if(!sc.hasOwn(this.actions, action)){
Logger.error('Items action not found', action, message);
return false;
}
if('function' !== typeof this[this.actions[action]]){
Logger.info('Items action is not a function.', message.act);
return false;
}
this[this.actions[action]](message);
}
onSetItems(message)
{
let tempItemsList = {};
for(let i of Object.keys(message.items)){
let messageItem = message.items[i];
let itemsProps = Object.assign({manager: this.manager}, messageItem, {uid: i});
let itemClass = this.getItemClass(itemsProps.key, itemsProps.type);
tempItemsList[i] = new itemClass(itemsProps);
if(tempItemsList[i].isType(ItemsConst.TYPES.EQUIPMENT) && sc.hasOwn(itemsProps, 'is_active')){
tempItemsList[i].equipped = (1 === itemsProps.is_active);
}
}
return this.manager.setItems(tempItemsList);
}
onSetGroups(message)
{
let tempGroupList = {};
for(let i of Object.keys(message.groups)){
let groupClass = this.getGroupClass(message.groups[i].key);
tempGroupList[message.groups[i].key] = new groupClass(message.groups[i]);
}
return this.manager.setGroups(tempGroupList);
}
onAddItem(message)
{
// @NOTE: receiver must override the uid since it's already been set on the server.
let itemsProps = Object.assign({manager: this.manager}, message.item, {uid: message.item.idx});
let itemClass = this.getItemClass(itemsProps.key, itemsProps.type);
let tmpItem = new itemClass(itemsProps);
this.manager.addItem(tmpItem).catch((err) => {
this.recieveErrorsLog.push({'Error receiver onAddItem.': err});
});
}
onRemoveItem(message)
{
this.manager.removeItem(message.item.idx).catch((err) => {
this.recieveErrorsLog.push({'Error receiver onRemoveItem.': err});
});
}
onSetQty(message)
{
this.manager.setItemQty(message.item.idx, message.item.qty).catch((err) => {
this.recieveErrorsLog.push({'Error receiver onSetQty.': err});
});
}
onEquipItem(message)
{
this.manager.items[message.item.idx].equip(false).catch((err) => {
this.recieveErrorsLog.push({'Error receiver onEquipItem.': err});
});
}
onUnequipItem(message)
{
this.manager.items[message.item.idx].unequip(false).catch((err) => {
this.recieveErrorsLog.push({'Error receiver onUnequipItem.': err});
});
}
// @NOTE: override to apply custom behaviors on these.
onModifiersApplied(message){}
onModifiersReverted(message){}
onExecuting(message){}
onExecuted(message){}
getItemClass(key, typeId)
{
return sc.get(this.manager.itemClasses, key, this.manager.types.classByTypeId(typeId));
}
getGroupClass(key)
{
let groupClass = ItemGroup;
if(sc.hasOwn(this.manager.groupClasses, key)){
groupClass = this.manager.groupClasses[key];
}
return groupClass;
}
}
module.exports = Receiver;