lineage2.gameserver.instancemanager.CursedWeaponsManager.java Source code

Java tutorial

Introduction

Here is the source code for lineage2.gameserver.instancemanager.CursedWeaponsManager.java

Source

/*
 * This program 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.
 *
 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
 */
package lineage2.gameserver.instancemanager;

import gnu.trove.map.hash.TIntObjectHashMap;

import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.ScheduledFuture;

import javax.xml.parsers.DocumentBuilderFactory;

import lineage2.commons.dbutils.DbUtils;
import lineage2.commons.threading.RunnableImpl;
import lineage2.commons.util.Rnd;
import lineage2.gameserver.Config;
import lineage2.gameserver.ThreadPoolManager;
import lineage2.gameserver.data.xml.holder.ItemHolder;
import lineage2.gameserver.database.DatabaseFactory;
import lineage2.gameserver.model.CursedWeapon;
import lineage2.gameserver.model.GameObjectsStorage;
import lineage2.gameserver.model.Player;
import lineage2.gameserver.model.instances.NpcInstance;
import lineage2.gameserver.model.items.ItemInstance;
import lineage2.gameserver.network.serverpackets.SystemMessage;
import lineage2.gameserver.tables.SkillTable;
import lineage2.gameserver.utils.Location;

import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
 * @author Mobius
 * @version $Revision: 1.0 $
 */
public class CursedWeaponsManager {
    /**
     * Field _log.
     */
    private static final Logger _log = LoggerFactory.getLogger(CursedWeaponsManager.class);
    /**
     * Field _instance.
     */
    private static final CursedWeaponsManager _instance = new CursedWeaponsManager();

    /**
     * Method getInstance.
     * @return CursedWeaponsManager
     */
    public static CursedWeaponsManager getInstance() {
        return _instance;
    }

    /**
     * Field _cursedWeapons.
     */
    CursedWeapon[] _cursedWeapons;
    /**
     * Field _cursedWeaponsMap.
     */
    private TIntObjectHashMap<CursedWeapon> _cursedWeaponsMap;
    /**
     * Field _removeTask.
     */
    private ScheduledFuture<?> _removeTask;
    /**
     * Field CURSEDWEAPONS_MAINTENANCE_INTERVAL.
     */
    private static final int CURSEDWEAPONS_MAINTENANCE_INTERVAL = 5 * 60 * 1000;

    /**
     * Constructor for CursedWeaponsManager.
     */
    public CursedWeaponsManager() {
        _cursedWeaponsMap = new TIntObjectHashMap<>();
        _cursedWeapons = new CursedWeapon[0];
        if (!Config.ALLOW_CURSED_WEAPONS) {
            return;
        }
        load();
        restore();
        checkConditions();
        cancelTask();
        _removeTask = ThreadPoolManager.getInstance().scheduleAtFixedRate(new RemoveTask(),
                CURSEDWEAPONS_MAINTENANCE_INTERVAL, CURSEDWEAPONS_MAINTENANCE_INTERVAL);
        _log.info("CursedWeaponsManager: Loaded " + _cursedWeapons.length + " cursed weapon(s).");
    }

