UNPKG

reldens

Version:
302 lines (283 loc) 12.5 kB
/** * * Reldens - InventoryMessageActions * */ const { PlayerProcessor } = require('./exchange/player-processor'); const { GameConst } = require('../../game/constants'); const { ObjectsConst } = require('../../objects/constants'); const { InventoryConst } = require('../constants'); const { Logger, sc } = require('@reldens/utils'); const { ExchangePlatform } = require('@reldens/items-system'); class InventoryMessageActions { async executeMessageActions(client, data, room, playerSchema) { if(!sc.hasOwn(data, 'act')){ return false; } if(GameConst.CLOSE_UI_ACTION === data.act){ if(!sc.hasOwn(data, 'id') || !data.id){ return false; } if(!sc.isFunction(data.id['indexOf']) || 0 !== data.id.indexOf('trade')){ return false; } return this.closeTradeAction(client, data, room, playerSchema); } if(0 !== data.act.indexOf(InventoryConst.ACTIONS.PREFIX)){ return false; } if(InventoryConst.ACTIONS.TRADE_START === data.act){ this.tryExchangeStart(client, data, room, playerSchema); return true; } if(InventoryConst.ACTIONS.TRADE_ACCEPTED === data.act && '1' === data.value){ this.startExchange(client, data, room, playerSchema); return true; } if(InventoryConst.ACTIONS.TRADE_ACTION === data.act){ await this.runTradeAction(client, data, room, playerSchema); return true; } if(InventoryConst.ACTIONS.REMOVE === data.act){ playerSchema.inventory.manager.removeItem(data.idx); return true; } if(InventoryConst.ACTIONS.USE === data.act){ if(!sc.hasOwn(playerSchema.inventory.manager.items, data.idx)){ Logger.info('Cannot use item, key not found: '+data.idx); return false; } playerSchema.inventory.manager.items[data.idx].use(); } if(InventoryConst.ACTIONS.EQUIP === data.act){ return await this.executeEquipAction(playerSchema, data); } } closeTradeAction(client, data, room, playerSchema) { let ownerA = playerSchema.tradeInProgress?.inventories['A']?.owner.sessionId; let ownerB = playerSchema.tradeInProgress?.inventories['B']?.owner.sessionId; this.sendCloseUIMessage(playerSchema, ownerA, ownerB, room); playerSchema.tradeInProgress?.cancelExchange(); return true; } sendCloseUIMessage(playerSchema, ownerA, ownerB, room) { let closeOnSessionId = playerSchema.sessionId === ownerA ? ownerB : ownerA; if(!closeOnSessionId){ return; } let closeOnClient = this.fetchClientBySessionId(room, closeOnSessionId); if(!closeOnClient){ return; } closeOnClient?.send('*', {act: GameConst.CLOSE_UI_ACTION, id: 'trade' + playerSchema.sessionId}); } fetchClientBySessionId(room, sessionId) { return room.activePlayerBySessionId(sessionId, room.roomId)?.client; } tryExchangeStart(client, data, room, playerSchema) { if(playerSchema.sessionId === data.id){ Logger.info('The player is trying to trade with himself.', playerSchema.sessionId, data); return false; } if(playerSchema.tradeInProgress){ playerSchema.tradeInProgress.cancelExchange(); } playerSchema.tradeInProgress = new ExchangePlatform({ events: room.events, exchangeInitializerId: playerSchema.sessionId }); let toPlayerClient = this.fetchClientBySessionId(room, data.id); if(!toPlayerClient){ Logger.error('Player client not found.', toPlayerClient, data); return false; } let sendData = { act: InventoryConst.ACTIONS.TRADE_START, listener: 'trade', from: playerSchema.playerName, id: playerSchema.sessionId, }; let awaitTrade = room.config.get('client/trade/players/awaitTimeOut', true); if(awaitTrade){ setTimeout(() => { if(playerSchema.tradeInProgress?.inventories?.A && playerSchema.tradeInProgress?.inventories?.B){ return true; } playerSchema.tradeInProgress.cancelExchange(); return false; }, room.config.get('client/trade/players/timeOut', 5000)); } toPlayerClient.send('*', sendData); } isMyTrade(playerSchema) { return playerSchema.tradeInProgress.exchangeInitializerId === playerSchema.sessionId; } startExchange(client, data, room, playerSchema) { let exchangeStarterClient = this.fetchExchangeStarterClient(room, data); if(!exchangeStarterClient){ Logger.warning('Missing starter client to start exchange. Session ID: '+data.id); return false; } let exchangeStarterPlayer = room.state.players[data.id]; if(!exchangeStarterPlayer){ Logger.warning( 'Start exchange error, starter player is not in the room anymore. Session ID: '+data.id, exchangeStarterPlayer ); return false; } exchangeStarterPlayer.tradeInProgress.initializeExchangeBetween({ inventoryA: exchangeStarterPlayer.inventory.manager, inventoryB: playerSchema.inventory.manager }); // both players will use the same exchange platform instance, if one cancel the request the other will get it: playerSchema.tradeInProgress = exchangeStarterPlayer.tradeInProgress; // both players require the data: this.sendExchangeUpdate(exchangeStarterPlayer, playerSchema, exchangeStarterClient); this.sendExchangeUpdate(playerSchema, exchangeStarterPlayer, client); } async runTradeAction(client, data, room, playerSchema) { let subActionParam = sc.get(data, ObjectsConst.TRADE_ACTIONS.SUB_ACTION, false); let mappedSubAction = this.mapSubAction(subActionParam); let functionExists = sc.isFunction(PlayerProcessor[mappedSubAction]); if(false === mappedSubAction || !functionExists){ Logger.critical('Missing mapped sub-action: "'+(mappedSubAction || 'false')+'".', {functionExists}); return false; } let inventoryKey = this.isMyTrade(playerSchema) ? 'A' : 'B'; let subActionResult = await PlayerProcessor[mappedSubAction]({ transaction: playerSchema.tradeInProgress, data, inventoryKey }); if(false === subActionResult && ObjectsConst.TRADE_ACTIONS.CONFIRM !== data.sub){ Logger.error('Exchange sub-action error.', playerSchema.tradeInProgress.lastError.message); return false; } let exchangeStarterClient = this.fetchExchangeStarterClient(room, data); if(!exchangeStarterClient){ Logger.error('Missing starter player client to run trade. Session ID: '+ data.id); return false; } let exchangeStarterPlayer = room.state.players[data.id]; if(!exchangeStarterPlayer){ Logger.error( 'Run trade error, starter player is not in the room anymore. Session ID: '+ data.id, exchangeStarterPlayer ); return false; } this.sendExchangeUpdate(exchangeStarterPlayer, playerSchema, exchangeStarterClient); this.sendExchangeUpdate(playerSchema, exchangeStarterPlayer, client); } fetchExchangeStarterClient(room, data) { return room.activePlayerBySessionId(data.id, room.roomId)?.client; } mapSubAction(subAction) { if(false === subAction || '' === subAction){ return false; } let map = {}; map[ObjectsConst.TRADE_ACTIONS.ADD] = ObjectsConst.TRADE_ACTIONS_FUNCTION_NAME.ADD; map[ObjectsConst.TRADE_ACTIONS.REMOVE] = ObjectsConst.TRADE_ACTIONS_FUNCTION_NAME.REMOVE; map[ObjectsConst.TRADE_ACTIONS.CONFIRM] = ObjectsConst.TRADE_ACTIONS_FUNCTION_NAME.CONFIRM; map[ObjectsConst.TRADE_ACTIONS.DISCONFIRM] = ObjectsConst.TRADE_ACTIONS_FUNCTION_NAME.DISCONFIRM; return sc.get(map, subAction, false); } sendExchangeUpdate(playerOwner, playerTo, playerToClient) { // @TODO - BETA - Refactor when include false conditions in the shortcuts and include a new property "tradable". let fromInventoryItems = [ ...(playerOwner.inventory.manager.findItemsByPropertyValue('equipped', false) || []), ...(playerOwner.inventory.manager.findItemsByPropertyValue('equipped', undefined) || []) ]; // the exchange key required for the items list is the opposite of the player inventory: let tradeInProgress = playerOwner.tradeInProgress; if(!tradeInProgress){ Logger.critical('Trade not longer in progress.'); return false; } let ownerSessionId = tradeInProgress.inventories['A']?.owner?.sessionId; if(!ownerSessionId){ Logger.critical('Trade owner unavailable.'); return false; } let playerToExchangeKey = ownerSessionId === playerTo.sessionId ? 'A' : 'B'; let traderItemsData = this.extractExchangeItemsDataFromInventory( playerToExchangeKey, tradeInProgress ); let playerConfirmed = tradeInProgress.confirmations[playerToExchangeKey]; let sendData = { act: InventoryConst.ACTIONS.TRADE_SHOW, listener: 'trade', with: playerTo.playerName, id: playerTo.sessionId, playerConfirmed: playerConfirmed, isTradeEnd: (tradeInProgress.confirmations['A'] && tradeInProgress.confirmations['B']), playerToExchangeKey, exchangeData: tradeInProgress.exchangeBetween, items: playerOwner.inventory.client.extractItemsDataForSend(fromInventoryItems), traderItemsData }; playerToClient.send('*', sendData); } extractExchangeItemsDataFromInventory(playerToExchangeKey, tradeInProgress) { let exchangeItems = tradeInProgress.exchangeBetween[playerToExchangeKey]; let exchangeItemsKeys = Object.keys(exchangeItems); if(0 === exchangeItemsKeys.length){ return {}; } let tradeItemsData = {}; let inventoryItems = tradeInProgress.inventories[playerToExchangeKey].items; for(let i of exchangeItemsKeys){ let itemData = inventoryItems[i]; if(!itemData){ Logger.error('Missing item data on inventory.', i, Object.keys(inventoryItems)); continue; } tradeItemsData[i] = { key: itemData.key, label: itemData.label, qty: itemData.qty, }; } return tradeItemsData; } async executeEquipAction(playerSchema, data) { // @TODO - BETA - This is temporal since for now we are only allowing one item per group. In the future // we will use inventory groups properly on the server side to validate if the item can be equipped // checking the group items limit (this also would help to avoid looping on all the items). let item = playerSchema.inventory.manager.items[data.idx]; if(!item.equipped){ this.unEquipPrevious(item.group_id, playerSchema.inventory.manager.items); await item.equip(); return true; } await item.unequip(); return true; } unEquipPrevious(groupId, itemsList) { for(let i of Object.keys(itemsList)){ let item = itemsList[i]; if(item.group_id === groupId && item.equipped){ item.unequip(); break; } } } } module.exports.InventoryMessageActions = InventoryMessageActions;