com.aionemu.gameserver.services.BrokerService.java Source code

Java tutorial

Introduction

Here is the source code for com.aionemu.gameserver.services.BrokerService.java

Source

/*
 * This file is part of aion-unique <aion-unique.org>.
 *
 *  aion-unique is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  aion-unique is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with aion-unique.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionemu.gameserver.services;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javolution.util.FastMap;

import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;

import com.aionemu.commons.database.dao.DAOManager;
import com.aionemu.gameserver.dao.BrokerDAO;
import com.aionemu.gameserver.model.Race;
import com.aionemu.gameserver.model.broker.BrokerItemMask;
import com.aionemu.gameserver.model.broker.BrokerMessages;
import com.aionemu.gameserver.model.broker.BrokerPlayerCache;
import com.aionemu.gameserver.model.broker.BrokerRace;
import com.aionemu.gameserver.model.gameobjects.BrokerItem;
import com.aionemu.gameserver.model.gameobjects.Item;
import com.aionemu.gameserver.model.gameobjects.PersistentState;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.network.aion.serverpackets.SM_ADD_ITEMS;
import com.aionemu.gameserver.network.aion.serverpackets.SM_BROKER_ITEMS;
import com.aionemu.gameserver.network.aion.serverpackets.SM_BROKER_REGISTERED_LIST;
import com.aionemu.gameserver.network.aion.serverpackets.SM_BROKER_REGISTRATION_SERVICE;
import com.aionemu.gameserver.network.aion.serverpackets.SM_BROKER_SETTLED_LIST;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.taskmanager.AbstractFIFOPeriodicTaskManager;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.World;

/**
 * @author kosyachok
 * @author ATracer
 * 
 */
public class BrokerService {
    private Map<Integer, BrokerItem> elyosBrokerItems = new FastMap<Integer, BrokerItem>().shared();
    private Map<Integer, BrokerItem> elyosSettledItems = new FastMap<Integer, BrokerItem>().shared();
    private Map<Integer, BrokerItem> asmodianBrokerItems = new FastMap<Integer, BrokerItem>().shared();
    private Map<Integer, BrokerItem> asmodianSettledItems = new FastMap<Integer, BrokerItem>().shared();

    private static final Logger log = Logger.getLogger(BrokerService.class);

    private final int DELAY_BROKER_SAVE = 6000;
    private final int DELAY_BROKER_CHECK = 60000;

    private BrokerPeriodicTaskManager saveManager;

    private Map<Integer, BrokerPlayerCache> playerBrokerCache = new FastMap<Integer, BrokerPlayerCache>().shared();

    public static final BrokerService getInstance() {
        return SingletonHolder.instance;
    }