    /**
     * Method load.
     */
    private void load() {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setValidating(false);
            factory.setIgnoringComments(true);
            File file = new File(Config.DATAPACK_ROOT, "data/xml/other/cursed_weapons.xml");
            if (!file.exists()) {
                return;
            }
            Document doc = factory.newDocumentBuilder().parse(file);
            for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling()) {
                if ("list".equalsIgnoreCase(n.getNodeName())) {
                    for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) {
                        if ("item".equalsIgnoreCase(d.getNodeName())) {
                            NamedNodeMap attrs = d.getAttributes();
                            int id = Integer.parseInt(attrs.getNamedItem("id").getNodeValue());
                            int skillId = Integer.parseInt(attrs.getNamedItem("skillId").getNodeValue());
                            String name = "Unknown cursed weapon";
                            if (attrs.getNamedItem("name") != null) {
                                name = attrs.getNamedItem("name").getNodeValue();
                            } else if (ItemHolder.getInstance().getTemplate(id) != null) {
                                name = ItemHolder.getInstance().getTemplate(id).getName();
                            }
                            if (id == 0) {
                                continue;
                            }
                            CursedWeapon cw = new CursedWeapon(id, skillId, name);
                            for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling()) {
                                if ("dropRate".equalsIgnoreCase(cd.getNodeName())) {
                                    cw.setDropRate(Integer
                                            .parseInt(cd.getAttributes().getNamedItem("val").getNodeValue()));
                                } else if ("duration".equalsIgnoreCase(cd.getNodeName())) {
                                    attrs = cd.getAttributes();
                                    cw.setDurationMin(Integer.parseInt(attrs.getNamedItem("min").getNodeValue()));
                                    cw.setDurationMax(Integer.parseInt(attrs.getNamedItem("max").getNodeValue()));
                                } else if ("durationLost".equalsIgnoreCase(cd.getNodeName())) {
                                    cw.setDurationLost(Integer
                                            .parseInt(cd.getAttributes().getNamedItem("val").getNodeValue()));
                                } else if ("disapearChance".equalsIgnoreCase(cd.getNodeName())) {
                                    cw.setDisapearChance(Integer
                                            .parseInt(cd.getAttributes().getNamedItem("val").getNodeValue()));
                                } else if ("stageKills".equalsIgnoreCase(cd.getNodeName())) {
                                    cw.setStageKills(Integer
                                            .parseInt(cd.getAttributes().getNamedItem("val").getNodeValue()));
                                } else if ("transformationId".equalsIgnoreCase(cd.getNodeName())) {
                                    cw.setTransformationId(Integer
                                            .parseInt(cd.getAttributes().getNamedItem("val").getNodeValue()));
                                } else if ("transformationTemplateId".equalsIgnoreCase(cd.getNodeName())) {
                                    cw.setTransformationTemplateId(Integer
                                            .parseInt(cd.getAttributes().getNamedItem("val").getNodeValue()));
                                } else if ("transformationName".equalsIgnoreCase(cd.getNodeName())) {
                                    cw.setTransformationName(cd.getAttributes().getNamedItem("val").getNodeValue());
                                }
                            }
                            _cursedWeaponsMap.put(id, cw);
                        }
                    }
                }
            }
            _cursedWeapons = _cursedWeaponsMap.values(new CursedWeapon[_cursedWeaponsMap.size()]);
        } catch (Exception e) {
            _log.error("CursedWeaponsManager: Error parsing cursed_weapons file. " + e);
        }
    }

    /**
     * Method restore.
     */
    private void restore() {
        Connection con = null;
        PreparedStatement statement = null;
        ResultSet rset = null;
        try {
            con = DatabaseFactory.getInstance().getConnection();
            statement = con.prepareStatement("SELECT * FROM cursed_weapons");
            rset = statement.executeQuery();
            while (rset.next()) {
                int itemId = rset.getInt("item_id");
                CursedWeapon cw = _cursedWeaponsMap.get(itemId);
                if (cw != null) {
                    cw.setPlayerId(rset.getInt("player_id"));
                    cw.setPlayerKarma(rset.getInt("player_karma"));
                    cw.setPlayerPkKills(rset.getInt("player_pkkills"));
                    cw.setNbKills(rset.getInt("nb_kills"));
                    cw.setLoc(new Location(rset.getInt("x"), rset.getInt("y"), rset.getInt("z")));
                    cw.setEndTime(rset.getLong("end_time") * 1000L);
                    if (!cw.reActivate()) {
                        endOfLife(cw);
                    }
                } else {
                    removeFromDb(itemId);
                    _log.warn("CursedWeaponsManager: Unknown cursed weapon " + itemId + ", deleted");
                }
            }
        } catch (Exception e) {
            _log.warn("CursedWeaponsManager: Could not restore cursed_weapons data: " + e);
            _log.error("", e);
        } finally {
            DbUtils.closeQuietly(con, statement, rset);
        }
    }

    /**
     * Method checkConditions.
     */
    private void checkConditions() {
        Connection con = null;
        PreparedStatement statement1 = null, statement2 = null;
        ResultSet rset = null;
        try {
            con = DatabaseFactory.getInstance().getConnection();
            statement1 = con.prepareStatement("DELETE FROM character_skills WHERE skill_id=?");
            statement2 = con.prepareStatement("SELECT owner_id FROM items WHERE item_id=?");
            for (CursedWeapon cw : _cursedWeapons) {
                int itemId = cw.getItemId();
                int skillId = cw.getSkillId();
                boolean foundedInItems = false;
                statement1.setInt(1, skillId);
                statement1.executeUpdate();
                statement2.setInt(1, itemId);
                rset = statement2.executeQuery();
                while (rset.next()) {
                    int playerId = rset.getInt("owner_id");
                    if (!foundedInItems) {
                        if ((playerId != cw.getPlayerId()) || (cw.getPlayerId() == 0)) {
                            emptyPlayerCursedWeapon(playerId, itemId, cw);
                            _log.info("CursedWeaponsManager[254]: Player " + playerId + " owns the cursed weapon "
                                    + itemId + " but he shouldn't.");
                        } else {
                            foundedInItems = true;
                        }
                    } else {
                        emptyPlayerCursedWeapon(playerId, itemId, cw);
                        _log.info("CursedWeaponsManager[262]: Player " + playerId + " owns the cursed weapon "
                                + itemId + " but he shouldn't.");
                    }
                }
                if (!foundedInItems && (cw.getPlayerId() != 0)) {
                    removeFromDb(cw.getItemId());
                    _log.info("CursedWeaponsManager: Unownered weapon, removing from table...");
                }
            }
        } catch (Exception e) {
            _log.warn("CursedWeaponsManager: Could not check cursed_weapons data: " + e);
        } finally {
            DbUtils.closeQuietly(statement1);
            DbUtils.closeQuietly(con, statement2, rset);
        }
    }

    /**
     * Method emptyPlayerCursedWeapon.
     * @param playerId int
     * @param itemId int
     * @param cw CursedWeapon
     */
    private void emptyPlayerCursedWeapon(int playerId, int itemId, CursedWeapon cw) {
        Connection con = null;
        PreparedStatement statement = null;
        try {
            con = DatabaseFactory.getInstance().getConnection();
            statement = con.prepareStatement("DELETE FROM items WHERE owner_id=? AND item_id=?");
            statement.setInt(1, playerId);
            statement.setInt(2, itemId);
            statement.executeUpdate();
            DbUtils.close(statement);
            statement = con.prepareStatement("UPDATE characters SET karma=?, pkkills=? WHERE obj_id=?");
            statement.setInt(1, cw.getPlayerKarma());
            statement.setInt(2, cw.getPlayerPkKills());
            statement.setInt(3, playerId);
            if (statement.executeUpdate() != 1) {
                _log.warn("Error while updating karma & pkkills for userId " + cw.getPlayerId());
            }
            removeFromDb(itemId);
        } catch (SQLException e) {
            _log.error("", e);
        } finally {
            DbUtils.closeQuietly(con, statement);
        }
    }

    /**
     * Method removeFromDb.
     * @param itemId int
     */
    public void removeFromDb(int itemId) {
        Connection con = null;
        PreparedStatement statement = null;
        try {
            con = DatabaseFactory.getInstance().getConnection();
            statement = con.prepareStatement("DELETE FROM cursed_weapons WHERE item_id = ?");
            statement.setInt(1, itemId);
            statement.executeUpdate();
            if (getCursedWeapon(itemId) != null) {
                getCursedWeapon(itemId).initWeapon();
            }
        } catch (SQLException e) {
            _log.error("CursedWeaponsManager: Failed to remove data: " + e);
        } finally {
            DbUtils.closeQuietly(con, statement);
        }
    }

    /**
     * Method cancelTask.
     */
    private void cancelTask() {
        if (_removeTask != null) {
            _removeTask.cancel(false);
            _removeTask = null;
        }
    }

    /**
     * @author Mobius
     */
    private class RemoveTask extends RunnableImpl {
        /**
         * Constructor for RemoveTask.
         */
        public RemoveTask() {
            // TODO Auto-generated constructor stub
        }

        /**
         * Method runImpl.
         */
        @Override
        public void runImpl() {
            for (CursedWeapon cw : _cursedWeapons) {
                if (cw.isActive() && (cw.getTimeLeft() <= 0)) {
                    endOfLife(cw);
                }
            }
        }
    }

    /**
     * Method endOfLife.
     * @param cw CursedWeapon
     */
    public void endOfLife(CursedWeapon cw) {
        if (cw.isActivated()) {
            Player player = cw.getOnlineOwner();
            if (player != null) {
                _log.info("CursedWeaponsManager: " + cw.getName() + " being removed online from " + player + ".");
                player.abortAttack(true, true);
                player.setKarma(cw.getPlayerKarma());
                player.setPkKills(cw.getPlayerPkKills());
                player.setCursedWeaponEquippedId(0);
                player.setTransformation(0);
                player.setTransformationName(null);
                player.removeSkill(
                        SkillTable.getInstance().getInfo(cw.getSkillId(), player.getSkillLevel(cw.getSkillId())),
                        false);
                player.getInventory().destroyItemByItemId(cw.getItemId(), 1L);
                player.broadcastCharInfo();
            } else {
                _log.info("CursedWeaponsManager: " + cw.getName() + " being removed offline.");
                Connection con = null;
                PreparedStatement statement = null;
                try {
                    con = DatabaseFactory.getInstance().getConnection();
                    statement = con.prepareStatement("DELETE FROM items WHERE owner_id=? AND item_id=?");
                    statement.setInt(1, cw.getPlayerId());
                    statement.setInt(2, cw.getItemId());
                    statement.executeUpdate();
                    DbUtils.close(statement);
                    statement = con
                            .prepareStatement("DELETE FROM character_skills WHERE char_obj_id=? AND skill_id=?");
                    statement.setInt(1, cw.getPlayerId());
                    statement.setInt(2, cw.getSkillId());
                    statement.executeUpdate();
                    DbUtils.close(statement);
                    statement = con.prepareStatement("UPDATE characters SET karma=?, pkkills=? WHERE obj_Id=?");
                    statement.setInt(1, cw.getPlayerKarma());
                    statement.setInt(2, cw.getPlayerPkKills());
                    statement.setInt(3, cw.getPlayerId());
                    statement.executeUpdate();
                } catch (SQLException e) {
                    _log.warn("CursedWeaponsManager: Could not delete : " + e);
                } finally {
                    DbUtils.closeQuietly(con, statement);
                }
            }
        } else if ((cw.getPlayer() != null)
                && (cw.getPlayer().getInventory().getItemByItemId(cw.getItemId()) != null)) {
            Player player = cw.getPlayer();
            if (!cw.getPlayer().getInventory().destroyItemByItemId(cw.getItemId(), 1)) {
                _log.info("CursedWeaponsManager[453]: Error! Cursed weapon not found!!!");
            }
            player.sendChanges();
            player.broadcastUserInfo();
        } else if (cw.getItem() != null) {
            cw.getItem().deleteMe();
            cw.getItem().delete();
            _log.info("CursedWeaponsManager: " + cw.getName() + " item has been removed from World.");
        }
        cw.initWeapon();
        removeFromDb(cw.getItemId());
        announce(new SystemMessage(SystemMessage.S1_HAS_DISAPPEARED_CW).addString(cw.getName()));
    }

    /**
     * Method saveData.
     * @param cw CursedWeapon
     */
    public void saveData(CursedWeapon cw) {
        Connection con = null;
        PreparedStatement statement = null;
        try {
            con = DatabaseFactory.getInstance().getConnection();
            statement = con.prepareStatement("DELETE FROM cursed_weapons WHERE item_id = ?");
            statement.setInt(1, cw.getItemId());
            statement.executeUpdate();
            if (cw.isActive()) {
                DbUtils.close(statement);
                statement = con.prepareStatement(
                        "REPLACE INTO cursed_weapons (item_id, player_id, player_karma, player_pkkills, nb_kills, x, y, z, end_time) VALUES (?,?,?,?,?,?,?,?,?)");
                statement.setInt(1, cw.getItemId());
                statement.setInt(2, cw.getPlayerId());
                statement.setInt(3, cw.getPlayerKarma());
                statement.setInt(4, cw.getPlayerPkKills());
                statement.setInt(5, cw.getNbKills());
                statement.setInt(6, cw.getLoc().x);
                statement.setInt(7, cw.getLoc().y);
                statement.setInt(8, cw.getLoc().z);
                statement.setLong(9, cw.getEndTime() / 1000);
                statement.executeUpdate();
            }
        } catch (SQLException e) {
            _log.error("CursedWeapon: Failed to save data: " + e);
        } finally {
            DbUtils.closeQuietly(con, statement);
        }
    }

    /**
     * Method saveData.
     */
    public void saveData() {
        for (CursedWeapon cw : _cursedWeapons) {
            saveData(cw);
        }
    }

    /**
     * Method checkPlayer.
     * @param player Player
     * @param item ItemInstance
     */
    public void checkPlayer(Player player, ItemInstance item) {
        if ((player == null) || (item == null) || player.isInOlympiadMode()) {
            return;
        }
        CursedWeapon cw = _cursedWeaponsMap.get(item.getItemId());
        if (cw == null) {
            return;
        }
        if ((player.getObjectId() == cw.getPlayerId()) || (cw.getPlayerId() == 0) || cw.isDropped()) {
            activate(player, item);
            showUsageTime(player, cw);
        } else {
            _log.warn("CursedWeaponsManager: " + player + " tried to obtain " + item + " in wrong way");
            player.getInventory().destroyItem(item, item.getCount());
        }
    }

    /**
     * Method activate.
     * @param player Player
     * @param item ItemInstance
     */
    public void activate(Player player, ItemInstance item) {
        if ((player == null) || player.isInOlympiadMode()) {
            return;
        }
        CursedWeapon cw = _cursedWeaponsMap.get(item.getItemId());
        if (cw == null) {
            return;
        }
        if (player.isCursedWeaponEquipped()) {
            if (player.getCursedWeaponEquippedId() != item.getItemId()) {
                CursedWeapon cw2 = _cursedWeaponsMap.get(player.getCursedWeaponEquippedId());
                cw2.setNbKills(cw2.getStageKills() - 1);
                cw2.increaseKills();
            }
            endOfLife(cw);
            player.getInventory().destroyItem(item, 1);
        } else if (cw.getTimeLeft() > 0) {
            cw.activate(player, item);
            saveData(cw);
            announce(new SystemMessage(SystemMessage.THE_OWNER_OF_S2_HAS_APPEARED_IN_THE_S1_REGION)
                    .addZoneName(player.getLoc()).addString(cw.getName()));
        } else {
            endOfLife(cw);
            player.getInventory().destroyItem(item, 1);
        }
    }

    /**
     * Method doLogout.
     * @param player Player
     */
    public void doLogout(Player player) {
        for (CursedWeapon cw : _cursedWeapons) {
            if (player.getInventory().getItemByItemId(cw.getItemId()) != null) {
                cw.setPlayer(null);
                cw.setItem(null);
            }
        }
    }

    /**
     * Method dropAttackable.
     * @param attackable NpcInstance
     * @param killer Player
     */
    public void dropAttackable(NpcInstance attackable, Player killer) {
        if (killer.isInOlympiadMode() || killer.isCursedWeaponEquipped() || (_cursedWeapons.length == 0)
                || (killer.getReflection() != ReflectionManager.DEFAULT)) {
            return;
        }
        synchronized (_cursedWeapons) {
            CursedWeapon[] cursedWeapons = new CursedWeapon[0];
            for (CursedWeapon cw : _cursedWeapons) {
                if (cw.isActive()) {
                    continue;
                }
                cursedWeapons = ArrayUtils.add(cursedWeapons, cw);
            }
            if (cursedWeapons.length > 0) {
                CursedWeapon cw = cursedWeapons[Rnd.get(cursedWeapons.length)];
                if (Rnd.get(100000000) <= cw.getDropRate()) {
                    cw.create(attackable, killer);
                }
            }
        }
    }

    /**
     * Method dropPlayer.
     * @param player Player
     */
    public void dropPlayer(Player player) {
        CursedWeapon cw = _cursedWeaponsMap.get(player.getCursedWeaponEquippedId());
        if (cw == null) {
            return;
        }
        if (cw.dropIt(null, null, player)) {
            saveData(cw);
            announce(new SystemMessage(SystemMessage.S2_WAS_DROPPED_IN_THE_S1_REGION).addZoneName(player.getLoc())
                    .addItemName(cw.getItemId()));
        } else {
            endOfLife(cw);
        }
    }

    /**
     * Method increaseKills.
     * @param itemId int
     */
    public void increaseKills(int itemId) {
        CursedWeapon cw = _cursedWeaponsMap.get(itemId);
        if (cw != null) {
            cw.increaseKills();
            saveData(cw);
        }
    }

    /**
     * Method getLevel.
     * @param itemId int
     * @return int
     */
    public int getLevel(int itemId) {
        CursedWeapon cw = _cursedWeaponsMap.get(itemId);
        return cw != null ? cw.getLevel() : 0;
    }

    /**
     * Method announce.
     * @param sm SystemMessage
     */
    public void announce(SystemMessage sm) {
        for (Player player : GameObjectsStorage.getAllPlayersForIterate()) {
            player.sendPacket(sm);
        }
    }

    /**
     * Method showUsageTime.
     * @param player Player
     * @param itemId int
     */
    public void showUsageTime(Player player, int itemId) {
        CursedWeapon cw = _cursedWeaponsMap.get(itemId);
        if (cw != null) {
            showUsageTime(player, cw);
        }
    }

    /**
     * Method showUsageTime.
     * @param player Player
     * @param cw CursedWeapon
     */
    public void showUsageTime(Player player, CursedWeapon cw) {
        SystemMessage sm = new SystemMessage(SystemMessage.S2_MINUTE_OF_USAGE_TIME_ARE_LEFT_FOR_S1);
        sm.addString(cw.getName());
        sm.addNumber(new Long(cw.getTimeLeft() / 60000).intValue());
        player.sendPacket(sm);
    }

    /**
     * Method isCursed.
     * @param itemId int
     * @return boolean
     */
    public boolean isCursed(int itemId) {
        return _cursedWeaponsMap.containsKey(itemId);
    }

    /**
     * Method getCursedWeapons.
     * @return CursedWeapon[]
     */
    public CursedWeapon[] getCursedWeapons() {
        return _cursedWeapons;
    }

    /**
     * Method getCursedWeaponsIds.
     * @return int[]
     */
    public int[] getCursedWeaponsIds() {
        return _cursedWeaponsMap.keys();
    }

    /**
     * Method getCursedWeapon.
     * @param itemId int
     * @return CursedWeapon
     */
    public CursedWeapon getCursedWeapon(int itemId) {
        return _cursedWeaponsMap.get(itemId);
    }
}