actual freya branch
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* $Header: Broadcast.java, 18/11/2005 15:33:35 luisantonioa Exp $
|
||||
*
|
||||
* $Author: luisantonioa $
|
||||
* $Date: 18/11/2005 15:33:35 $
|
||||
* $Revision: 1 $
|
||||
* $Log: Broadcast.java,v $
|
||||
* Revision 1 18/11/2005 15:33:35 luisantonioa
|
||||
* Added copyright notice
|
||||
*
|
||||
*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jserver.Config;
|
||||
import com.l2jserver.gameserver.model.L2World;
|
||||
import com.l2jserver.gameserver.model.actor.L2Character;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jserver.gameserver.network.clientpackets.Say2;
|
||||
import com.l2jserver.gameserver.network.serverpackets.CharInfo;
|
||||
import com.l2jserver.gameserver.network.serverpackets.CreatureSay;
|
||||
import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
|
||||
import com.l2jserver.gameserver.network.serverpackets.RelationChanged;
|
||||
|
||||
/**
|
||||
* This class ...
|
||||
* @version $Revision: 1.2 $ $Date: 2004/06/27 08:12:59 $
|
||||
*/
|
||||
|
||||
public final class Broadcast
|
||||
{
|
||||
private static Logger _log = Logger.getLogger(Broadcast.class.getName());
|
||||
|
||||
/**
|
||||
* Send a packet to all L2PcInstance in the _KnownPlayers of the L2Character that have the Character targetted.<BR>
|
||||
* <BR>
|
||||
* <B><U> Concept</U> :</B><BR>
|
||||
* L2PcInstance in the detection area of the L2Character are identified in <B>_knownPlayers</B>.<BR>
|
||||
* In order to inform other players of state modification on the L2Character, server just need to go through _knownPlayers to send Server->Client Packet<BR>
|
||||
* <BR>
|
||||
* <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packet to this L2Character (to do this use method toSelfAndKnownPlayers)</B></FONT><BR>
|
||||
* <BR>
|
||||
*/
|
||||
public static void toPlayersTargettingMyself(L2Character character, L2GameServerPacket mov)
|
||||
{
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.fine("players to notify:" + character.getKnownList().getKnownPlayers().size() + " packet:" + mov.getType());
|
||||
}
|
||||
|
||||
Collection<L2PcInstance> plrs = character.getKnownList().getKnownPlayers().values();
|
||||
// synchronized (character.getKnownList().getKnownPlayers())
|
||||
{
|
||||
for (L2PcInstance player : plrs)
|
||||
{
|
||||
if (player.getTarget() != character)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
player.sendPacket(mov);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to all L2PcInstance in the _KnownPlayers of the L2Character.<BR>
|
||||
* <BR>
|
||||
* <B><U> Concept</U> :</B><BR>
|
||||
* L2PcInstance in the detection area of the L2Character are identified in <B>_knownPlayers</B>.<BR>
|
||||
* In order to inform other players of state modification on the L2Character, server just need to go through _knownPlayers to send Server->Client Packet<BR>
|
||||
* <BR>
|
||||
* <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packet to this L2Character (to do this use method toSelfAndKnownPlayers)</B></FONT><BR>
|
||||
* <BR>
|
||||
*/
|
||||
public static void toKnownPlayers(L2Character character, L2GameServerPacket mov)
|
||||
{
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.fine("players to notify:" + character.getKnownList().getKnownPlayers().size() + " packet:" + mov.getType());
|
||||
}
|
||||
|
||||
Collection<L2PcInstance> plrs = character.getKnownList().getKnownPlayers().values();
|
||||
// synchronized (character.getKnownList().getKnownPlayers())
|
||||
{
|
||||
for (L2PcInstance player : plrs)
|
||||
{
|
||||
if (player == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
player.sendPacket(mov);
|
||||
if ((mov instanceof CharInfo) && (character instanceof L2PcInstance))
|
||||
{
|
||||
int relation = ((L2PcInstance) character).getRelation(player);
|
||||
Integer oldrelation = character.getKnownList().getKnownRelations().get(player.getObjectId());
|
||||
if ((oldrelation != null) && (oldrelation != relation))
|
||||
{
|
||||
player.sendPacket(new RelationChanged((L2PcInstance) character, relation, character.isAutoAttackable(player)));
|
||||
if (((L2PcInstance) character).getPet() != null)
|
||||
{
|
||||
player.sendPacket(new RelationChanged(((L2PcInstance) character).getPet(), relation, character.isAutoAttackable(player)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NullPointerException e)
|
||||
{
|
||||
_log.log(Level.WARNING, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to all L2PcInstance in the _KnownPlayers (in the specified radius) of the L2Character.<BR>
|
||||
* <BR>
|
||||
* <B><U> Concept</U> :</B><BR>
|
||||
* L2PcInstance in the detection area of the L2Character are identified in <B>_knownPlayers</B>.<BR>
|
||||
* In order to inform other players of state modification on the L2Character, server just needs to go through _knownPlayers to send Server->Client Packet and check the distance between the targets.<BR>
|
||||
* <BR>
|
||||
* <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packet to this L2Character (to do this use method toSelfAndKnownPlayers)</B></FONT><BR>
|
||||
* <BR>
|
||||
*/
|
||||
public static void toKnownPlayersInRadius(L2Character character, L2GameServerPacket mov, int radius)
|
||||
{
|
||||
if (radius < 0)
|
||||
{
|
||||
radius = 1500;
|
||||
}
|
||||
|
||||
Collection<L2PcInstance> plrs = character.getKnownList().getKnownPlayers().values();
|
||||
// synchronized (character.getKnownList().getKnownPlayers())
|
||||
{
|
||||
for (L2PcInstance player : plrs)
|
||||
{
|
||||
if (character.isInsideRadius(player, radius, false, false))
|
||||
{
|
||||
player.sendPacket(mov);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to all L2PcInstance in the _KnownPlayers of the L2Character and to the specified character.<BR>
|
||||
* <BR>
|
||||
* <B><U> Concept</U> :</B><BR>
|
||||
* L2PcInstance in the detection area of the L2Character are identified in <B>_knownPlayers</B>.<BR>
|
||||
* In order to inform other players of state modification on the L2Character, server just need to go through _knownPlayers to send Server->Client Packet<BR>
|
||||
* <BR>
|
||||
*/
|
||||
public static void toSelfAndKnownPlayers(L2Character character, L2GameServerPacket mov)
|
||||
{
|
||||
if (character instanceof L2PcInstance)
|
||||
{
|
||||
character.sendPacket(mov);
|
||||
}
|
||||
|
||||
toKnownPlayers(character, mov);
|
||||
}
|
||||
|
||||
// To improve performance we are comparing values of radius^2 instead of calculating sqrt all the time
|
||||
public static void toSelfAndKnownPlayersInRadius(L2Character character, L2GameServerPacket mov, long radiusSq)
|
||||
{
|
||||
if (radiusSq < 0)
|
||||
{
|
||||
radiusSq = 360000;
|
||||
}
|
||||
|
||||
if (character instanceof L2PcInstance)
|
||||
{
|
||||
character.sendPacket(mov);
|
||||
}
|
||||
|
||||
Collection<L2PcInstance> plrs = character.getKnownList().getKnownPlayers().values();
|
||||
// synchronized (character.getKnownList().getKnownPlayers())
|
||||
{
|
||||
for (L2PcInstance player : plrs)
|
||||
{
|
||||
if ((player != null) && (character.getDistanceSq(player) <= radiusSq))
|
||||
{
|
||||
player.sendPacket(mov);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to all L2PcInstance present in the world.<BR>
|
||||
* <BR>
|
||||
* <B><U> Concept</U> :</B><BR>
|
||||
* In order to inform other players of state modification on the L2Character, server just need to go through _allPlayers to send Server->Client Packet<BR>
|
||||
* <BR>
|
||||
* <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packet to this L2Character (to do this use method toSelfAndKnownPlayers)</B></FONT><BR>
|
||||
* <BR>
|
||||
*/
|
||||
public static void toAllOnlinePlayers(L2GameServerPacket mov)
|
||||
{
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.fine("Players to notify: " + L2World.getInstance().getAllPlayersCount() + " (with packet " + mov.getType() + ")");
|
||||
}
|
||||
|
||||
Collection<L2PcInstance> pls = L2World.getInstance().getAllPlayers().values();
|
||||
// synchronized (L2World.getInstance().getAllPlayers())
|
||||
{
|
||||
for (L2PcInstance onlinePlayer : pls)
|
||||
{
|
||||
if ((onlinePlayer != null) && onlinePlayer.isOnline())
|
||||
{
|
||||
onlinePlayer.sendPacket(mov);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void announceToOnlinePlayers(String text)
|
||||
{
|
||||
CreatureSay cs = new CreatureSay(0, Say2.ANNOUNCEMENT, "", text);
|
||||
toAllOnlinePlayers(cs);
|
||||
}
|
||||
|
||||
public static void toPlayersInInstance(L2GameServerPacket mov, int instanceId)
|
||||
{
|
||||
Collection<L2PcInstance> pls = L2World.getInstance().getAllPlayers().values();
|
||||
// synchronized (character.getKnownList().getKnownPlayers())
|
||||
{
|
||||
for (L2PcInstance onlinePlayer : pls)
|
||||
{
|
||||
if ((onlinePlayer != null) && onlinePlayer.isOnline() && (onlinePlayer.getInstanceId() == instanceId))
|
||||
{
|
||||
onlinePlayer.sendPacket(mov);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jserver.Config;
|
||||
import com.l2jserver.L2DatabaseFactory;
|
||||
import com.l2jserver.gameserver.ThreadPoolManager;
|
||||
import com.l2jserver.gameserver.datatables.NpcTable;
|
||||
import com.l2jserver.gameserver.datatables.SummonItemsData;
|
||||
import com.l2jserver.gameserver.model.L2ItemInstance;
|
||||
import com.l2jserver.gameserver.model.L2SummonItem;
|
||||
import com.l2jserver.gameserver.model.L2World;
|
||||
import com.l2jserver.gameserver.model.actor.L2Npc;
|
||||
import com.l2jserver.gameserver.model.actor.L2Summon;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2PetInstance;
|
||||
import com.l2jserver.gameserver.network.SystemMessageId;
|
||||
import com.l2jserver.gameserver.network.serverpackets.InventoryUpdate;
|
||||
import com.l2jserver.gameserver.network.serverpackets.MagicSkillLaunched;
|
||||
import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
|
||||
import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
|
||||
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
|
||||
import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
|
||||
|
||||
public final class Evolve
|
||||
{
|
||||
public static final Logger _log = Logger.getLogger(Evolve.class.getName());
|
||||
|
||||
public static final boolean doEvolve(L2PcInstance player, L2Npc npc, int itemIdtake, int itemIdgive, int petminlvl)
|
||||
{
|
||||
if ((itemIdtake == 0) || (itemIdgive == 0) || (petminlvl == 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
L2Summon summon = player.getPet();
|
||||
|
||||
if ((summon == null) || !(summon instanceof L2PetInstance))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
L2PetInstance currentPet = (L2PetInstance) summon;
|
||||
|
||||
if (currentPet.isAlikeDead())
|
||||
{
|
||||
Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to use death pet exploit!", Config.DEFAULT_PUNISH);
|
||||
return false;
|
||||
}
|
||||
|
||||
L2ItemInstance item = null;
|
||||
long petexp = currentPet.getStat().getExp();
|
||||
String oldname = currentPet.getName();
|
||||
int oldX = currentPet.getX();
|
||||
int oldY = currentPet.getY();
|
||||
int oldZ = currentPet.getZ();
|
||||
|
||||
L2SummonItem olditem = SummonItemsData.getInstance().getSummonItem(itemIdtake);
|
||||
|
||||
if (olditem == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int oldnpcID = olditem.getNpcId();
|
||||
|
||||
if ((currentPet.getStat().getLevel() < petminlvl) || (currentPet.getNpcId() != oldnpcID))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
L2SummonItem sitem = SummonItemsData.getInstance().getSummonItem(itemIdgive);
|
||||
|
||||
if (sitem == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int npcID = sitem.getNpcId();
|
||||
|
||||
if (npcID == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
L2NpcTemplate npcTemplate = NpcTable.getInstance().getTemplate(npcID);
|
||||
|
||||
currentPet.unSummon(player);
|
||||
|
||||
// deleting old pet item
|
||||
currentPet.destroyControlItem(player, true);
|
||||
|
||||
item = player.getInventory().addItem("Evolve", itemIdgive, 1, player, npc);
|
||||
|
||||
// Summoning new pet
|
||||
L2PetInstance petSummon = L2PetInstance.spawnPet(npcTemplate, player, item);
|
||||
|
||||
if (petSummon == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fix for non-linear baby pet exp
|
||||
long _minimumexp = petSummon.getStat().getExpForLevel(petminlvl);
|
||||
if (petexp < _minimumexp)
|
||||
{
|
||||
petexp = _minimumexp;
|
||||
}
|
||||
|
||||
petSummon.getStat().addExp(petexp);
|
||||
petSummon.setCurrentHp(petSummon.getMaxHp());
|
||||
petSummon.setCurrentMp(petSummon.getMaxMp());
|
||||
petSummon.setCurrentFed(petSummon.getMaxFed());
|
||||
petSummon.setTitle(player.getName());
|
||||
petSummon.setName(oldname);
|
||||
petSummon.setRunning();
|
||||
petSummon.store();
|
||||
|
||||
player.setPet(petSummon);
|
||||
|
||||
player.sendPacket(new MagicSkillUse(npc, 2046, 1, 1000, 600000));
|
||||
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.SUMMON_A_PET));
|
||||
// L2World.getInstance().storeObject(petSummon);
|
||||
petSummon.spawnMe(oldX, oldY, oldZ);
|
||||
petSummon.startFeed();
|
||||
item.setEnchantLevel(petSummon.getLevel());
|
||||
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new EvolveFinalizer(player, petSummon), 900);
|
||||
|
||||
if (petSummon.getCurrentFed() <= 0)
|
||||
{
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new EvolveFeedWait(player, petSummon), 60000);
|
||||
}
|
||||
else
|
||||
{
|
||||
petSummon.startFeed();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final boolean doRestore(L2PcInstance player, L2Npc npc, int itemIdtake, int itemIdgive, int petminlvl)
|
||||
{
|
||||
if ((itemIdtake == 0) || (itemIdgive == 0) || (petminlvl == 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
L2ItemInstance item = player.getInventory().getItemByItemId(itemIdtake);
|
||||
if (item == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int oldpetlvl = item.getEnchantLevel();
|
||||
if (oldpetlvl < petminlvl)
|
||||
{
|
||||
oldpetlvl = petminlvl;
|
||||
}
|
||||
|
||||
L2SummonItem oldItem = SummonItemsData.getInstance().getSummonItem(itemIdtake);
|
||||
if (oldItem == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
L2SummonItem sItem = SummonItemsData.getInstance().getSummonItem(itemIdgive);
|
||||
if (sItem == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int npcId = sItem.getNpcId();
|
||||
if (npcId == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
L2NpcTemplate npcTemplate = NpcTable.getInstance().getTemplate(npcId);
|
||||
|
||||
// deleting old pet item
|
||||
L2ItemInstance removedItem = player.getInventory().destroyItem("PetRestore", item, player, npc);
|
||||
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED).addItemName(removedItem));
|
||||
|
||||
// Give new pet item
|
||||
L2ItemInstance addedItem = player.getInventory().addItem("PetRestore", itemIdgive, 1, player, npc);
|
||||
|
||||
// Summoning new pet
|
||||
L2PetInstance petSummon = L2PetInstance.spawnPet(npcTemplate, player, addedItem);
|
||||
if (petSummon == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long _maxexp = petSummon.getStat().getExpForLevel(oldpetlvl);
|
||||
|
||||
petSummon.getStat().addExp(_maxexp);
|
||||
petSummon.setCurrentHp(petSummon.getMaxHp());
|
||||
petSummon.setCurrentMp(petSummon.getMaxMp());
|
||||
petSummon.setCurrentFed(petSummon.getMaxFed());
|
||||
petSummon.setTitle(player.getName());
|
||||
petSummon.setRunning();
|
||||
petSummon.store();
|
||||
|
||||
player.setPet(petSummon);
|
||||
|
||||
player.sendPacket(new MagicSkillUse(npc, 2046, 1, 1000, 600000));
|
||||
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.SUMMON_A_PET));
|
||||
// L2World.getInstance().storeObject(petSummon);
|
||||
petSummon.spawnMe(player.getX(), player.getY(), player.getZ());
|
||||
petSummon.startFeed();
|
||||
addedItem.setEnchantLevel(petSummon.getLevel());
|
||||
|
||||
// Inventory update
|
||||
InventoryUpdate iu = new InventoryUpdate();
|
||||
iu.addRemovedItem(removedItem);
|
||||
player.sendPacket(iu);
|
||||
|
||||
StatusUpdate su = new StatusUpdate(player);
|
||||
su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad());
|
||||
player.sendPacket(su);
|
||||
|
||||
player.broadcastUserInfo();
|
||||
|
||||
L2World world = L2World.getInstance();
|
||||
world.removeObject(removedItem);
|
||||
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new EvolveFinalizer(player, petSummon), 900);
|
||||
|
||||
if (petSummon.getCurrentFed() <= 0)
|
||||
{
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new EvolveFeedWait(player, petSummon), 60000);
|
||||
}
|
||||
else
|
||||
{
|
||||
petSummon.startFeed();
|
||||
}
|
||||
|
||||
// pet control item no longer exists, delete the pet from the db
|
||||
Connection con = null;
|
||||
try
|
||||
{
|
||||
con = L2DatabaseFactory.getInstance().getConnection();
|
||||
PreparedStatement statement = con.prepareStatement("DELETE FROM pets WHERE item_obj_id=?");
|
||||
statement.setInt(1, removedItem.getObjectId());
|
||||
statement.execute();
|
||||
statement.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
L2DatabaseFactory.close(con);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static final class EvolveFeedWait implements Runnable
|
||||
{
|
||||
private final L2PcInstance _activeChar;
|
||||
private final L2PetInstance _petSummon;
|
||||
|
||||
EvolveFeedWait(L2PcInstance activeChar, L2PetInstance petSummon)
|
||||
{
|
||||
_activeChar = activeChar;
|
||||
_petSummon = petSummon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_petSummon.getCurrentFed() <= 0)
|
||||
{
|
||||
_petSummon.unSummon(_activeChar);
|
||||
}
|
||||
else
|
||||
{
|
||||
_petSummon.startFeed();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.log(Level.WARNING, "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class EvolveFinalizer implements Runnable
|
||||
{
|
||||
private final L2PcInstance _activeChar;
|
||||
private final L2PetInstance _petSummon;
|
||||
|
||||
EvolveFinalizer(L2PcInstance activeChar, L2PetInstance petSummon)
|
||||
{
|
||||
_activeChar = activeChar;
|
||||
_petSummon = petSummon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
_activeChar.sendPacket(new MagicSkillLaunched(_activeChar, 2046, 1));
|
||||
_petSummon.setFollowStatus(true);
|
||||
_petSummon.setShowSummonAnimation(false);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
_log.log(Level.WARNING, "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* $HeadURL: $
|
||||
*
|
||||
* $Author: $
|
||||
* $Date: $
|
||||
* $Revision: $
|
||||
*
|
||||
*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
/**
|
||||
* This interface can be implemented by extensions to register simple functions with the DynamicExtension handler It's in the responsibility of the extensions to interpret the get and set functions
|
||||
* @version $Revision: $ $Date: $
|
||||
* @author Galun
|
||||
*/
|
||||
public interface ExtensionFunction
|
||||
{
|
||||
/**
|
||||
* get an object identified with a name (should have a human readable output with toString())
|
||||
* @param name the name of an object or a result of a function
|
||||
* @return the object
|
||||
*/
|
||||
public Object get(String name);
|
||||
|
||||
/**
|
||||
* set the named object to the new value supplied in obj
|
||||
* @param name the name of the object
|
||||
* @param obj the new value
|
||||
*/
|
||||
public void set(String name, Object obj);
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jserver.gameserver.GameTimeController;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jserver.gameserver.network.L2GameClient;
|
||||
import com.l2jserver.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Flood protector implementation.
|
||||
* @author fordfrog
|
||||
*/
|
||||
public final class FloodProtectorAction
|
||||
{
|
||||
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
private static final Logger _log = Logger.getLogger(FloodProtectorAction.class.getName());
|
||||
/**
|
||||
* Client for this instance of flood protector.
|
||||
*/
|
||||
private final L2GameClient _client;
|
||||
/**
|
||||
* Configuration of this instance of flood protector.
|
||||
*/
|
||||
private final FloodProtectorConfig _config;
|
||||
/**
|
||||
* Next game tick when new request is allowed.
|
||||
*/
|
||||
private volatile int _nextGameTick = GameTimeController.getGameTicks();
|
||||
/**
|
||||
* Request counter.
|
||||
*/
|
||||
private final AtomicInteger _count = new AtomicInteger(0);
|
||||
/**
|
||||
* Flag determining whether exceeding request has been logged.
|
||||
*/
|
||||
private boolean _logged;
|
||||
/**
|
||||
* Flag determining whether punishment application is in progress so that we do not apply punisment multiple times (flooding).
|
||||
*/
|
||||
private volatile boolean _punishmentInProgress;
|
||||
|
||||
/**
|
||||
* Creates new instance of FloodProtectorAction.
|
||||
* @param player player for which flood protection is being created
|
||||
* @param config flood protector configuration
|
||||
*/
|
||||
public FloodProtectorAction(final L2GameClient client, final FloodProtectorConfig config)
|
||||
{
|
||||
super();
|
||||
_client = client;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the request is flood protected or not.
|
||||
* @param command command issued or short command description
|
||||
* @return true if action is allowed, otherwise false
|
||||
*/
|
||||
public boolean tryPerformAction(final String command)
|
||||
{
|
||||
final int curTick = GameTimeController.getGameTicks();
|
||||
|
||||
if ((curTick < _nextGameTick) || _punishmentInProgress)
|
||||
{
|
||||
if (_config.LOG_FLOODING && !_logged && _log.isLoggable(Level.WARNING))
|
||||
{
|
||||
log(" called command ", command, " ~", String.valueOf((_config.FLOOD_PROTECTION_INTERVAL - (_nextGameTick - curTick)) * GameTimeController.MILLIS_IN_TICK), " ms after previous command");
|
||||
_logged = true;
|
||||
}
|
||||
|
||||
_count.incrementAndGet();
|
||||
|
||||
if (!_punishmentInProgress && (_config.PUNISHMENT_LIMIT > 0) && (_count.get() >= _config.PUNISHMENT_LIMIT) && (_config.PUNISHMENT_TYPE != null))
|
||||
{
|
||||
_punishmentInProgress = true;
|
||||
|
||||
if ("kick".equals(_config.PUNISHMENT_TYPE))
|
||||
{
|
||||
kickPlayer();
|
||||
}
|
||||
else if ("ban".equals(_config.PUNISHMENT_TYPE))
|
||||
{
|
||||
banAccount();
|
||||
}
|
||||
else if ("jail".equals(_config.PUNISHMENT_TYPE))
|
||||
{
|
||||
jailChar();
|
||||
}
|
||||
|
||||
_punishmentInProgress = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_count.get() > 0)
|
||||
{
|
||||
if (_config.LOG_FLOODING && _log.isLoggable(Level.WARNING))
|
||||
{
|
||||
log(" issued ", String.valueOf(_count), " extra requests within ~", String.valueOf(_config.FLOOD_PROTECTION_INTERVAL * GameTimeController.MILLIS_IN_TICK), " ms");
|
||||
}
|
||||
}
|
||||
|
||||
_nextGameTick = curTick + _config.FLOOD_PROTECTION_INTERVAL;
|
||||
_logged = false;
|
||||
_count.set(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kick player from game (close network connection).
|
||||
*/
|
||||
private void kickPlayer()
|
||||
{
|
||||
if (_client.getActiveChar() != null)
|
||||
{
|
||||
_client.getActiveChar().logout(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_client.closeNow();
|
||||
}
|
||||
|
||||
if (_log.isLoggable(Level.WARNING))
|
||||
{
|
||||
log("kicked for flooding");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bans char account and logs out the char.
|
||||
*/
|
||||
private void banAccount()
|
||||
{
|
||||
if (_client.getActiveChar() != null)
|
||||
{
|
||||
_client.getActiveChar().setPunishLevel(L2PcInstance.PunishLevel.ACC, _config.PUNISHMENT_TIME);
|
||||
|
||||
if (_log.isLoggable(Level.WARNING))
|
||||
{
|
||||
log(" banned for flooding ", _config.PUNISHMENT_TIME <= 0 ? "forever" : "for " + _config.PUNISHMENT_TIME + " mins");
|
||||
}
|
||||
|
||||
_client.getActiveChar().logout();
|
||||
}
|
||||
else
|
||||
{
|
||||
log(" unable to ban account: no active player");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Jails char.
|
||||
*/
|
||||
private void jailChar()
|
||||
{
|
||||
if (_client.getActiveChar() != null)
|
||||
{
|
||||
_client.getActiveChar().setPunishLevel(L2PcInstance.PunishLevel.JAIL, _config.PUNISHMENT_TIME);
|
||||
|
||||
if (_log.isLoggable(Level.WARNING))
|
||||
{
|
||||
log(" jailed for flooding ", _config.PUNISHMENT_TIME <= 0 ? "forever" : "for " + _config.PUNISHMENT_TIME + " mins");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(" unable to jail: no active player");
|
||||
}
|
||||
}
|
||||
|
||||
private void log(String... lines)
|
||||
{
|
||||
final StringBuilder output = StringUtil.startAppend(100, _config.FLOOD_PROTECTOR_TYPE, ": ");
|
||||
String address = null;
|
||||
try
|
||||
{
|
||||
if (!_client.isDetached())
|
||||
{
|
||||
address = _client.getConnection().getInetAddress().getHostAddress();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
|
||||
switch (_client.getState())
|
||||
{
|
||||
case IN_GAME:
|
||||
if (_client.getActiveChar() != null)
|
||||
{
|
||||
StringUtil.append(output, _client.getActiveChar().getName());
|
||||
StringUtil.append(output, "(", String.valueOf(_client.getActiveChar().getObjectId()), ") ");
|
||||
}
|
||||
case AUTHED:
|
||||
if (_client.getAccountName() != null)
|
||||
{
|
||||
StringUtil.append(output, _client.getAccountName(), " ");
|
||||
}
|
||||
case CONNECTED:
|
||||
if (address != null)
|
||||
{
|
||||
StringUtil.append(output, address);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Missing state on switch");
|
||||
}
|
||||
|
||||
StringUtil.append(output, lines);
|
||||
_log.warning(output.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
/**
|
||||
* Flood protector configuration
|
||||
* @author fordfrog
|
||||
*/
|
||||
public final class FloodProtectorConfig
|
||||
{
|
||||
|
||||
/**
|
||||
* Type used for identification of logging output.
|
||||
*/
|
||||
public String FLOOD_PROTECTOR_TYPE;
|
||||
/**
|
||||
* Flood protection interval in game ticks.
|
||||
*/
|
||||
public int FLOOD_PROTECTION_INTERVAL;
|
||||
/**
|
||||
* Whether flooding should be logged.
|
||||
*/
|
||||
public boolean LOG_FLOODING;
|
||||
/**
|
||||
* If specified punishment limit is exceeded, punishment is applied.
|
||||
*/
|
||||
public int PUNISHMENT_LIMIT;
|
||||
/**
|
||||
* Punishment type. Either 'none', 'kick', 'ban' or 'jail'.
|
||||
*/
|
||||
public String PUNISHMENT_TYPE;
|
||||
/**
|
||||
* For how long should the char/account be punished.
|
||||
*/
|
||||
public int PUNISHMENT_TIME;
|
||||
|
||||
/**
|
||||
* Creates new instance of FloodProtectorConfig.
|
||||
* @param floodProtectorType {@link #FLOOD_PROTECTOR_TYPE}
|
||||
*/
|
||||
public FloodProtectorConfig(final String floodProtectorType)
|
||||
{
|
||||
super();
|
||||
FLOOD_PROTECTOR_TYPE = floodProtectorType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
import com.l2jserver.Config;
|
||||
import com.l2jserver.gameserver.network.L2GameClient;
|
||||
|
||||
/**
|
||||
* Collection of flood protectors for single player.
|
||||
* @author fordfrog
|
||||
*/
|
||||
public final class FloodProtectors
|
||||
{
|
||||
|
||||
/**
|
||||
* Use-item flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _useItem;
|
||||
/**
|
||||
* Roll-dice flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _rollDice;
|
||||
/**
|
||||
* Firework flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _firework;
|
||||
/**
|
||||
* Item-pet-summon flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _itemPetSummon;
|
||||
/**
|
||||
* Hero-voice flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _heroVoice;
|
||||
/**
|
||||
* Global-chat flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _globalChat;
|
||||
/**
|
||||
* Subclass flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _subclass;
|
||||
/**
|
||||
* Drop-item flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _dropItem;
|
||||
/**
|
||||
* Server-bypass flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _serverBypass;
|
||||
/**
|
||||
* Multisell flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _multiSell;
|
||||
/**
|
||||
* Transaction flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _transaction;
|
||||
/**
|
||||
* Manufacture flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _manufacture;
|
||||
/**
|
||||
* Manor flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _manor;
|
||||
/**
|
||||
* Send mail flood protector.
|
||||
*/
|
||||
private final FloodProtectorAction _sendMail;
|
||||
/**
|
||||
* Character Select protector
|
||||
*/
|
||||
private final FloodProtectorAction _characterSelect;
|
||||
/**
|
||||
* Item Auction
|
||||
*/
|
||||
private final FloodProtectorAction _itemAuction;
|
||||
|
||||
/**
|
||||
* Creates new instance of FloodProtectors.
|
||||
* @param player player for which the collection of flood protectors is being created.
|
||||
*/
|
||||
public FloodProtectors(final L2GameClient client)
|
||||
{
|
||||
super();
|
||||
_useItem = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_USE_ITEM);
|
||||
_rollDice = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_ROLL_DICE);
|
||||
_firework = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_FIREWORK);
|
||||
_itemPetSummon = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_ITEM_PET_SUMMON);
|
||||
_heroVoice = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_HERO_VOICE);
|
||||
_globalChat = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_GLOBAL_CHAT);
|
||||
_subclass = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_SUBCLASS);
|
||||
_dropItem = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_DROP_ITEM);
|
||||
_serverBypass = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_SERVER_BYPASS);
|
||||
_multiSell = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_MULTISELL);
|
||||
_transaction = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_TRANSACTION);
|
||||
_manufacture = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_MANUFACTURE);
|
||||
_manor = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_MANOR);
|
||||
_sendMail = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_SENDMAIL);
|
||||
_characterSelect = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_CHARACTER_SELECT);
|
||||
_itemAuction = new FloodProtectorAction(client, Config.FLOOD_PROTECTOR_ITEM_AUCTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_useItem}.
|
||||
* @return {@link #_useItem}
|
||||
*/
|
||||
public FloodProtectorAction getUseItem()
|
||||
{
|
||||
return _useItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_rollDice}.
|
||||
* @return {@link #_rollDice}
|
||||
*/
|
||||
public FloodProtectorAction getRollDice()
|
||||
{
|
||||
return _rollDice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_firework}.
|
||||
* @return {@link #_firework}
|
||||
*/
|
||||
public FloodProtectorAction getFirework()
|
||||
{
|
||||
return _firework;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_itemPetSummon}.
|
||||
* @return {@link #_itemPetSummon}
|
||||
*/
|
||||
public FloodProtectorAction getItemPetSummon()
|
||||
{
|
||||
return _itemPetSummon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_heroVoice}.
|
||||
* @return {@link #_heroVoice}
|
||||
*/
|
||||
public FloodProtectorAction getHeroVoice()
|
||||
{
|
||||
return _heroVoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_globalChat}.
|
||||
* @return {@link #_globalChat}
|
||||
*/
|
||||
public FloodProtectorAction getGlobalChat()
|
||||
{
|
||||
return _globalChat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_subclass}.
|
||||
* @return {@link #_subclass}
|
||||
*/
|
||||
public FloodProtectorAction getSubclass()
|
||||
{
|
||||
return _subclass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_dropItem}.
|
||||
* @return {@link #_dropItem}
|
||||
*/
|
||||
public FloodProtectorAction getDropItem()
|
||||
{
|
||||
return _dropItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_serverBypass}.
|
||||
* @return {@link #_serverBypass}
|
||||
*/
|
||||
public FloodProtectorAction getServerBypass()
|
||||
{
|
||||
return _serverBypass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_multisell}.
|
||||
* @return {@link #_multisell}
|
||||
*/
|
||||
public FloodProtectorAction getMultiSell()
|
||||
{
|
||||
return _multiSell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_transaction}.
|
||||
* @return {@link #_transaction}
|
||||
*/
|
||||
public FloodProtectorAction getTransaction()
|
||||
{
|
||||
return _transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_manufacture}.
|
||||
* @return {@link #_manufacture}
|
||||
*/
|
||||
public FloodProtectorAction getManufacture()
|
||||
{
|
||||
return _manufacture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_manor}.
|
||||
* @return {@link #_manor}
|
||||
*/
|
||||
public FloodProtectorAction getManor()
|
||||
{
|
||||
return _manor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_sendMail}.
|
||||
* @return {@link #_sendMail}
|
||||
*/
|
||||
public FloodProtectorAction getSendMail()
|
||||
{
|
||||
return _sendMail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_characterSelect}.
|
||||
* @return {@link #_characterSelect}
|
||||
*/
|
||||
public FloodProtectorAction getCharacterSelect()
|
||||
{
|
||||
return _characterSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #_itemAuction}.
|
||||
* @return {@link #_itemAuction}
|
||||
*/
|
||||
public FloodProtectorAction getItemAuction()
|
||||
{
|
||||
return _itemAuction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jserver.util.lib.Log;
|
||||
|
||||
public class GMAudit
|
||||
{
|
||||
static
|
||||
{
|
||||
new File("log/GMAudit").mkdirs();
|
||||
}
|
||||
|
||||
private static final Logger _log = Logger.getLogger(Log.class.getName());
|
||||
private static final SimpleDateFormat _formatter = new SimpleDateFormat("dd/MM/yyyy H:mm:ss");
|
||||
|
||||
public static void auditGMAction(String gmName, String action, String target, String params)
|
||||
{
|
||||
String today = _formatter.format(new Date());
|
||||
|
||||
FileWriter save = null;
|
||||
try
|
||||
{
|
||||
File file = new File("log/GMAudit/" + gmName + ".txt");
|
||||
save = new FileWriter(file, true);
|
||||
|
||||
String out = (today + ">" + gmName + ">" + action + ">" + target + ">" + params + "\r\n");
|
||||
save.write(out);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
_log.log(Level.SEVERE, "GMAudit for GM " + gmName + " could not be saved: ", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
save.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void auditGMAction(String gmName, String action, String target)
|
||||
{
|
||||
auditGMAction(gmName, action, target, "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* $Header: IllegalPlayerAction.java, 21/10/2005 23:32:02 luisantonioa Exp $
|
||||
*
|
||||
* $Author: luisantonioa $ $Date: 21/10/2005 23:32:02 $ $Revision: 1 $ $Log:
|
||||
* IllegalPlayerAction.java,v $ Revision 1 21/10/2005 23:32:02 luisantonioa
|
||||
* Added copyright notice
|
||||
*
|
||||
*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jserver.Config;
|
||||
import com.l2jserver.gameserver.GmListTable;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
|
||||
|
||||
/**
|
||||
* This class ...
|
||||
* @version $Revision: 1.2 $ $Date: 2004/06/27 08:12:59 $
|
||||
*/
|
||||
public final class IllegalPlayerAction implements Runnable
|
||||
{
|
||||
private static Logger _logAudit = Logger.getLogger("audit");
|
||||
|
||||
private final String _message;
|
||||
private final int _punishment;
|
||||
private final L2PcInstance _actor;
|
||||
|
||||
public static final int PUNISH_BROADCAST = 1;
|
||||
public static final int PUNISH_KICK = 2;
|
||||
public static final int PUNISH_KICKBAN = 3;
|
||||
public static final int PUNISH_JAIL = 4;
|
||||
|
||||
public IllegalPlayerAction(L2PcInstance actor, String message, int punishment)
|
||||
{
|
||||
_message = message;
|
||||
_punishment = punishment;
|
||||
_actor = actor;
|
||||
|
||||
switch (punishment)
|
||||
{
|
||||
case PUNISH_KICK:
|
||||
_actor.sendMessage("You will be kicked for illegal action, GM informed.");
|
||||
break;
|
||||
case PUNISH_KICKBAN:
|
||||
_actor.setAccessLevel(-100);
|
||||
_actor.setAccountAccesslevel(-100);
|
||||
_actor.sendMessage("You are banned for illegal action, GM informed.");
|
||||
break;
|
||||
case PUNISH_JAIL:
|
||||
_actor.sendMessage("Illegal action performed!");
|
||||
_actor.sendMessage("You will be teleported to GM Consultation Service area and jailed.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
LogRecord record = new LogRecord(Level.INFO, "AUDIT:" + _message);
|
||||
record.setLoggerName("audit");
|
||||
record.setParameters(new Object[]
|
||||
{
|
||||
_actor,
|
||||
_punishment
|
||||
});
|
||||
_logAudit.log(record);
|
||||
|
||||
GmListTable.broadcastMessageToGMs(_message);
|
||||
|
||||
switch (_punishment)
|
||||
{
|
||||
case PUNISH_BROADCAST:
|
||||
return;
|
||||
case PUNISH_KICK:
|
||||
_actor.logout(false);
|
||||
break;
|
||||
case PUNISH_KICKBAN:
|
||||
_actor.logout();
|
||||
break;
|
||||
case PUNISH_JAIL:
|
||||
_actor.setPunishLevel(L2PcInstance.PunishLevel.JAIL, Config.DEFAULT_PUNISH_PARAM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
* This is a class loader for the dynamic extensions used by DynamicExtension class.
|
||||
* @version $Revision: $ $Date: $
|
||||
* @author galun
|
||||
*/
|
||||
public class JarClassLoader extends ClassLoader
|
||||
{
|
||||
private static Logger _log = Logger.getLogger(JarClassLoader.class.getCanonicalName());
|
||||
HashSet<String> _jars = new HashSet<>();
|
||||
|
||||
public void addJarFile(String filename)
|
||||
{
|
||||
_jars.add(filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] b = loadClassData(name);
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] loadClassData(String name) throws IOException
|
||||
{
|
||||
byte[] classData = null;
|
||||
for (String jarFile : _jars)
|
||||
{
|
||||
File file = new File(jarFile);
|
||||
try (ZipFile zipFile = new ZipFile(file);)
|
||||
{
|
||||
String fileName = name.replace('.', '/') + ".class";
|
||||
ZipEntry entry = zipFile.getEntry(fileName);
|
||||
if (entry == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
classData = new byte[(int) entry.getSize()];
|
||||
|
||||
try (DataInputStream zipStream = new DataInputStream(zipFile.getInputStream(entry)))
|
||||
{
|
||||
zipStream.readFully(classData, 0, (int) entry.getSize());
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
_log.log(Level.WARNING, jarFile + ": " + e.getMessage(), e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (classData == null)
|
||||
{
|
||||
throw new IOException("class not found in " + _jars);
|
||||
}
|
||||
return classData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javolution.util.FastList;
|
||||
import javolution.util.FastSet;
|
||||
|
||||
import com.l2jserver.Config;
|
||||
import com.l2jserver.gameserver.ThreadPoolManager;
|
||||
import com.l2jserver.gameserver.datatables.NpcTable;
|
||||
import com.l2jserver.gameserver.idfactory.IdFactory;
|
||||
import com.l2jserver.gameserver.model.L2MinionData;
|
||||
import com.l2jserver.gameserver.model.actor.L2Character;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
|
||||
import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
|
||||
import com.l2jserver.util.Rnd;
|
||||
|
||||
/**
|
||||
* @author luisantonioa, DS
|
||||
*/
|
||||
public class MinionList
|
||||
{
|
||||
private static Logger _log = Logger.getLogger(MinionList.class.getName());
|
||||
|
||||
protected final L2MonsterInstance _master;
|
||||
/** List containing the current spawned minions */
|
||||
private final List<L2MonsterInstance> _minionReferences;
|
||||
/** List containing the cached deleted minions for reuse */
|
||||
protected List<L2MonsterInstance> _reusedMinionReferences = null;
|
||||
|
||||
public MinionList(L2MonsterInstance pMaster)
|
||||
{
|
||||
if (pMaster == null)
|
||||
{
|
||||
throw new NullPointerException("MinionList: master is null");
|
||||
}
|
||||
|
||||
_master = pMaster;
|
||||
_minionReferences = new FastList<L2MonsterInstance>().shared();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of the spawned (alive) minions.
|
||||
*/
|
||||
public List<L2MonsterInstance> getSpawnedMinions()
|
||||
{
|
||||
return _minionReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the spawn of Minions.<BR>
|
||||
* <BR>
|
||||
* <B><U> Actions</U> :</B><BR>
|
||||
* <BR>
|
||||
* <li>Get the Minion data of all Minions that must be spawn</li> <li>For each Minion type, spawn the amount of Minion needed</li><BR>
|
||||
* <BR>
|
||||
*/
|
||||
public final void spawnMinions()
|
||||
{
|
||||
if (_master.isAlikeDead())
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<L2MinionData> minions = _master.getTemplate().getMinionData();
|
||||
if (minions == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int minionCount, minionId, minionsToSpawn;
|
||||
for (L2MinionData minion : minions)
|
||||
{
|
||||
minionCount = minion.getAmount();
|
||||
minionId = minion.getMinionId();
|
||||
|
||||
minionsToSpawn = minionCount - countSpawnedMinionsById(minionId);
|
||||
if (minionsToSpawn > 0)
|
||||
{
|
||||
for (int i = 0; i < minionsToSpawn; i++)
|
||||
{
|
||||
spawnMinion(minionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
// remove non-needed minions
|
||||
deleteReusedMinions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all spawned minions and try to reuse them.
|
||||
*/
|
||||
public void deleteSpawnedMinions()
|
||||
{
|
||||
if (!_minionReferences.isEmpty())
|
||||
{
|
||||
for (L2MonsterInstance minion : _minionReferences)
|
||||
{
|
||||
if (minion != null)
|
||||
{
|
||||
minion.setLeader(null);
|
||||
minion.deleteMe();
|
||||
if (_reusedMinionReferences != null)
|
||||
{
|
||||
_reusedMinionReferences.add(minion);
|
||||
}
|
||||
}
|
||||
}
|
||||
_minionReferences.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all reused minions to prevent memory leaks.
|
||||
*/
|
||||
public void deleteReusedMinions()
|
||||
{
|
||||
if (_reusedMinionReferences != null)
|
||||
{
|
||||
_reusedMinionReferences.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// hooks
|
||||
|
||||
/**
|
||||
* Called on the master spawn Old minions (from previous spawn) are deleted. If master can respawn - enabled reuse of the killed minions.
|
||||
*/
|
||||
public void onMasterSpawn()
|
||||
{
|
||||
deleteSpawnedMinions();
|
||||
|
||||
// if master has spawn and can respawn - try to reuse minions
|
||||
if ((_reusedMinionReferences == null) && (_master.getTemplate().getMinionData() != null) && (_master.getSpawn() != null) && _master.getSpawn().isRespawnEnabled())
|
||||
{
|
||||
_reusedMinionReferences = new FastList<L2MonsterInstance>().shared();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on the minion spawn and added them in the list of the spawned minions.
|
||||
*/
|
||||
public void onMinionSpawn(L2MonsterInstance minion)
|
||||
{
|
||||
_minionReferences.add(minion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on the master death/delete.
|
||||
* @param force if true - force delete of the spawned minions By default minions deleted only for raidbosses
|
||||
*/
|
||||
public void onMasterDie(boolean force)
|
||||
{
|
||||
if (_master.isRaid() || force)
|
||||
{
|
||||
deleteSpawnedMinions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on the minion death/delete. Removed minion from the list of the spawned minions and reuse if possible.
|
||||
* @param respawnTime (ms) enable respawning of this minion while master is alive. -1 - use default value: 0 (disable) for mobs and config value for raids.
|
||||
*/
|
||||
public void onMinionDie(L2MonsterInstance minion, int respawnTime)
|
||||
{
|
||||
minion.setLeader(null); // prevent memory leaks
|
||||
_minionReferences.remove(minion);
|
||||
if (_reusedMinionReferences != null)
|
||||
{
|
||||
_reusedMinionReferences.add(minion);
|
||||
}
|
||||
|
||||
final int time = respawnTime < 0 ? _master.isRaid() ? (int) Config.RAID_MINION_RESPAWN_TIMER : 0 : respawnTime;
|
||||
if ((time > 0) && !_master.isAlikeDead())
|
||||
{
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new MinionRespawnTask(minion), time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called if master/minion was attacked. Master and all free minions receive aggro against attacker.
|
||||
*/
|
||||
public void onAssist(L2Character caller, L2Character attacker)
|
||||
{
|
||||
if (attacker == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_master.isAlikeDead() && !_master.isInCombat())
|
||||
{
|
||||
_master.addDamageHate(attacker, 0, 1);
|
||||
}
|
||||
|
||||
final boolean callerIsMaster = caller == _master;
|
||||
int aggro = callerIsMaster ? 10 : 1;
|
||||
if (_master.isRaid())
|
||||
{
|
||||
aggro *= 10;
|
||||
}
|
||||
|
||||
for (L2MonsterInstance minion : _minionReferences)
|
||||
{
|
||||
if ((minion != null) && !minion.isDead() && (callerIsMaster || !minion.isInCombat()))
|
||||
{
|
||||
minion.addDamageHate(attacker, 0, aggro);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from onTeleported() of the master Alive and able to move minions teleported to master.
|
||||
*/
|
||||
public void onMasterTeleported()
|
||||
{
|
||||
final int offset = 200;
|
||||
final int minRadius = (int) _master.getCollisionRadius() + 30;
|
||||
|
||||
for (L2MonsterInstance minion : _minionReferences)
|
||||
{
|
||||
if ((minion != null) && !minion.isDead() && !minion.isMovementDisabled())
|
||||
{
|
||||
int newX = Rnd.get(minRadius * 2, offset * 2); // x
|
||||
int newY = Rnd.get(newX, offset * 2); // distance
|
||||
newY = (int) Math.sqrt((newY * newY) - (newX * newX)); // y
|
||||
if (newX > (offset + minRadius))
|
||||
{
|
||||
newX = (_master.getX() + newX) - offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
newX = (_master.getX() - newX) + minRadius;
|
||||
}
|
||||
if (newY > (offset + minRadius))
|
||||
{
|
||||
newY = (_master.getY() + newY) - offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
newY = (_master.getY() - newY) + minRadius;
|
||||
}
|
||||
|
||||
minion.teleToLocation(newX, newY, _master.getZ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final void spawnMinion(int minionId)
|
||||
{
|
||||
if (minionId == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// searching in reused minions
|
||||
if ((_reusedMinionReferences != null) && !_reusedMinionReferences.isEmpty())
|
||||
{
|
||||
L2MonsterInstance minion;
|
||||
Iterator<L2MonsterInstance> iter = _reusedMinionReferences.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
minion = iter.next();
|
||||
if ((minion != null) && (minion.getNpcId() == minionId))
|
||||
{
|
||||
iter.remove();
|
||||
minion.refreshID();
|
||||
initializeNpcInstance(_master, minion);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// not found in cache
|
||||
spawnMinion(_master, minionId);
|
||||
}
|
||||
|
||||
private final class MinionRespawnTask implements Runnable
|
||||
{
|
||||
private final L2MonsterInstance _minion;
|
||||
|
||||
public MinionRespawnTask(L2MonsterInstance minion)
|
||||
{
|
||||
_minion = minion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (!_master.isAlikeDead() && _master.isVisible())
|
||||
{
|
||||
// minion can be already spawned or deleted
|
||||
if (!_minion.isVisible())
|
||||
{
|
||||
if (_reusedMinionReferences != null)
|
||||
{
|
||||
_reusedMinionReferences.remove(_minion);
|
||||
}
|
||||
|
||||
_minion.refreshID();
|
||||
initializeNpcInstance(_master, _minion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init a Minion and add it in the world as a visible object.<BR>
|
||||
* <BR>
|
||||
* <B><U> Actions</U> :</B><BR>
|
||||
* <BR>
|
||||
* <li>Get the template of the Minion to spawn</li> <li>Create and Init the Minion and generate its Identifier</li> <li>Set the Minion HP, MP and Heading</li> <li>Set the Minion leader to this RaidBoss</li> <li>Init the position of the Minion and add it in the world as a visible object</li><BR>
|
||||
* <BR>
|
||||
* @param master L2MonsterInstance used as master for this minion
|
||||
* @param minionid The L2NpcTemplate Identifier of the Minion to spawn
|
||||
*/
|
||||
public static final L2MonsterInstance spawnMinion(L2MonsterInstance master, int minionId)
|
||||
{
|
||||
// Get the template of the Minion to spawn
|
||||
L2NpcTemplate minionTemplate = NpcTable.getInstance().getTemplate(minionId);
|
||||
if (minionTemplate == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create and Init the Minion and generate its Identifier
|
||||
L2MonsterInstance minion = new L2MonsterInstance(IdFactory.getInstance().getNextId(), minionTemplate);
|
||||
return initializeNpcInstance(master, minion);
|
||||
}
|
||||
|
||||
protected static final L2MonsterInstance initializeNpcInstance(L2MonsterInstance master, L2MonsterInstance minion)
|
||||
{
|
||||
minion.stopAllEffects();
|
||||
minion.setIsDead(false);
|
||||
minion.setDecayed(false);
|
||||
|
||||
// Set the Minion HP, MP and Heading
|
||||
minion.setCurrentHpMp(minion.getMaxHp(), minion.getMaxMp());
|
||||
minion.setHeading(master.getHeading());
|
||||
|
||||
// Set the Minion leader to this RaidBoss
|
||||
minion.setLeader(master);
|
||||
|
||||
// move monster to masters instance
|
||||
minion.setInstanceId(master.getInstanceId());
|
||||
|
||||
// Init the position of the Minion and add it in the world as a visible object
|
||||
final int offset = 200;
|
||||
final int minRadius = (int) master.getCollisionRadius() + 30;
|
||||
|
||||
int newX = Rnd.get(minRadius * 2, offset * 2); // x
|
||||
int newY = Rnd.get(newX, offset * 2); // distance
|
||||
newY = (int) Math.sqrt((newY * newY) - (newX * newX)); // y
|
||||
if (newX > (offset + minRadius))
|
||||
{
|
||||
newX = (master.getX() + newX) - offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
newX = (master.getX() - newX) + minRadius;
|
||||
}
|
||||
if (newY > (offset + minRadius))
|
||||
{
|
||||
newY = (master.getY() + newY) - offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
newY = (master.getY() - newY) + minRadius;
|
||||
}
|
||||
|
||||
minion.spawnMe(newX, newY, master.getZ());
|
||||
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.fine("Spawned minion template " + minion.getNpcId() + " with objid: " + minion.getObjectId() + " to boss " + master.getObjectId() + " ,at: " + minion.getX() + " x, " + minion.getY() + " y, " + minion.getZ() + " z");
|
||||
}
|
||||
|
||||
return minion;
|
||||
}
|
||||
|
||||
// Statistics part
|
||||
|
||||
private final int countSpawnedMinionsById(int minionId)
|
||||
{
|
||||
int count = 0;
|
||||
for (L2MonsterInstance minion : _minionReferences)
|
||||
{
|
||||
if ((minion != null) && (minion.getNpcId() == minionId))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public final int countSpawnedMinions()
|
||||
{
|
||||
return _minionReferences.size();
|
||||
}
|
||||
|
||||
public final int lazyCountSpawnedMinionsGroups()
|
||||
{
|
||||
Set<Integer> seenGroups = new FastSet<>();
|
||||
for (L2MonsterInstance minion : _minionReferences)
|
||||
{
|
||||
if (minion == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
seenGroups.add(minion.getNpcId());
|
||||
}
|
||||
return seenGroups.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javolution.util.FastList;
|
||||
|
||||
/**
|
||||
* Descending Integer Sort Algorithm - Fast ordering system. - Can easily be ported elsewhere. - Can handle any number of values, from a list or even from a map. - Handles duplicate values.
|
||||
* @author Tempy
|
||||
*/
|
||||
public class MultiSort
|
||||
{
|
||||
public static final int SORT_ASCENDING = 0;
|
||||
public static final int SORT_DESCENDING = 1;
|
||||
|
||||
private List<?> _keyList;
|
||||
private List<Integer> _valueList;
|
||||
|
||||
private boolean _isSortDescending;
|
||||
private boolean _isSorted;
|
||||
|
||||
public MultiSort(int[] valueList)
|
||||
{
|
||||
_valueList = getIntList(valueList);
|
||||
}
|
||||
|
||||
public MultiSort(Collection<Integer> valueList)
|
||||
{
|
||||
_valueList = getIntList(valueList);
|
||||
}
|
||||
|
||||
public MultiSort(Object[] keyList, int[] valueList)
|
||||
{
|
||||
_keyList = getList(keyList);
|
||||
_valueList = getIntList(valueList);
|
||||
}
|
||||
|
||||
public MultiSort(Map<?, Integer> valueMap)
|
||||
{
|
||||
_keyList = getList(valueMap.keySet());
|
||||
_valueList = getIntList(valueMap.values());
|
||||
}
|
||||
|
||||
private final List<Integer> getIntList(Collection<Integer> valueList)
|
||||
{
|
||||
return Arrays.asList(valueList.toArray(new Integer[valueList.size()]));
|
||||
}
|
||||
|
||||
private final List<Integer> getIntList(int[] valueList)
|
||||
{
|
||||
Integer[] tempIntList = new Integer[valueList.length];
|
||||
|
||||
for (int i = 0; i < valueList.length; i++)
|
||||
{
|
||||
tempIntList[i] = Integer.valueOf(valueList[i]);
|
||||
}
|
||||
|
||||
return Arrays.asList(tempIntList);
|
||||
}
|
||||
|
||||
private final List<?> getList(Collection<?> valueList)
|
||||
{
|
||||
return getList(valueList.toArray(new Object[valueList.size()]));
|
||||
}
|
||||
|
||||
private final List<Object> getList(Object[] valueList)
|
||||
{
|
||||
return Arrays.asList(valueList);
|
||||
}
|
||||
|
||||
public final int getCount()
|
||||
{
|
||||
return getValues().size();
|
||||
}
|
||||
|
||||
public final int getHarmonicMean()
|
||||
{
|
||||
if (getValues().isEmpty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int totalValue = 0;
|
||||
|
||||
for (int currValue : getValues())
|
||||
{
|
||||
totalValue += (1 / currValue);
|
||||
}
|
||||
|
||||
return (getCount() / totalValue);
|
||||
}
|
||||
|
||||
public final List<?> getKeys()
|
||||
{
|
||||
if (_keyList == null)
|
||||
{
|
||||
return new FastList<>();
|
||||
}
|
||||
|
||||
return _keyList;
|
||||
}
|
||||
|
||||
public final int getFrequency(int checkValue)
|
||||
{
|
||||
return Collections.frequency(getValues(), checkValue);
|
||||
}
|
||||
|
||||
public final int getMaxValue()
|
||||
{
|
||||
return Collections.max(getValues());
|
||||
}
|
||||
|
||||
public final int getMinValue()
|
||||
{
|
||||
return Collections.min(getValues());
|
||||
}
|
||||
|
||||
public final int getMean()
|
||||
{
|
||||
if (getValues().isEmpty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (getTotalValue() / getCount());
|
||||
}
|
||||
|
||||
public final double getStandardDeviation()
|
||||
{
|
||||
if (getValues().isEmpty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
List<Double> tempValList = new FastList<>();
|
||||
|
||||
int meanValue = getMean();
|
||||
int numValues = getCount();
|
||||
|
||||
for (int value : getValues())
|
||||
{
|
||||
double adjValue = Math.pow(value - meanValue, 2);
|
||||
tempValList.add(adjValue);
|
||||
}
|
||||
|
||||
double totalValue = 0;
|
||||
|
||||
for (double storedVal : tempValList)
|
||||
{
|
||||
totalValue += storedVal;
|
||||
}
|
||||
|
||||
return Math.sqrt(totalValue / (numValues - 1));
|
||||
}
|
||||
|
||||
public final int getTotalValue()
|
||||
{
|
||||
if (getValues().isEmpty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int totalValue = 0;
|
||||
|
||||
for (int currValue : getValues())
|
||||
{
|
||||
totalValue += currValue;
|
||||
}
|
||||
|
||||
return totalValue;
|
||||
}
|
||||
|
||||
public final List<Integer> getValues()
|
||||
{
|
||||
if (_valueList == null)
|
||||
{
|
||||
return new FastList<>();
|
||||
}
|
||||
|
||||
return _valueList;
|
||||
}
|
||||
|
||||
public final boolean isSortDescending()
|
||||
{
|
||||
return _isSortDescending;
|
||||
}
|
||||
|
||||
public final boolean isSorted()
|
||||
{
|
||||
return _isSorted;
|
||||
}
|
||||
|
||||
public final void setSortDescending(boolean isDescending)
|
||||
{
|
||||
_isSortDescending = isDescending;
|
||||
}
|
||||
|
||||
public boolean sort()
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Object> newKeyList = new FastList<>();
|
||||
List<Integer> newValueList = new FastList<>();
|
||||
|
||||
// Sort the list of values in ascending numerical order.
|
||||
Collections.sort(getValues());
|
||||
|
||||
int lastValue = 0;
|
||||
|
||||
if (!isSortDescending())
|
||||
{
|
||||
// If there are no keys, just return the ascendingly sorted values.
|
||||
if (getKeys().isEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Iterate through the list of ordered numerical values.
|
||||
for (int i = getValues().size() - 1; i > -1; i--)
|
||||
{
|
||||
int currValue = getValues().get(i);
|
||||
|
||||
// If the current value is equal to the last value, we have at least one
|
||||
// duplicate that has been outputted already, so continue.
|
||||
if (currValue == lastValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set the last value to the current value, to prevent duplication.
|
||||
lastValue = currValue;
|
||||
|
||||
// Iterate through each key and match it to its stored integer value,
|
||||
// then output both sets of data in the correct descending numerical order.
|
||||
for (int j = 0; j < getKeys().size(); j++)
|
||||
{
|
||||
Object currKey = getKeys().get(j);
|
||||
|
||||
if (getValues().get(j) == currValue)
|
||||
{
|
||||
newKeyList.add(currKey);
|
||||
newValueList.add(currValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there are no keys, just sort the value list in reverse order.
|
||||
if (getKeys().isEmpty())
|
||||
{
|
||||
Collections.reverse(getValues());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do the exact same as above, but in descending order.
|
||||
for (int i = 0; i < getValues().size(); i++)
|
||||
{
|
||||
int currValue = getValues().get(i);
|
||||
|
||||
if (currValue == lastValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
lastValue = currValue;
|
||||
|
||||
for (int j = 0; j < getKeys().size(); j++)
|
||||
{
|
||||
Object currKey = getKeys().get(j);
|
||||
|
||||
if (getValues().get(j) == currValue)
|
||||
{
|
||||
newKeyList.add(currKey);
|
||||
newValueList.add(currValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_keyList = newKeyList;
|
||||
_valueList = newValueList;
|
||||
_isSorted = true;
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* $Header: Util.java, 21/10/2005 23:17:40 luisantonioa Exp $
|
||||
*
|
||||
* $Author: luisantonioa $
|
||||
* $Date: 21/10/2005 23:17:40 $
|
||||
* $Revision: 1 $
|
||||
* $Log: Util.java,v $
|
||||
* Revision 1 21/10/2005 23:17:40 luisantonioa
|
||||
* Added copyright notice
|
||||
*
|
||||
*
|
||||
* 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 com.l2jserver.gameserver.util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javolution.text.TextBuilder;
|
||||
|
||||
import com.l2jserver.gameserver.ThreadPoolManager;
|
||||
import com.l2jserver.gameserver.model.L2Object;
|
||||
import com.l2jserver.gameserver.model.actor.L2Character;
|
||||
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
|
||||
|
||||
/**
|
||||
* General Utility functions related to Gameserver
|
||||
*/
|
||||
public final class Util
|
||||
{
|
||||
public static void handleIllegalPlayerAction(L2PcInstance actor, String message, int punishment)
|
||||
{
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new IllegalPlayerAction(actor, message, punishment), 5000);
|
||||
}
|
||||
|
||||
public static String getRelativePath(File base, File file)
|
||||
{
|
||||
return file.toURI().getPath().substring(base.toURI().getPath().length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return degree value of object 2 to the horizontal line with object 1 being the origin
|
||||
*/
|
||||
public static double calculateAngleFrom(L2Object obj1, L2Object obj2)
|
||||
{
|
||||
return calculateAngleFrom(obj1.getX(), obj1.getY(), obj2.getX(), obj2.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return degree value of object 2 to the horizontal line with object 1 being the origin
|
||||
*/
|
||||
public final static double calculateAngleFrom(int obj1X, int obj1Y, int obj2X, int obj2Y)
|
||||
{
|
||||
double angleTarget = Math.toDegrees(Math.atan2(obj2Y - obj1Y, obj2X - obj1X));
|
||||
if (angleTarget < 0)
|
||||
{
|
||||
angleTarget = 360 + angleTarget;
|
||||
}
|
||||
return angleTarget;
|
||||
}
|
||||
|
||||
public final static double convertHeadingToDegree(int clientHeading)
|
||||
{
|
||||
double degree = clientHeading / 182.044444444;
|
||||
return degree;
|
||||
}
|
||||
|
||||
public final static int convertDegreeToClientHeading(double degree)
|
||||
{
|
||||
if (degree < 0)
|
||||
{
|
||||
degree = 360 + degree;
|
||||
}
|
||||
return (int) (degree * 182.044444444);
|
||||
}
|
||||
|
||||
public final static int calculateHeadingFrom(L2Object obj1, L2Object obj2)
|
||||
{
|
||||
return calculateHeadingFrom(obj1.getX(), obj1.getY(), obj2.getX(), obj2.getY());
|
||||
}
|
||||
|
||||
public final static int calculateHeadingFrom(int obj1X, int obj1Y, int obj2X, int obj2Y)
|
||||
{
|
||||
double angleTarget = Math.toDegrees(Math.atan2(obj2Y - obj1Y, obj2X - obj1X));
|
||||
if (angleTarget < 0)
|
||||
{
|
||||
angleTarget = 360 + angleTarget;
|
||||
}
|
||||
return (int) (angleTarget * 182.044444444);
|
||||
}
|
||||
|
||||
public final static int calculateHeadingFrom(double dx, double dy)
|
||||
{
|
||||
double angleTarget = Math.toDegrees(Math.atan2(dy, dx));
|
||||
if (angleTarget < 0)
|
||||
{
|
||||
angleTarget = 360 + angleTarget;
|
||||
}
|
||||
return (int) (angleTarget * 182.044444444);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the distance between the two coordinates in 2D plane
|
||||
*/
|
||||
public static double calculateDistance(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
return calculateDistance(x1, y1, 0, x2, y2, 0, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param includeZAxis - if true, includes also the Z axis in the calculation
|
||||
* @return the distance between the two coordinates
|
||||
*/
|
||||
public static double calculateDistance(int x1, int y1, int z1, int x2, int y2, int z2, boolean includeZAxis)
|
||||
{
|
||||
double dx = (double) x1 - x2;
|
||||
double dy = (double) y1 - y2;
|
||||
|
||||
if (includeZAxis)
|
||||
{
|
||||
double dz = z1 - z2;
|
||||
return Math.sqrt((dx * dx) + (dy * dy) + (dz * dz));
|
||||
}
|
||||
return Math.sqrt((dx * dx) + (dy * dy));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param includeZAxis - if true, includes also the Z axis in the calculation
|
||||
* @return the distance between the two objects
|
||||
*/
|
||||
public static double calculateDistance(L2Object obj1, L2Object obj2, boolean includeZAxis)
|
||||
{
|
||||
if ((obj1 == null) || (obj2 == null))
|
||||
{
|
||||
return 1000000;
|
||||
}
|
||||
|
||||
return calculateDistance(obj1.getPosition().getX(), obj1.getPosition().getY(), obj1.getPosition().getZ(), obj2.getPosition().getX(), obj2.getPosition().getY(), obj2.getPosition().getZ(), includeZAxis);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str - the string whose first letter to capitalize
|
||||
* @return a string with the first letter of the {@code str} capitalized
|
||||
*/
|
||||
public static String capitalizeFirst(String str)
|
||||
{
|
||||
if ((str == null) || str.isEmpty())
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
final char[] arr = str.toCharArray();
|
||||
final char c = arr[0];
|
||||
|
||||
if (Character.isLetter(c))
|
||||
{
|
||||
arr[0] = Character.toUpperCase(c);
|
||||
}
|
||||
|
||||
return arr.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* (Based on ucwords() function of PHP) DrHouse: still functional but must be rewritten to avoid += to concat strings
|
||||
* @param str - the string to capitalize
|
||||
* @return a string with the first letter of every word in {@code str} capitalized
|
||||
*/
|
||||
@Deprecated
|
||||
public static String capitalizeWords(String str)
|
||||
{
|
||||
if ((str == null) || str.isEmpty())
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
char[] charArray = str.toCharArray();
|
||||
String result = "";
|
||||
|
||||
// Capitalize the first letter in the given string!
|
||||
charArray[0] = Character.toUpperCase(charArray[0]);
|
||||
|
||||
for (int i = 0; i < charArray.length; i++)
|
||||
{
|
||||
if (Character.isWhitespace(charArray[i]))
|
||||
{
|
||||
charArray[i + 1] = Character.toUpperCase(charArray[i + 1]);
|
||||
}
|
||||
|
||||
result += Character.toString(charArray[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the two objects are within specified range between each other, {@code false} otherwise
|
||||
*/
|
||||
public static boolean checkIfInRange(int range, L2Object obj1, L2Object obj2, boolean includeZAxis)
|
||||
{
|
||||
if ((obj1 == null) || (obj2 == null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (obj1.getInstanceId() != obj2.getInstanceId())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (range == -1)
|
||||
{
|
||||
return true; // not limited
|
||||
}
|
||||
|
||||
int rad = 0;
|
||||
if (obj1 instanceof L2Character)
|
||||
{
|
||||
rad += ((L2Character) obj1).getTemplate().collisionRadius;
|
||||
}
|
||||
if (obj2 instanceof L2Character)
|
||||
{
|
||||
rad += ((L2Character) obj2).getTemplate().collisionRadius;
|
||||
}
|
||||
|
||||
double dx = obj1.getX() - obj2.getX();
|
||||
double dy = obj1.getY() - obj2.getY();
|
||||
|
||||
if (includeZAxis)
|
||||
{
|
||||
double dz = obj1.getZ() - obj2.getZ();
|
||||
double d = (dx * dx) + (dy * dy) + (dz * dz);
|
||||
|
||||
return d <= ((range * range) + (2 * range * rad) + (rad * rad));
|
||||
}
|
||||
double d = (dx * dx) + (dy * dy);
|
||||
|
||||
return d <= ((range * range) + (2 * range * rad) + (rad * rad));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if object is within short (sqrt(int.max_value)) radius, not using collisionRadius. Faster calculation than checkIfInRange if distance is short and collisionRadius isn't needed. Not for long distance checks (potential teleports, far away castles etc).
|
||||
* @param range - the maximum range between the two objects
|
||||
* @param includeZAxis - if true, check also Z axis (3-dimensional check), otherwise only 2D
|
||||
* @return {@code true} if objects are within specified range between each other, {@code false} otherwise
|
||||
*/
|
||||
public static boolean checkIfInShortRadius(int radius, L2Object obj1, L2Object obj2, boolean includeZAxis)
|
||||
{
|
||||
if ((obj1 == null) || (obj2 == null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (radius == -1)
|
||||
{
|
||||
return true; // not limited
|
||||
}
|
||||
|
||||
int dx = obj1.getX() - obj2.getX();
|
||||
int dy = obj1.getY() - obj2.getY();
|
||||
|
||||
if (includeZAxis)
|
||||
{
|
||||
int dz = obj1.getZ() - obj2.getZ();
|
||||
return ((dx * dx) + (dy * dy) + (dz * dz)) <= (radius * radius);
|
||||
}
|
||||
return ((dx * dx) + (dy * dy)) <= (radius * radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str - the String to count
|
||||
* @return the number of "words" in a given string.
|
||||
*/
|
||||
public static int countWords(String str)
|
||||
{
|
||||
return str.trim().split("\\s+").length;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Based on implode() in PHP)
|
||||
* @param strArray - an array of strings to concatenate
|
||||
* @param strDelim - the delimiter to put between the strings
|
||||
* @return a delimited string for a given array of string elements.
|
||||
*/
|
||||
public static String implodeString(Iterable<String> strArray, String strDelim)
|
||||
{
|
||||
final TextBuilder sbString = TextBuilder.newInstance();
|
||||
|
||||
for (String strValue : strArray)
|
||||
{
|
||||
sbString.append(strValue);
|
||||
sbString.append(strDelim);
|
||||
}
|
||||
|
||||
String result = sbString.toString();
|
||||
TextBuilder.recycle(sbString);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Based on round() in PHP)
|
||||
* @param number - the number to round
|
||||
* @param numPlaces - how many digits after decimal point to leave intact
|
||||
* @return the value of {@code number} rounded to specified number of digits after the decimal point.
|
||||
*/
|
||||
public static float roundTo(float number, int numPlaces)
|
||||
{
|
||||
if (numPlaces <= 1)
|
||||
{
|
||||
return Math.round(number);
|
||||
}
|
||||
|
||||
float exponent = (float) Math.pow(10, numPlaces);
|
||||
|
||||
return Math.round(number * exponent) / exponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param text - the text to check
|
||||
* @return {@code true} if {@code text} contains only numbers, {@code false} otherwise
|
||||
*/
|
||||
public static boolean isDigit(String text)
|
||||
{
|
||||
if ((text == null) || text.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (char c : text.toCharArray())
|
||||
{
|
||||
if (!Character.isDigit(c))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param text - the text to check
|
||||
* @return {@code true} if {@code text} contains only letters and/or numbers, {@code false} otherwise
|
||||
*/
|
||||
public static boolean isAlphaNumeric(String text)
|
||||
{
|
||||
if ((text == null) || text.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (char c : text.toCharArray())
|
||||
{
|
||||
if (!Character.isLetterOrDigit(c))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the specified digit using the digit grouping symbol "," (comma). For example, 123456789 becomes 123,456,789.
|
||||
* @param amount - the amount of adena
|
||||
* @return the formatted adena amount
|
||||
*/
|
||||
public static String formatAdena(long amount)
|
||||
{
|
||||
String s = "";
|
||||
long rem = amount % 1000;
|
||||
s = Long.toString(rem);
|
||||
amount = (amount - rem) / 1000;
|
||||
while (amount > 0)
|
||||
{
|
||||
if (rem < 99)
|
||||
{
|
||||
s = '0' + s;
|
||||
}
|
||||
if (rem < 9)
|
||||
{
|
||||
s = '0' + s;
|
||||
}
|
||||
rem = amount % 1000;
|
||||
s = Long.toString(rem) + "," + s;
|
||||
amount = (amount - rem) / 1000;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array - the array to look into
|
||||
* @param obj - the object to search for
|
||||
* @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise
|
||||
*/
|
||||
public static <T> boolean contains(T[] array, T obj)
|
||||
{
|
||||
for (T element : array)
|
||||
{
|
||||
if (element == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array - the array to look into
|
||||
* @param obj - the integer to search for
|
||||
* @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise
|
||||
*/
|
||||
public static boolean contains(int[] array, int obj)
|
||||
{
|
||||
for (int element : array)
|
||||
{
|
||||
if (element == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user