Java tutorial
/* * 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); } }