    public BrokerService() {
        initBrokerService();

        saveManager = new BrokerPeriodicTaskManager(DELAY_BROKER_SAVE);
        ThreadPoolManager.getInstance().scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                checkExpiredItems();
            }
        }, DELAY_BROKER_CHECK, DELAY_BROKER_CHECK);
    }

    private void initBrokerService() {
        log.info("Loading broker...");
        int loadedBrokerItemsCount = 0;
        int loadedSettledItemsCount = 0;

        List<BrokerItem> brokerItems = DAOManager.getDAO(BrokerDAO.class).loadBroker();

        for (BrokerItem item : brokerItems) {
            if (item.getItemBrokerRace() == BrokerRace.ASMODIAN) {
                if (item.isSettled()) {
                    asmodianSettledItems.put(item.getItemUniqueId(), item);
                    loadedSettledItemsCount++;
                } else {
                    asmodianBrokerItems.put(item.getItemUniqueId(), item);
                    loadedBrokerItemsCount++;
                }
            } else if (item.getItemBrokerRace() == BrokerRace.ELYOS) {
                if (item.isSettled()) {
                    elyosSettledItems.put(item.getItemUniqueId(), item);
                    loadedSettledItemsCount++;
                } else {
                    elyosBrokerItems.put(item.getItemUniqueId(), item);
                    loadedBrokerItemsCount++;
                }
            }
        }

        log.info("Broker loaded with " + loadedBrokerItemsCount + " broker items, " + loadedSettledItemsCount
                + " settled items.");
    }

    /**
     * 
     * @param player
     * @param clientMask
     * @param sortType
     * @param startPage
     */
    public void showRequestedItems(Player player, int clientMask, int sortType, int startPage) {
        BrokerItem[] searchItems = null;
        int playerBrokerMaskCache = getPlayerMask(player);
        BrokerItemMask brokerMaskById = BrokerItemMask.getBrokerMaskById(clientMask);
        boolean isChidrenMask = brokerMaskById.isChildrenMask(playerBrokerMaskCache);
        if (getFilteredItems(player).length == 0 || !isChidrenMask) {
            searchItems = getItemsByMask(player, clientMask, false);
        } else if (isChidrenMask) {
            searchItems = getItemsByMask(player, clientMask, true);
        } else
            searchItems = getFilteredItems(player);

        if (searchItems == null || searchItems.length < 0)
            return;

        int totalSearchItemsCount = searchItems.length;

        getPlayerCache(player).setBrokerSortTypeCache(sortType);
        getPlayerCache(player).setBrokerStartPageCache(startPage);

        sortBrokerItems(searchItems, sortType);
        searchItems = getRequestedPage(searchItems, startPage);

        PacketSendUtility.sendPacket(player, new SM_BROKER_ITEMS(searchItems, totalSearchItemsCount, startPage));
    }

    /**
     * 
     * @param player
     * @param clientMask
     * @return
     */
    private BrokerItem[] getItemsByMask(Player player, int clientMask, boolean cached) {
        List<BrokerItem> searchItems = new ArrayList<BrokerItem>();

        BrokerItemMask brokerMask = BrokerItemMask.getBrokerMaskById(clientMask);

        if (cached) {
            BrokerItem[] brokerItems = getFilteredItems(player);
            if (brokerItems == null)
                return null;

            for (BrokerItem item : brokerItems) {
                if (item == null || item.getItem() == null)
                    continue;

                if (brokerMask.isMatches(item.getItem())) {
                    searchItems.add(item);
                }
            }
        } else {
            Map<Integer, BrokerItem> brokerItems = getRaceBrokerItems(player.getCommonData().getRace());
            if (brokerItems == null)
                return null;
            for (BrokerItem item : brokerItems.values()) {
                if (item == null || item.getItem() == null)
                    continue;

                if (brokerMask.isMatches(item.getItem())) {
                    searchItems.add(item);
                }
            }
        }

        BrokerItem[] items = searchItems.toArray(new BrokerItem[searchItems.size()]);
        getPlayerCache(player).setBrokerListCache(items);
        getPlayerCache(player).setBrokerMaskCache(clientMask);

        return items;
    }

    /**
     * Perform sorting according to sort type
     * 
     * @param brokerItems
     * @param sortType
     */
    private void sortBrokerItems(BrokerItem[] brokerItems, int sortType) {
        Arrays.sort(brokerItems, BrokerItem.getComparatoryByType(sortType));
    }

    /**
     * 
     * @param brokerItems
     * @param startPage
     * @return
     */
    private BrokerItem[] getRequestedPage(BrokerItem[] brokerItems, int startPage) {
        List<BrokerItem> page = new ArrayList<BrokerItem>();
        int startingElement = startPage * 9;

        for (int i = startingElement, limit = 0; i < brokerItems.length && limit < 45; i++, limit++) {
            page.add(brokerItems[i]);
        }

        return page.toArray(new BrokerItem[page.size()]);
    }

    /**
     * 
     * @param race
     * @return
     */
    private Map<Integer, BrokerItem> getRaceBrokerItems(Race race) {
        switch (race) {
        case ELYOS:
            return elyosBrokerItems;
        case ASMODIANS:
            return asmodianBrokerItems;
        default:
            return null;
        }
    }

    /**
     * 
     * @param race
     * @return
     */
    private Map<Integer, BrokerItem> getRaceBrokerSettledItems(Race race) {
        switch (race) {
        case ELYOS:
            return elyosSettledItems;
        case ASMODIANS:
            return asmodianSettledItems;
        default:
            return null;
        }
    }

    /**
     * 
     * @param player
     * @param itemUniqueId
     */
    public void buyBrokerItem(Player player, int itemUniqueId) {
        if (player.getInventory().isFull()) {
            PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.MSG_FULL_INVENTORY);
            return;
        }

        boolean isEmptyCache = getFilteredItems(player).length == 0;
        Race playerRace = player.getCommonData().getRace();

        BrokerItem buyingItem = getRaceBrokerItems(playerRace).get(itemUniqueId);

        if (buyingItem == null)
            return; // TODO: Message "this item has already been bought, refresh page please."

        Item item = buyingItem.getItem();
        long price = buyingItem.getPrice();

        if (player.getInventory().getKinahItem().getItemCount() < price)
            return;

        getRaceBrokerItems(playerRace).remove(itemUniqueId);
        putToSettled(playerRace, buyingItem, true);

        if (!isEmptyCache) {
            BrokerItem[] newCache = (BrokerItem[]) ArrayUtils.removeElement(getFilteredItems(player), buyingItem);
            getPlayerCache(player).setBrokerListCache(newCache);
        }

        ItemService.decreaseKinah(player, price);
        ItemService.addFullItem(player, player.getInventory(), item);
        // create save task
        BrokerOpSaveTask bost = new BrokerOpSaveTask(buyingItem);
        saveManager.add(bost);

        showRequestedItems(player, getPlayerCache(player).getBrokerMaskCache(),
                getPlayerCache(player).getBrokerSortTypeCache(), getPlayerCache(player).getBrokerStartPageCache());
    }

    /**
     * 
     * @param race
     * @param brokerItem
     * @param isSold
     */
    private void putToSettled(Race race, BrokerItem brokerItem, boolean isSold) {
        if (isSold)
            brokerItem.removeItem();
        else
            brokerItem.setSettled();

        brokerItem.setPersistentState(PersistentState.UPDATE_REQUIRED);

        switch (race) {
        case ASMODIANS:
            asmodianSettledItems.put(brokerItem.getItemUniqueId(), brokerItem);
            break;

        case ELYOS:
            elyosSettledItems.put(brokerItem.getItemUniqueId(), brokerItem);
            break;
        }

        Player seller = World.getInstance().findPlayer(brokerItem.getSellerId());

        saveManager.add(new BrokerOpSaveTask(brokerItem));

        if (seller != null) {
            PacketSendUtility.sendPacket(seller, new SM_BROKER_SETTLED_LIST(true));
            // TODO: Retail system message
        }
    }

    /**
     * 
     * @param player
     * @param itemUniqueId
     * @param price
     */
    public void registerItem(Player player, int itemUniqueId, int price) {
        Item itemToRegister = player.getInventory().getItemByObjId(itemUniqueId);
        Race playerRace = player.getCommonData().getRace();

        if (itemToRegister == null)
            return;

        // Check Trade Hack
        if (!itemToRegister.isTradeable())
            return;

        BrokerRace brRace;

        if (playerRace == Race.ASMODIANS)
            brRace = BrokerRace.ASMODIAN;
        else if (playerRace == Race.ELYOS)
            brRace = BrokerRace.ELYOS;
        else
            return;

        int registrationCommition = Math.round(price * 0.02f);

        if (registrationCommition < 10)
            registrationCommition = 10;

        if (player.getInventory().getKinahItem().getItemCount() < registrationCommition) {
            PacketSendUtility.sendPacket(player,
                    new SM_BROKER_REGISTRATION_SERVICE(BrokerMessages.NO_ENOUGHT_KINAH.getId()));
            return;
        }

        ItemService.decreaseKinah(player, registrationCommition);
        ItemService.removeItemFromInventory(player, itemToRegister, false);

        itemToRegister.setItemLocation(126);

        BrokerItem newBrokerItem = new BrokerItem(itemToRegister, price, player.getName(), player.getObjectId(),
                brRace);

        switch (brRace) {
        case ASMODIAN:
            asmodianBrokerItems.put(newBrokerItem.getItemUniqueId(), newBrokerItem);
            break;

        case ELYOS:
            elyosBrokerItems.put(newBrokerItem.getItemUniqueId(), newBrokerItem);
            break;
        }

        BrokerOpSaveTask bost = new BrokerOpSaveTask(newBrokerItem);
        saveManager.add(bost);

        PacketSendUtility.sendPacket(player, new SM_BROKER_REGISTRATION_SERVICE(newBrokerItem));
    }

    /**
     * 
     * @param player
     */
    public void showRegisteredItems(Player player) {
        Map<Integer, BrokerItem> brokerItems = getRaceBrokerItems(player.getCommonData().getRace());

        List<BrokerItem> registeredItems = new ArrayList<BrokerItem>();
        int playerId = player.getObjectId();

        for (BrokerItem item : brokerItems.values()) {
            if (item != null && item.getItem() != null && playerId == item.getSellerId())
                registeredItems.add(item);
        }

        PacketSendUtility.sendPacket(player, new SM_BROKER_REGISTERED_LIST(registeredItems));
    }

    /**
     * 
     * @param player
     * @param brokerItemId
     */
    public void cancelRegisteredItem(Player player, int brokerItemId) {
        Map<Integer, BrokerItem> brokerItems = getRaceBrokerItems(player.getCommonData().getRace());
        BrokerItem brokerItem = brokerItems.get(brokerItemId);

        if (brokerItem != null) {
            ItemService.addFullItem(player, player.getInventory(), brokerItem.getItem());
            brokerItem.setPersistentState(PersistentState.DELETED);
            saveManager.add(new BrokerOpSaveTask(brokerItem));
            brokerItems.remove(brokerItemId);
        }
        showRegisteredItems(player);
    }

    /**
     * 
     * @param player
     */
    public void showSettledItems(Player player) {
        Map<Integer, BrokerItem> brokerSettledItems = getRaceBrokerSettledItems(player.getCommonData().getRace());

        List<BrokerItem> settledItems = new ArrayList<BrokerItem>();

        int playerId = player.getObjectId();
        int totalKinah = 0;

        for (BrokerItem item : brokerSettledItems.values()) {
            if (item != null && playerId == item.getSellerId()) {
                settledItems.add(item);

                if (item.isSold())
                    totalKinah += item.getPrice();
            }
        }

        PacketSendUtility.sendPacket(player, new SM_BROKER_SETTLED_LIST(settledItems, totalKinah));
    }

    /**
     * 
     * @param player
     */
    public void settleAccount(Player player) {
        Race playerRace = player.getCommonData().getRace();
        Map<Integer, BrokerItem> brokerSettledItems = getRaceBrokerSettledItems(playerRace);
        List<BrokerItem> collectedItems = new ArrayList<BrokerItem>();
        int playerId = player.getObjectId();
        int kinahCollect = 0;
        boolean itemsLeft = false;

        for (BrokerItem item : brokerSettledItems.values()) {
            if (item.getSellerId() == playerId)
                collectedItems.add(item);
        }

        for (BrokerItem item : collectedItems) {
            if (item.isSold()) {
                boolean result = false;
                switch (playerRace) {
                case ASMODIANS:
                    result = asmodianSettledItems.remove(item.getItemUniqueId()) != null;
                    break;
                case ELYOS:
                    result = elyosSettledItems.remove(item.getItemUniqueId()) != null;
                    break;
                }

                if (result) {
                    item.setPersistentState(PersistentState.DELETED);
                    saveManager.add(new BrokerOpSaveTask(item));
                    kinahCollect += item.getPrice();
                }
            } else {
                if (item.getItem() != null) {
                    Item resultItem = player.getInventory().putToBag(item.getItem());
                    if (resultItem != null) {
                        boolean result = false;
                        switch (playerRace) {
                        case ASMODIANS:
                            result = asmodianSettledItems.remove(item.getItemUniqueId()) != null;
                            break;
                        case ELYOS:
                            result = elyosSettledItems.remove(item.getItemUniqueId()) != null;
                            break;
                        }

                        if (result) {
                            item.setPersistentState(PersistentState.DELETED);
                            saveManager.add(new BrokerOpSaveTask(item));
                            PacketSendUtility.sendPacket(player,
                                    new SM_ADD_ITEMS(Collections.singletonList(resultItem)));
                        }
                    } else
                        itemsLeft = true;

                } else
                    log.warn("Broker settled item missed. ObjID: " + item.getItemUniqueId());
            }
        }

        ItemService.increaseKinah(player, kinahCollect);
        showSettledItems(player);

        if (!itemsLeft)
            PacketSendUtility.sendPacket(player, new SM_BROKER_SETTLED_LIST(false));

    }

    private void checkExpiredItems() {
        Map<Integer, BrokerItem> asmoBrokerItems = getRaceBrokerItems(Race.ASMODIANS);
        Map<Integer, BrokerItem> elyosBrokerItems = getRaceBrokerItems(Race.ELYOS);

        Timestamp currentTime = new Timestamp(Calendar.getInstance().getTimeInMillis());

        for (BrokerItem item : asmoBrokerItems.values()) {
            if (item != null && item.getExpireTime().getTime() <= currentTime.getTime()) {
                putToSettled(Race.ASMODIANS, item, false);
                asmodianBrokerItems.remove(item.getItemUniqueId());
            }
        }

        for (BrokerItem item : elyosBrokerItems.values()) {
            if (item != null && item.getExpireTime().getTime() <= currentTime.getTime()) {
                putToSettled(Race.ELYOS, item, false);
                this.elyosBrokerItems.remove(item.getItemUniqueId());
            }
        }
    }

    /**
     * 
     * @param player
     */
    public void onPlayerLogin(Player player) {
        Map<Integer, BrokerItem> brokerSettledItems = getRaceBrokerSettledItems(player.getCommonData().getRace());

        int playerId = player.getObjectId();

        for (BrokerItem item : brokerSettledItems.values()) {
            if (item != null && playerId == item.getSellerId()) {
                PacketSendUtility.sendPacket(player, new SM_BROKER_SETTLED_LIST(true));
                break;
            }
        }
    }

    /**
     * 
     * @param player
     * @return
     */
    private BrokerPlayerCache getPlayerCache(Player player) {
        BrokerPlayerCache cacheEntry = playerBrokerCache.get(player.getObjectId());
        if (cacheEntry == null) {
            cacheEntry = new BrokerPlayerCache();
            playerBrokerCache.put(player.getObjectId(), cacheEntry);
        }
        return cacheEntry;
    }

    public void removePlayerCache(Player player) {
        playerBrokerCache.remove(player.getObjectId());
    }

    /**
     * 
     * @param player
     * @return
     */
    private int getPlayerMask(Player player) {
        return getPlayerCache(player).getBrokerMaskCache();
    }

    /**
     * 
     * @param player
     * @return
     */
    private BrokerItem[] getFilteredItems(Player player) {
        return getPlayerCache(player).getBrokerListCache();
    }

    /**
     * Frequent running save task
     */
    public static final class BrokerPeriodicTaskManager extends AbstractFIFOPeriodicTaskManager<BrokerOpSaveTask> {
        private static final String CALLED_METHOD_NAME = "brokerOperation()";

        /**
         * @param period
         */
        public BrokerPeriodicTaskManager(int period) {
            super(period);
        }

        @Override
        protected void callTask(BrokerOpSaveTask task) {
            task.run();
        }

        @Override
        protected String getCalledMethodName() {
            return CALLED_METHOD_NAME;
        }
    }

    /**
     * This class is used for storing all items in one shot after any broker operation
     */
    public static final class BrokerOpSaveTask implements Runnable {
        private BrokerItem brokerItem;

        /**
         * @param brokerItem
         */
        public BrokerOpSaveTask(BrokerItem brokerItem) {
            this.brokerItem = brokerItem;
        }

        @Override
        public void run() {
            if (brokerItem != null)
                DAOManager.getDAO(BrokerDAO.class).store(brokerItem);
        }
    }

    @SuppressWarnings("synthetic-access")
    private static class SingletonHolder {
        protected static final BrokerService instance = new BrokerService();
    }
}