Index: C:/workspace/L2_GameServer/java/config/altsettings.properties =================================================================== --- C:/workspace/L2_GameServer/java/config/altsettings.properties (revision 2218) +++ C:/workspace/L2_GameServer/java/config/altsettings.properties (working copy) @@ -20,6 +20,11 @@ # - players get EXP/SP for crafting AltGameCreation = False +# Alt game creation XP/SP based on mana +# new XP/SP reward system, calculation based on +# mana used to craft item +AltGameCreationByMana = False + # Alternative skill learn rules: # - all classes can learn all skills # - skills of another class costs x2 SP Index: C:/workspace/L2_GameServer/java/net/sf/l2j/status/Status.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/status/Status.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/status/Status.java (working copy) @@ -43,6 +43,7 @@ if(lst.isAlive()) { _loginStatus.add(lst); + lst.setPriority(lst.getPriority()+1); // raise priority a bit } } if (this.isInterrupted()) Index: C:/workspace/L2_GameServer/java/net/sf/l2j/status/GameStatusThread.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/status/GameStatusThread.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/status/GameStatusThread.java (working copy) @@ -245,6 +246,12 @@ { _print.println(line); } + _print.println(); + // maxMemory is the upper limit the jvm can use, totalMemory the size of the current allocation pool, freeMemory the unused memory in the allocation pool + long freeMem = (Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory()+Runtime.getRuntime().freeMemory()) / 1024 / 1024; + long totalMem = Runtime.getRuntime().maxMemory() / 1024 / 1024; + _print.println("Free memory "+freeMem+" Mb of "+totalMem+" Mb total"); + _print.println(); _print.flush(); } else if (_usrCommand.startsWith("announce")) Index: C:/workspace/L2_GameServer/java/net/sf/l2j/Config.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/Config.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/Config.java (working copy) @@ -72,8 +72,11 @@ /** Thread pools size */ public static int THREAD_P_HIGH; + public static int THREAD_P_MEDHIGH; public static int THREAD_P_MED; public static int THREAD_P_LOW; + public static int THREAD_P_AI; + public static int THREAD_P_CRAFT; /** Auto-loot? */ public static boolean AUTO_LOOT; @@ -83,10 +86,16 @@ /** Global chat state */ public static String DEFAULT_GLOBAL_CHAT; + /** For test servers - evrybody has admin rights */ public static boolean EVERYBODY_HAS_ADMIN_RIGHTS; + /** Alternative game crafting */ public static boolean ALT_GAME_CREATION; + + /** Reward XP/SP to crafter based on mana **/ + public static boolean ALT_GAME_CREATION_BY_MANA; + /** Alternative game skill learning */ public static boolean ALT_GAME_SKILL_LEARN; /** Cancel ATTACK/cast by hit */ @@ -388,9 +400,11 @@ public static int EXECUTOR_PRI_LOW; public static int EXECUTOR_PRI_MED; + public static int EXECUTOR_PRI_MEDHIGH; public static int EXECUTOR_PRI_HIGH; - - + public static int EXECUTOR_PRI_AI; + public static int EXECUTOR_PRI_CRAFT; + public static enum IdFactoryType { Compaction, @@ -586,8 +606,11 @@ AUTODELETE_INVALID_QUEST_DATA = Boolean.valueOf(serverSettings.getProperty("AutoDeleteInvalidQuestData", "False")); THREAD_P_HIGH = Integer.parseInt(serverSettings.getProperty("ThreadPoolSizeHigh", "4")); - THREAD_P_MED = Integer.parseInt(serverSettings.getProperty("ThreadPoolSizeMed", "10")); - THREAD_P_LOW = Integer.parseInt(serverSettings.getProperty("ThreadPoolSizeLow", "4")); + THREAD_P_MEDHIGH = Integer.parseInt(serverSettings.getProperty("ThreadPoolSizeMedHigh","4")); + THREAD_P_MED = Integer.parseInt(serverSettings.getProperty("ThreadPoolSizeMed", "4")); + THREAD_P_LOW = Integer.parseInt(serverSettings.getProperty("ThreadPoolSizeLow", "4")); + THREAD_P_AI = Integer.parseInt(serverSettings.getProperty("ThreadPoolSizeAi", "4")); + THREAD_P_CRAFT = Integer.parseInt(serverSettings.getProperty("ThreadPoolSizeCraft", "4")); MAXIMUM_ONLINE_USERS = Integer.parseInt(serverSettings.getProperty("MaximumOnlineUsers", "100")); @@ -620,7 +643,10 @@ EXECUTOR_PRI_LOW = Integer.parseInt(serverSettings.getProperty("ExecutorPriLow", "-1")); EXECUTOR_PRI_MED = Integer.parseInt(serverSettings.getProperty("ExecutorPriMed", "0")); - EXECUTOR_PRI_HIGH = Integer.parseInt(serverSettings.getProperty("ExecutorPriHigh", "1")); + EXECUTOR_PRI_MEDHIGH = Integer.parseInt(serverSettings.getProperty("ExecutorPriMedHigh", "1")); + EXECUTOR_PRI_HIGH = Integer.parseInt(serverSettings.getProperty("ExecutorPriHigh", "2")); + EXECUTOR_PRI_AI = Integer.parseInt(serverSettings.getProperty("ExecutorPriAi", "0")); + EXECUTOR_PRI_CRAFT = Integer.parseInt(serverSettings.getProperty("ExecutorPriCraft", "0")); } catch (Exception e) { @@ -793,25 +826,26 @@ altSettings.load(is); is.close(); - ALT_GAME_TIREDNESS = Boolean.parseBoolean(altSettings.getProperty("AltGameTiredness", "false")); - ALT_GAME_CREATION = Boolean.parseBoolean(altSettings.getProperty("AltGameCreation", "false")); - ALT_GAME_SKILL_LEARN = Boolean.parseBoolean(altSettings.getProperty("AltGameSkillLearn", "false")); - ALT_GAME_CANCEL_BOW = altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("bow") || altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("all"); - ALT_GAME_CANCEL_CAST = altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("cast") || altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("all"); - ALT_GAME_SHIELD_BLOCKS = Boolean.parseBoolean(altSettings.getProperty("AltShieldBlocks", "false")); - ALT_GAME_DELEVEL = Boolean.parseBoolean(altSettings.getProperty("Delevel", "true")); - ALT_GAME_MOB_ATTACK_AI = Boolean.parseBoolean(altSettings.getProperty("AltGameMobAttackAI", "false")); - ALT_GAME_SKILL_FORMULAS = altSettings.getProperty("AltGameSkillFormulas", "none"); - ALT_GAME_EXPONENT_XP = Float.parseFloat(altSettings.getProperty("AltGameExponentXp", "0.")); - ALT_GAME_EXPONENT_SP = Float.parseFloat(altSettings.getProperty("AltGameExponentSp", "0.")); - ALLOW_CLASS_MASTERS = Boolean.valueOf(altSettings.getProperty("AllowClassMasters", "False")); - ALT_GAME_FREIGHTS = Boolean.parseBoolean(altSettings.getProperty("AltGameFreights", "false")); - ALT_GAME_FREIGHT_PRICE = Integer.parseInt(altSettings.getProperty("AltGameFreightPrice", "1000")); - ALT_GAME_SKILL_HIT_RATE = Float.parseFloat(altSettings.getProperty("AltGameSkillHitRate", "1.")); - ENABLE_RATE_HP = Boolean.parseBoolean(altSettings.getProperty("EnableRateHp", "false")); - IS_CRAFTING_ENABLED = Boolean.parseBoolean(altSettings.getProperty("CraftingEnabled", "true")); - SP_BOOK_NEEDED = Boolean.parseBoolean(altSettings.getProperty("SpBookNeeded", "true")); - AUTO_LOOT = altSettings.getProperty("AutoLoot").equalsIgnoreCase("True"); + ALT_GAME_TIREDNESS = Boolean.parseBoolean(altSettings.getProperty("AltGameTiredness", "false")); + ALT_GAME_CREATION = Boolean.parseBoolean(altSettings.getProperty("AltGameCreation", "false")); + ALT_GAME_CREATION_BY_MANA = Boolean.parseBoolean(altSettings.getProperty("AltGameCreationByMana", "false")); + ALT_GAME_SKILL_LEARN = Boolean.parseBoolean(altSettings.getProperty("AltGameSkillLearn", "false")); + ALT_GAME_CANCEL_BOW = altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("bow") || altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("all"); + ALT_GAME_CANCEL_CAST = altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("cast") || altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("all"); + ALT_GAME_SHIELD_BLOCKS = Boolean.parseBoolean(altSettings.getProperty("AltShieldBlocks", "false")); + ALT_GAME_DELEVEL = Boolean.parseBoolean(altSettings.getProperty("Delevel", "true")); + ALT_GAME_MOB_ATTACK_AI = Boolean.parseBoolean(altSettings.getProperty("AltGameMobAttackAI", "false")); + ALT_GAME_SKILL_FORMULAS = altSettings.getProperty("AltGameSkillFormulas", "none"); + ALT_GAME_EXPONENT_XP = Float.parseFloat(altSettings.getProperty("AltGameExponentXp", "0.")); + ALT_GAME_EXPONENT_SP = Float.parseFloat(altSettings.getProperty("AltGameExponentSp", "0.")); + ALLOW_CLASS_MASTERS = Boolean.valueOf(altSettings.getProperty("AllowClassMasters", "False")); + ALT_GAME_FREIGHTS = Boolean.parseBoolean(altSettings.getProperty("AltGameFreights", "false")); + ALT_GAME_FREIGHT_PRICE = Integer.parseInt(altSettings.getProperty("AltGameFreightPrice", "1000")); + ALT_GAME_SKILL_HIT_RATE = Float.parseFloat(altSettings.getProperty("AltGameSkillHitRate", "1.")); + ENABLE_RATE_HP = Boolean.parseBoolean(altSettings.getProperty("EnableRateHp", "false")); + IS_CRAFTING_ENABLED = Boolean.parseBoolean(altSettings.getProperty("CraftingEnabled", "true")); + SP_BOOK_NEEDED = Boolean.parseBoolean(altSettings.getProperty("SpBookNeeded", "true")); + AUTO_LOOT = altSettings.getProperty("AutoLoot").equalsIgnoreCase("True"); ALT_GAME_KARMA_PLAYER_CAN_BE_KILLED_IN_PEACEZONE = Boolean.valueOf(altSettings.getProperty("AltKarmaPlayerCanBeKilledInPeaceZone", "false")); ALT_GAME_KARMA_PLAYER_CAN_SHOP = Boolean.valueOf(altSettings.getProperty("AltKarmaPlayerCanShop", "true")); ALT_GAME_KARMA_PLAYER_CAN_TELEPORT = Boolean.valueOf(altSettings.getProperty("AltKarmaPlayerCanTeleport", "true")); Index: C:/workspace/L2_GameServer/java/net/sf/l2j/Server.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/Server.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/Server.java (working copy) @@ -79,6 +79,7 @@ if ( Config.IS_TELNET_ENABLED ) { statusServer = new Status(0); statusServer.start(); + statusServer.setPriority(statusServer.getPriority()+1); // telnet is very important, even on high cpu load this should make it work properly } else { System.out.println("Telnet server is currently disabled."); Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/SelectorThread.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/SelectorThread.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/SelectorThread.java (working copy) @@ -146,7 +146,7 @@ this._hostname = hostname; this._port = port; this.setDaemon(true); - this.setPriority(Thread.NORM_PRIORITY+1); + this.setPriority(Thread.NORM_PRIORITY+2); // write buffers (HeapByteBuffer is much faster for our perposes) writeBuffers = new ByteBuffer[WRITE_BUF_HASH_SIZE]; for (int i=0; i < WRITE_BUF_HASH_SIZE; i++) { @@ -723,7 +723,7 @@ packetHistory.clear(); byteHistory.clear(); - packetMonitor = ClientScheduler.getInstance().scheduleLowAtFixedRate( + packetMonitor = ClientScheduler.getInstance().scheduleMedAtFixedRate( new Runnable() { public void run() Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/clientpackets/RequestRecipeItemMakeSelf.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/clientpackets/RequestRecipeItemMakeSelf.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/clientpackets/RequestRecipeItemMakeSelf.java (working copy) @@ -19,8 +19,10 @@ package net.sf.l2j.gameserver.clientpackets; import java.nio.ByteBuffer; +import java.util.logging.Logger; import net.sf.l2j.gameserver.ClientThread; +import net.sf.l2j.gameserver.GameServer; import net.sf.l2j.gameserver.RecipeController; import net.sf.l2j.gameserver.model.L2PcInstance; @@ -33,7 +35,7 @@ public class RequestRecipeItemMakeSelf extends ClientBasePacket { private static final String _C__AF_REQUESTRECIPEITEMMAKESELF = "[C] AF RequestRecipeItemMakeSelf"; - //private static Logger _log = Logger.getLogger(RequestSellItem.class.getName()); + private static final Logger _log = Logger.getLogger(RequestRecipeItemMakeSelf.class.getName()); private final int _id; /** @@ -60,6 +62,7 @@ if (activeChar.isInCraftMode()) { activeChar.sendMessage("Currently in Craft Mode"); + _log.warning("Currently in Craft Mode"); return; } Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Potion.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Potion.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Potion.java (working copy) @@ -24,7 +24,6 @@ import net.sf.l2j.Config; import net.sf.l2j.gameserver.ClientScheduler; - /** * * This class ... @@ -65,15 +64,13 @@ { double nowHp = _instance.getCurrentHp(); if(_duration == 0) - { stopPotionHpRegeneration(); - } - if (_duration != 0) + else { nowHp += _effect; _instance.setCurrentHp(nowHp); - _duration = _duration - (_milliseconds / 1000); - setCurrentHpPotion2(); + _duration -= (_milliseconds / 1000); + if(_duration==0) stopPotionHpRegeneration(); } } } @@ -100,13 +97,6 @@ if (Config.DEBUG) _log.fine("Potion HP regen stop"); } - public void setCurrentHpPotion2() - { - if (_duration == 0) - { - stopPotionHpRegeneration(); - } - } public void setCurrentHpPotion1(L2Character activeChar, int item) { _potion = item; @@ -114,23 +104,8 @@ switch (_potion) { - case (1540): - double nowHp = activeChar.getCurrentHp(); - nowHp+=435; - if (nowHp>= activeChar.getMaxHp()) - { - nowHp = activeChar.getMaxHp(); - } - activeChar.setCurrentHp(nowHp); - case (728): - double nowMp = activeChar.getMaxMp(); - nowMp+=435; - if (nowMp>= activeChar.getMaxMp()) - { - nowMp = activeChar.getMaxMp(); - } - activeChar.setCurrentMp(nowMp); - break; + case (1540): activeChar.setCurrentHp(java.lang.Math.min(activeChar.getCurrentHp()+435,(double)activeChar.getMaxHp()));break; + case (728) : activeChar.setCurrentMp(java.lang.Math.min(activeChar.getCurrentMp()+435,(double)activeChar.getMaxMp()));break; case (726): _milliseconds = 500; _duration = 15; @@ -157,16 +132,13 @@ { double nowMp = _instance.getCurrentMp(); if(_duration == 0) + stopPotionMpRegeneration(); + else { - stopPotionMpRegeneration(); - } - if (_duration != 0) - { nowMp+=_effect; _instance.setCurrentMp(nowMp); _duration=(_duration-(_milliseconds/1000)); - setCurrentMpPotion2(); - + if(_duration == 0) stopPotionMpRegeneration(); } } } @@ -179,7 +151,7 @@ private void startPotionMpRegeneration(L2Character activeChar) { - _potionmpRegTask = ClientScheduler.getInstance().scheduleMedAtFixedRate( + _potionmpRegTask = ClientScheduler.getInstance().scheduleMedHighAtFixedRate( new PotionMpHealing(activeChar), 1000, _milliseconds); if (Config.DEBUG) _log.fine("Potion MP regen Started"); } @@ -195,14 +167,6 @@ if (Config.DEBUG) _log.fine("Potion MP regen stop"); } - public void setCurrentMpPotion2() - { - if (_duration == 0) - { - stopPotionMpRegeneration(); - } - } - public void setCurrentMpPotion1(L2Character activeChar, int item) { _potion = item; Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/actor/character/CharStatus.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/actor/character/CharStatus.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/actor/character/CharStatus.java (working copy) @@ -187,7 +187,7 @@ int period = Formulas.getInstance().getRegeneratePeriod(getActiveChar()); // Create the HP/MP/CP Regeneration task - _RegTask = ClientScheduler.getInstance().scheduleMedAtFixedRate(new RegenTask(), period, period); + _RegTask = ClientScheduler.getInstance().scheduleMedHighAtFixedRate(new RegenTask(), period, period); } } Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2MonsterInstance.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2MonsterInstance.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2MonsterInstance.java (working copy) @@ -109,9 +109,7 @@ try { minionList.maintainMinions(); - //must be fixed. class exception. - //for(L2MinionInstance minion : minionList.getSpawnedMinions()) - // minion.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, this); + callMinions(); } catch (Throwable e) { @@ -145,7 +143,8 @@ Random rnd = getRnd(); int minionX = masterX + (rnd.nextInt(401) - 200); int minionY = masterY + (rnd.nextInt(401) - 200); - int minionZ = masterZ; + int minionZ = masterZ+50; // just in case master is on high ground, shouldn't hurt ? while (((minionX != (masterX + 30)) && (minionX != (masterX - 30))) || ((minionY != (masterY + 30)) && (minionY != (masterY - 30)))) { minionX = masterX + (rnd.nextInt(401) - 200); @@ -186,7 +183,7 @@ { if (minionMaintainTask != null) minionMaintainTask.cancel(true); - + minionMaintainTask=null; super.doDie(killer); } Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Clan.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Clan.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Clan.java (working copy) @@ -118,6 +127,7 @@ */ public int getLeaderId() { + if (_leader==null) setNewLeader(); return _leader.getObjectId(); } /** @@ -125,6 +135,7 @@ */ public L2ClanMember getLeader() { + if (_leader==null) setNewLeader(); return _leader; } /** @@ -160,7 +172,8 @@ */ public String getLeaderName() { - return _leader.getName(); + if (_leader==null) setNewLeader(); + return _leader.getName(); } /** Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Skill.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Skill.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Skill.java (working copy) @@ -159,7 +159,8 @@ DRAIN_SOUL, // unimplemented - NOTDONE; + NOTDONE, + MDAM_ELEMENTAL; private final Class clazz; Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Attackable.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Attackable.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/model/L2Attackable.java (working copy) @@ -339,7 +339,7 @@ if (this instanceof L2MinionInstance) { master = ((L2MinionInstance)this).getLeader(); - if (!master.isInCombat()) + if (!master.isInCombat()&&!master.isDead()) master.addDamage(attacker, 1); } if (master.hasMinions()) Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ai/L2AttackableAI.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ai/L2AttackableAI.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ai/L2AttackableAI.java (working copy) @@ -206,45 +206,53 @@ */ synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1) { - if (intention == AI_INTENTION_IDLE || intention == AI_INTENTION_ACTIVE) + if (intention == AI_INTENTION_ACTIVE) + { + intention = AI_INTENTION_IDLE; // suppose we don't need AI anymore + + // Check if actor is not dead + if(!_actor.isAlikeDead()) + { + // find at least one L2PcInstance worth keeping AI active (in knownlist but also not dead) + for(L2PcInstance in:((L2Attackable)_actor).getKnownList().getKnownPlayers()) + { + if(in!=null && !in.isAlikeDead()) + { + intention=AI_INTENTION_ACTIVE; // found one, worth activating + break; + } + } + } + } + + // ================================================================== + + if (intention == AI_INTENTION_IDLE) { - // Check if actor is not dead - if (!_actor.isAlikeDead()) + // Set the Intention of this L2AttackableAI to AI_INTENTION_IDLE + super.changeIntention(AI_INTENTION_IDLE, null, null); + + // Stop AI task and detach AI from NPC + if (aiTask != null) { - L2Attackable npc = (L2Attackable)_actor; - - // If its _knownPlayer isn't empty set the Intention to AI_INTENTION_ACTIVE - Collection knownPlayers = npc.getKnownList().getKnownPlayers(); - if (knownPlayers != null && knownPlayers.size() > 0) - intention = AI_INTENTION_ACTIVE; + aiTask.cancel(true); + aiTask = null; } - - if (intention == AI_INTENTION_IDLE) - { - // Set the Intention of this L2AttackableAI to AI_INTENTION_IDLE - super.changeIntention(AI_INTENTION_IDLE, null, null); - - // Stop AI task and detach AI from NPC - if (aiTask != null) - { - aiTask.cancel(true); - aiTask = null; - } - // Cancel the AI - _accessor.detachAI(); + // Cancel the AI + _accessor.detachAI(); - return; - } + return; } + // Set the Intention of this L2AttackableAI to intention super.changeIntention(intention, arg0, arg1); // If not idle - create an AI task (schedule onEvtThink repeatedly) if (aiTask == null) { - aiTask = ClientScheduler.getInstance().scheduleLowAtFixedRate(this, 1000, 1000); + aiTask = ClientScheduler.getInstance().scheduleAiAtFixedRate(this, 1000, 1000); } } @@ -351,7 +359,7 @@ // Order to the L2Attackable to attack the target - if (hated != null) + if (hated != null && !hated.isAlikeDead()) { // Get the hate level of the L2Attackable against this L2Character target contained in _aggroList int aggro = npc.getHating(hated); Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ai/L2PlayerAI.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ai/L2PlayerAI.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ai/L2PlayerAI.java (working copy) @@ -255,6 +255,8 @@ private void thinkPickUp() { if (_actor.isAllSkillsDisabled()) return; + if (_actor.isAlikeDead()) + return; if (checkTargetLost(getTarget())) return; if (maybeMoveToPawn(getTarget(), 36)) @@ -155,40 +153,41 @@ */ synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1) { - if (Config.DEBUG) - _log.info("L2SiegeAI.changeIntention(" + intention + ", " + arg0 + ", " + arg1+")"); + if (intention == AI_INTENTION_ACTIVE) + { + intention = AI_INTENTION_IDLE; - if (intention == AI_INTENTION_IDLE || intention == AI_INTENTION_ACTIVE) - { // Check if actor is not dead if(!_actor.isAlikeDead()) { - L2Attackable npc = (L2Attackable)_actor; - - // If its _knownPlayer isn't empty set the Intention to AI_INTENTION_ACTIVE - if(npc.getKnownList().getKnownPlayers().size() > 0) - intention = AI_INTENTION_ACTIVE; - else - intention = AI_INTENTION_IDLE; + // find at least one L2PcInstance worth keeping AI active (in knownlist but also not dead) + for(L2PcInstance in:((L2Attackable)_actor).getKnownList().getKnownPlayers()) + { + if(in!=null && !in.isAlikeDead()) + { + intention=AI_INTENTION_ACTIVE; // found one, worth activating + break; + } + } } + } - if (intention == AI_INTENTION_IDLE) + if (intention == AI_INTENTION_IDLE) + { + // Set the Intention of this L2AttackableAI to AI_INTENTION_IDLE + super.changeIntention(AI_INTENTION_IDLE, null, null); + + // Stop AI task and detach AI from NPC + if (aiTask != null) { - // Set the Intention of this L2AttackableAI to AI_INTENTION_IDLE - super.changeIntention(AI_INTENTION_IDLE, null, null); - - // Stop AI task and detach AI from NPC - if (aiTask != null) - { - aiTask.cancel(true); - aiTask = null; - } + aiTask.cancel(true); + aiTask = null; + } - // Cancel the AI - _accessor.detachAI(); + // Cancel the AI + _accessor.detachAI(); - return; - } + return; } // Set the Intention of this L2AttackableAI to intention @@ -197,7 +196,7 @@ // If not idle - create an AI task (schedule onEvtThink repeatedly) if (aiTask == null) { - aiTask = ClientScheduler.getInstance().scheduleLowAtFixedRate(this, 1000, 1000); + aiTask = ClientScheduler.getInstance().scheduleAiAtFixedRate(this, 1000, 1000); } } @@ -562,11 +561,22 @@ { // if(getIntention() != AI_INTENTION_IDLE && (!_actor.isVisible() || !_actor.hasAI() || !_actor.isKnownPlayers())) // setIntention(AI_INTENTION_IDLE); + + // Check if the actor can't use skills and if a thinking action isn't already in progress + if (thinking || _actor.isAllSkillsDisabled()) + return; + + if((!_actor.isVisible()) || (!_actor.hasAI())) + setIntention(AI_INTENTION_IDLE); + if((getIntention() == AI_INTENTION_FOLLOW) && (_actor.getKnownList().getKnownPlayers().isEmpty())) + setIntention(AI_INTENTION_IDLE); + + if(getIntention() == AI_INTENTION_IDLE) + return; + // Check if the actor can't use skills and if a thinking action isn't already in progress - if (thinking || _actor.isAllSkillsDisabled()) - return; - + // Start thinking action thinking = true; @@ -599,6 +609,12 @@ */ protected void onEvtAttacked(L2Character attacker) { + if(attacker==null) + { + _log.warning("L2SiegeGuardAI.java: onEvtAttacked(L2Character attacker) -> attacker=null, RETURNING with setting attacktimeout"); + _attack_timeout = GameTimeController.getGameTicks(); + return; + } // Calculate the attack timeout _attack_timeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks(); @@ -655,9 +671,8 @@ if (!_actor.isRunning()) _actor.setRunning(); - L2SiegeGuardInstance sGuard = (L2SiegeGuardInstance)_actor; - double homeX = target.getX() - sGuard.getHomeX(); - double homeY = target.getY() - sGuard.getHomeY(); + double homeX = target.getX() - ((L2SiegeGuardInstance)_actor).getHomeX(); + double homeY = target.getY() - ((L2SiegeGuardInstance)_actor).getHomeY(); // Check if the L2SiegeGuardInstance is not too far from its home location if (homeX*homeX+homeY*homeY < 1200*1200) Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ai/AbstractAI.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ai/AbstractAI.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ai/AbstractAI.java (working copy) @@ -29,6 +29,7 @@ import net.sf.l2j.gameserver.ClientScheduler; import net.sf.l2j.gameserver.GameTimeController; import net.sf.l2j.gameserver.model.L2CharPosition; +import net.sf.l2j.gameserver.model.L2Attackable; import net.sf.l2j.gameserver.model.L2Character; import net.sf.l2j.gameserver.model.L2Object; import net.sf.l2j.gameserver.model.L2PcInstance; @@ -714,7 +715,7 @@ // Create and Launch an AI Follow Task to execute every 1s _follow_target = target; - _follow_task = ClientScheduler.getInstance().scheduleMedAtFixedRate(new FollowTask(), 5, FOLLOW_INTERVAL); + _follow_task = ClientScheduler.getInstance().scheduleAiAtFixedRate(new FollowTask(), 5, FOLLOW_INTERVAL); } /** @@ -732,7 +733,7 @@ } _follow_target = target; - _follow_task = ClientScheduler.getInstance().scheduleMedAtFixedRate(new FollowTask(range), 5, ATTACK_FOLLOW_INTERVAL); + _follow_task = ClientScheduler.getInstance().scheduleAiAtFixedRate(new FollowTask(range), 5, ATTACK_FOLLOW_INTERVAL); } /** Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/RecipeController.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/RecipeController.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/RecipeController.java (working copy) @@ -16,8 +16,20 @@ * * http://www.gnu.org/copyleft/gpl.html */ + + + + + package net.sf.l2j.gameserver; - +///// +//// +/// +// This file is now overcomented to explain all the changes +// in detail. Feel free to remove them if it makes you happy +/// +//// +///// import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -55,524 +67,687 @@ public class RecipeController { - protected static Logger _log = Logger.getLogger(RecipeController.class.getName()); - private static RecipeController _instance; + protected static Logger _log = Logger.getLogger(RecipeController.class.getName()); + private static RecipeController _instance; + + private Map _lists; + + protected static Map activeMakers = Collections.synchronizedMap(new WeakHashMap()); - private Map _lists; - - protected static Map activeMakers = Collections.synchronizedMap(new WeakHashMap()); - protected static final Random _rnd = new Random(); - - public static RecipeController getInstance() - { - if (_instance == null) - { - _instance = new RecipeController(); - } - return _instance; - } - - public RecipeController() - { - _lists = new FastMap(); - String line = null; - LineNumberReader lnr = null; - - try - { - File recipesData = new File(Config.DATAPACK_ROOT, "data/recipes.csv"); - lnr = new LineNumberReader(new BufferedReader( new FileReader(recipesData))); - - while ((line=lnr.readLine()) != null) - { - if (line.trim().length() == 0 || line.startsWith("#")) - { - continue; - } - - parseList(line); - - } - _log.config("RecipeController: Loaded "+_lists.size()+" Recipes."); - } - catch (Exception e) - { - if (lnr != null) - { - _log.log(Level.WARNING, "error while creating recipe controller in linenr: "+lnr.getLineNumber(), e); - } - else - { - _log.warning("No recipes were found in data folder"); - } - } + + public static RecipeController getInstance() + { + if (_instance == null) + { + _instance = new RecipeController(); + } + return _instance; + } + + public RecipeController() + { + _lists = new FastMap(); + String line = null; + LineNumberReader lnr = null; + + try + { + File recipesData = new File(Config.DATAPACK_ROOT, "data/recipes.csv"); + lnr = new LineNumberReader(new BufferedReader( new FileReader(recipesData))); + + while ((line=lnr.readLine()) != null) + { + if (line.trim().length() == 0 || line.startsWith("#")) + { + continue; + } + + parseList(line); + + } + _log.config("RecipeController: Loaded "+_lists.size()+" Recipes."); + } + catch (Exception e) + { + if (lnr != null) + { + _log.log(Level.WARNING, "error while creating recipe controller in linenr: "+lnr.getLineNumber(), e); + } + else + { + _log.warning("No recipes were found in data folder"); + } + } finally { try { lnr.close(); } catch (Exception e) { } } - } - - public int getRecipesCount() - { - return _lists.size(); - } - - public L2RecipeList getRecipeList(int listId) - { - return _lists.get(listId); - } - - public L2RecipeList getRecipeByItemId(int itemId) - { - for (int i = 0; i < _lists.size(); i++) - { - L2RecipeList find = _lists.get(new Integer(i)); - if (find.getRecipeId() == itemId) - { - return find; - } - } - return null; - } - - public synchronized void requestBookOpen(L2PcInstance player) - { - if (!Config.ALT_GAME_CREATION){ - RecipeBookItemList response = new RecipeBookItemList(); - response.addRecipes(player.getRecipeBook()); - player.sendPacket(response); - return; - } - ReceipeItemMaker maker = activeMakers.get(player); + } + + public int getRecipesCount() + { + return _lists.size(); + } + public L2RecipeList getRecipeList(int listId) + { + return _lists.get(listId); + } + public L2RecipeList getRecipeByItemId(int itemId) + { + for (int i = 0; i < _lists.size(); i++) + { + L2RecipeList find = _lists.get(new Integer(i)); + if (find.getRecipeId() == itemId) + { + return find; + } + } + return null; + } + + public synchronized void requestBookOpen(L2PcInstance player) + { + RecipeItemMaker maker=null; + + // @@todo: this must be removed, but also made sure it will happen only if realy crafting + if (Config.ALT_GAME_CREATION) + { + maker = activeMakers.get(player); + if(!player.isInCraftMode() && maker!=null) + { + activeMakers.remove(player); + if (Config.DEBUG) + _log.fine("removed "+player.getName()+" from activeMakers by force, trust only isInCraftMode for acurate state"); + } + } + if (maker == null) { - RecipeBookItemList response = new RecipeBookItemList(); - response.addRecipes(player.getRecipeBook()); - player.sendPacket(response); - return; + RecipeBookItemList response = new RecipeBookItemList(); + response.addRecipes(player.getRecipeBook()); + player.sendPacket(response); + return; } - if (maker.timeReady <= GameTimeController.getGameTicks()) { - maker.run(); - return; - } + + if (Config.DEBUG) _log.fine("requestBookOpen: Busy creating"); SystemMessage sm = new SystemMessage(614); sm.addString("You are busy creating "); sm.addItemName(maker.recipeList.getItemId()); player.sendPacket(sm); return; - } - - public synchronized void requestManufactureItem(L2PcInstance manufacturer, int recipeListId, L2PcInstance player) - { - L2RecipeList recipeList = getRecipeList(recipeListId-1); - - SystemMessage sm = new SystemMessage(614); + } + + public synchronized void requestManufactureItem(L2PcInstance manufacturer, int recipeListId, L2PcInstance customer) + { + L2RecipeList recipeList = getRecipeList(recipeListId-1); + SystemMessage sm = new SystemMessage(614); - manufacturer.isInCraftMode(true); - if ((recipeList == null) || (recipeList.getRecipes().length == 0)) - { - sm = new SystemMessage(614); - sm.addString("No recipe for: " + recipeListId); - player.sendPacket(sm); - manufacturer.isInCraftMode(false); - return; - } - if (!Config.ALT_GAME_CREATION) { - new ReceipeItemMaker(manufacturer, recipeList, player); - } else { - ReceipeItemMaker maker = activeMakers.get(manufacturer); - if (maker != null) - { - sm = new SystemMessage(614); - sm.addString("Manufacturer are busy creating."); - sm.addItemName(recipeList.getItemId()); - player.sendPacket(sm); - manufacturer.isInCraftMode(false); - return; - } - maker = new ReceipeItemMaker(manufacturer, recipeList, player); - if (maker.isValid) - activeMakers.put(manufacturer, maker); - } - } - public synchronized void requestMakeItem(L2PcInstance player, int recipeListId) - { - L2RecipeList recipeList = getRecipeList(recipeListId-1); - - SystemMessage sm = new SystemMessage(614); + if(manufacturer.isInCraftMode()) + { + if(Config.DEBUG) _log.fine("requestManufactureItem called but manufacturer is in craft mode"); + sm = new SystemMessage(614); + sm.addString("Manufacturer is busy."); + sm.addItemName(recipeList.getItemId()); + customer.sendPacket(sm); + return; + } - player.isInCraftMode(true); - if ((recipeList == null) || (recipeList.getRecipes().length == 0)) - { - sm = new SystemMessage(614); - sm.addString("No recipe for: " + recipeListId); - player.sendPacket(sm); - player.isInCraftMode(false); - return; - } - if (!Config.ALT_GAME_CREATION) { - new ReceipeItemMaker(player, recipeList, null); - } else { - ReceipeItemMaker maker = activeMakers.get(player); - if (maker != null) - { - sm = new SystemMessage(614); - sm.addString("You are busy creating "); - sm.addItemName(recipeList.getItemId()); - player.sendPacket(sm); - player.isInCraftMode(false); - return; - } - maker = new ReceipeItemMaker(player, recipeList, null); - if (maker.isValid) - activeMakers.put(player, maker); - } - } - - public synchronized void requestMakeItemAbort(L2PcInstance player) - { - activeMakers.remove(player); - } - - private void parseList(String line) - { - StringTokenizer st = new StringTokenizer(line,";"); - List recipePartList = new FastList(); - - String recipeName = st.nextToken(); - int id = Integer.parseInt(st.nextToken()); - int recipeId = Integer.parseInt(st.nextToken()); - int level = Integer.parseInt(st.nextToken()); - - //material - StringTokenizer st2 = new StringTokenizer(st.nextToken(), "[],"); - while (st2.hasMoreTokens()) - { - StringTokenizer st3 = new StringTokenizer(st2.nextToken(), "()"); - int rpItemId = Integer.parseInt(st3.nextToken()); - int quantity = Integer.parseInt(st3.nextToken()); - L2RecipeInstance rp = new L2RecipeInstance(rpItemId, quantity); - recipePartList.add(rp); - //recipe.addRecipe(rp); - } - - int itemId = Integer.parseInt(st.nextToken()); - int count = Integer.parseInt(st.nextToken()); - - //npc fee - /*String notdoneyet = */ st.nextToken(); - - int mpCost = Integer.parseInt(st.nextToken()); - int successRate = Integer.parseInt(st.nextToken()); - - L2RecipeList recipeList = new L2RecipeList(id,level,recipeId,recipeName,successRate,mpCost,itemId,count); - for (L2RecipeInstance recipePart : recipePartList) - { - recipeList.addRecipe(recipePart); - } - _lists.put(new Integer(_lists.size()), recipeList); - } - - - - - class ReceipeItemMaker implements Runnable - { - int timeReady; - final L2PcInstance player; - final L2PcInstance target; - final L2RecipeList recipeList; - final List items; - int materialsRefPrice; - int totalItems; - int usedItems; - int price; - boolean isValid; - - ReceipeItemMaker(L2PcInstance player, L2RecipeList recipeList, L2PcInstance target ) - { - this.player = player; - this.target = target; - this.recipeList = recipeList; - this.items = new FastList(); - - int skillLevel = player.getSkillLevel(L2Skill.SKILL_CRAFTING); - if (skillLevel <= 0) - { - player.sendPacket(new ActionFailed()); - player.isInCraftMode(false); - return; - } - - if ((recipeList == null) || (recipeList.getRecipes().length == 0)) - { - SystemMessage sm = new SystemMessage(614); - sm.addString("No such recipe"); - player.sendPacket(sm); - player.isInCraftMode(false); - return; - } - - if (target != null) - { - for (L2ManufactureItem temp : player.getCreateList().getList()) - { - if (temp.getRecipeId() == recipeList.getId()) - { - price = temp.getCost(); - if (target.getAdena() < price) - { - target.sendPacket(new SystemMessage(SystemMessage.YOU_NOT_ENOUGH_ADENA)); - player.isInCraftMode(false); - return; - } - break; - } - } - } - if (recipeList.getLevel()>skillLevel) - { - SystemMessage sm = new SystemMessage(614); - sm.addString("Need skill level "+recipeList.getLevel()); - player.sendPacket(sm); - player.isInCraftMode(false); - return; - } - /* - if (recipeList.getAdenaCost()>activeChar.getAdena()) - { - SystemMessage sm = new SystemMessage(614); - sm.addString("Need "+recipeList.getAdenaCost()+" Adena"); - activeChar.sendPacket(sm); - return; - }*/ - - L2RecipeInstance[] recipes = recipeList.getRecipes(); - - Inventory inv = null; - if (target == null) - inv = player.getInventory(); - else - inv = target.getInventory(); - - for (L2RecipeInstance recipe : recipes) - { - if (recipe.getQuantity() != 0) - { - L2ItemInstance invItem = inv.getItemByItemId(recipe.getItemId()); - if ((invItem == null) || (recipe.getQuantity()>invItem.getCount())) - { - SystemMessage sm = new SystemMessage(614); - sm.addString("You dont have the right elements for making this item"); - if (target == null) - player.sendPacket(sm); - else - target.sendPacket(sm); - player.isInCraftMode(false); - return; - } - } - } - - if (!Config.ALT_GAME_CREATION) - { - if (player.getCurrentMp() < recipeList.getMpCost()) - { - if (Config.DEBUG) _log.fine("not enough mana"); - SystemMessage sm = new SystemMessage(SystemMessage.NOT_ENOUGH_MP); - if (target == null) - player.sendPacket(sm); - else - target.sendPacket(sm); - timeReady = GameTimeController.getGameTicks(); - player.isInCraftMode(false); - return; - } - } - - for (L2RecipeInstance recipe : recipes) - { - if (recipe.getQuantity() != 0) - { - L2ItemInstance invItem = inv.getItemByItemId(recipe.getItemId()); - invItem = inv.dropItem(invItem, recipe.getQuantity()); - items.add(invItem); - materialsRefPrice += invItem.getReferencePrice()*invItem.getCount(); - totalItems += invItem.getCount(); - } - } - - isValid = true; - - timeReady = GameTimeController.TICKS_PER_SECOND + GameTimeController.getGameTicks(); - ClientScheduler.getInstance().scheduleLow(this, 1100); - } - - public void run() - { - player.isInCraftMode(true); + if ((recipeList == null) || (recipeList.getRecipes().length == 0)) + { + _log.warning("I bet this can never happen normally, "+ + "cause customer can order only listed recipes, which are 100% in manufacturer's recipe book"); - if ( Config.IS_CRAFTING_ENABLED ) { - double currentPlayerMp = player.getCurrentMp(); - if (currentPlayerMp < recipeList.getMpCost()) { - if (Config.DEBUG) _log.fine("not enough mana"); - SystemMessage sm = new SystemMessage(SystemMessage.NOT_ENOUGH_MP); - if (target == null) - player.sendPacket(sm); - else - target.sendPacket(sm); - timeReady = GameTimeController.getGameTicks(); - player.isInCraftMode(false); - return; - } - - int gameTicks = GameTimeController.getGameTicks(); - if (timeReady > gameTicks) + sm = new SystemMessage(614); + sm.addString("No recipe for: " + recipeListId); + customer.sendPacket(sm); + manufacturer.isInCraftMode(false); + return; + } + + if (Config.ALT_GAME_CREATION) + { + RecipeItemMaker maker = activeMakers.get(manufacturer); + if (maker != null) + { + if(!manufacturer.isInCraftMode()) { - player.isInCraftMode(false); - return; + if(Config.DEBUG) + { + _log.fine(maker.manufacturer.getName() + " is in activeMakers but not IsInCraftmode"); + _log.fine("decision: isincraftmode() is right, activeMakers wrong, removing from activeMakers"); + } + activeMakers.remove(manufacturer); + } else + { + sm = new SystemMessage(614); + sm.addString("Manufacturer is busy."); + sm.addItemName(recipeList.getItemId()); + customer.sendPacket(sm); + manufacturer.isInCraftMode(false); + return; } - - timeReady = gameTicks + (int)(15 * player.getMReuseRate(player.getKnownSkill(172)) * GameTimeController.TICKS_PER_SECOND); - - if (!Config.ALT_GAME_CREATION || items.isEmpty()) { - player.reduceCurrentMp(recipeList.getMpCost()); - - StatusUpdate su = new StatusUpdate(player.getObjectId()); - - L2ItemInstance createdItem = ItemTable.getInstance().createItem(recipeList.getItemId()); - createdItem.setCount(recipeList.getCount()); - - int randCheck = _rnd.nextInt(100); - if(recipeList.getSuccessRate() <= randCheck ) { - SystemMessage sm = new SystemMessage(614); - sm.addString("Item(s) failed to create"); - player.sendPacket(sm); - player.isInCraftMode(false); - } - else { - int createdItemCount = createdItem.getCount(); - SystemMessage sm = new SystemMessage(SystemMessage.EARNED_ITEM); - sm.addItemName(createdItem.getItemId()); - sm.addNumber(createdItemCount); - //sm.addString("Item(s) created"); - if (target == null) - { - player.getInventory().addItem(createdItem); - player.sendPacket(sm); - su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad()); - } else - { - if (price > 0) { - target.reduceAdena(price); - player.addAdena(price); - L2ItemInstance adenaupdate = player.getInventory().findItemByItemId(57); - InventoryUpdate iu = new InventoryUpdate(); - iu.addModifiedItem(adenaupdate); - player.sendPacket(iu); - SystemMessage sm2 = new SystemMessage(SystemMessage.DISSAPEARED_ADENA); - sm2.addNumber(price); - target.sendPacket(sm2); - sm2 = new SystemMessage(SystemMessage.EARNED_ADENA); - sm2.addNumber(price); - player.sendPacket(sm2); - } - target.getInventory().addItem(createdItem); - target.sendPacket(sm); - StatusUpdate su2 = new StatusUpdate(target.getObjectId()); - su2.addAttribute(StatusUpdate.CUR_LOAD, target.getCurrentLoad()); - target.sendPacket(su2); - } - - - if (Config.ALT_GAME_CREATION) { - int skillLevel = player.getSkillLevel(L2Skill.SKILL_CRAFTING); - int receipeLevel = recipeList.getLevel(); - int exp = createdItem.getReferencePrice()*createdItemCount; - // one variation - exp -= materialsRefPrice; - if (exp < 0) exp = 0; - // another variation - // exp /= receipeLevel - for (int i=skillLevel; i > receipeLevel; i--) - exp /= 4; - int sp = exp / 10; - player.addExpAndSp((int)player.calcStat(Stats.EXPSP_RATE, exp * Config.RATE_XP, null, null), - (int)player.calcStat(Stats.EXPSP_RATE, sp * Config.RATE_SP, null, null)); - } - } - activeMakers.remove(player); - player.isInCraftMode(false); - - su.addAttribute(StatusUpdate.CUR_MP, (int) player.getCurrentMp()); - player.sendPacket(su); - if (target == null){ - player.sendPacket(new ItemList(player, false)); - player.sendPacket(new RecipeItemMakeInfo(recipeList.getId(),player)); - } else - { - target.sendPacket(new ItemList(target, false)); - target.sendPacket(new RecipeShopItemInfo(player.getObjectId(),recipeList.getId())); - } - } - else { - double currentMp = player.getCurrentMp(); - if (currentMp < recipeList.getMpCost()) { - if (Config.DEBUG) _log.fine("not enough mana"); - SystemMessage sm = new SystemMessage(SystemMessage.NOT_ENOUGH_MP); - if (target == null) - player.sendPacket(sm); - else - target.sendPacket(sm); - timeReady = GameTimeController.getGameTicks(); - player.isInCraftMode(false); - return; - } - player.setCurrentMp(currentMp - recipeList.getMpCost()); - - int numItems = player.getSkillLevel(172); - while (numItems > 0 && !items.isEmpty()) { - L2ItemInstance item = items.get(0); - - int count = item.getCount(); - if (count >= numItems) count = numItems; - - item.setCount(item.getCount() - count); - if (item.getCount() <= 0) items.remove(0); - - numItems -= count; - usedItems += count; - - SystemMessage sm = new SystemMessage(368); - sm.addNumber(count); - sm.addItemName(item.getItemId()); - if (target == null) - player.sendPacket(sm); - else - target.sendPacket(sm); - - player.isInCraftMode(false); - } - - int delay = (timeReady-gameTicks) * GameTimeController.MILLIS_IN_TICK; - MagicSkillUser msk = new MagicSkillUser(player, 1050, 1, delay, 0); - player.broadcastPacket(msk); - SetupGauge sg = new SetupGauge(0, delay); - player.sendPacket(sg); - - ClientScheduler.getInstance().scheduleLow(this, 100+delay); - } - } - else { - // crafting is disabled... - SystemMessage sm = new SystemMessage(614); - sm.addString("Crafting is currently disabled."); - if (target == null) - player.sendPacket(sm); - else - target.sendPacket(sm); - player.isInCraftMode(false); - } - } - } + } + + maker = new RecipeItemMaker(manufacturer, recipeList, customer); + + if (maker!=null && manufacturer!=null && maker.isValid) + activeMakers.put(manufacturer, maker); + } else // for regular crafting we don't use activeMakers + new RecipeItemMaker(manufacturer, recipeList, customer); + } + public synchronized void requestMakeItem(L2PcInstance manufacturer, int recipeListId) + { + L2RecipeList recipeList = getRecipeList(recipeListId-1); + + SystemMessage sm = new SystemMessage(614); + + if ((recipeList == null) || (recipeList.getRecipes().length == 0)) + { + sm = new SystemMessage(614); + sm.addString("No recipe for: " + recipeListId); + manufacturer.sendPacket(sm); + return; + } + + if(manufacturer.isInCraftMode()) + { + sm = new SystemMessage(614); + sm.addString("You are busy creating "); + sm.addItemName(recipeList.getItemId()); + manufacturer.sendPacket(sm); + return; + } + + if (Config.ALT_GAME_CREATION) + { + RecipeItemMaker maker = activeMakers.get(manufacturer); + if (maker != null) + activeMakers.remove(manufacturer); + + maker = new RecipeItemMaker(manufacturer, recipeList, null); + + if (manufacturer!=null && maker!=null && maker.isValid) + activeMakers.put(manufacturer, maker); + } else + { + new RecipeItemMaker(manufacturer, recipeList, null); + } + } + public synchronized void requestMakeItemAbort(L2PcInstance manufacturer) + { + manufacturer.isInCraftMode(false); + if (Config.DEBUG) _log.fine(manufacturer.getName()+" IsInCraftMode(false)"); + + if(Config.ALT_GAME_CREATION && activeMakers!=null) + { + if(activeMakers.get(manufacturer)!=null) activeMakers.remove(manufacturer); + if (Config.DEBUG) + _log.fine("requestMakeItemAbort called - removing " +manufacturer.getName() +" from activeMakers "); + } + } + + private void parseList(String line) + { + StringTokenizer st = new StringTokenizer(line,";"); + List recipePartList = new FastList(); + + String recipeName = st.nextToken(); + int id = Integer.parseInt(st.nextToken()); + int recipeId = Integer.parseInt(st.nextToken()); + int level = Integer.parseInt(st.nextToken()); + + //material + StringTokenizer st2 = new StringTokenizer(st.nextToken(), "[],"); + while (st2.hasMoreTokens()) + { + StringTokenizer st3 = new StringTokenizer(st2.nextToken(), "()"); + int rpItemId = Integer.parseInt(st3.nextToken()); + int quantity = Integer.parseInt(st3.nextToken()); + L2RecipeInstance rp = new L2RecipeInstance(rpItemId, quantity); + recipePartList.add(rp); + //recipe.addRecipe(rp); + } + + int itemId = Integer.parseInt(st.nextToken()); + int count = Integer.parseInt(st.nextToken()); + + //npc fee + /*String notdoneyet = */ st.nextToken(); + + int mpCost = Integer.parseInt(st.nextToken()); + int successRate = Integer.parseInt(st.nextToken()); + + L2RecipeList recipeList = new L2RecipeList(id,level,recipeId,recipeName,successRate,mpCost,itemId,count); + for (L2RecipeInstance recipePart : recipePartList) + { + recipeList.addRecipe(recipePart); + } + _lists.put(new Integer(_lists.size()), recipeList); + } + + class RecipeItemMaker implements Runnable + { + int timeReady; + final L2PcInstance manufacturer; + final L2PcInstance customer; + final L2RecipeList recipeList; + final List items; + final int skillLevel; + int creationPasses; + int materialsRefPrice; + int totalItems; + int usedItems; + int price; + boolean isValid; + + + RecipeItemMaker(L2PcInstance manufacturer, L2RecipeList recipeList, L2PcInstance customer ) + { + this.manufacturer = manufacturer; + this.customer = customer; + this.recipeList = recipeList; + this.items = new FastList(); + this.skillLevel = manufacturer.getSkillLevel(L2Skill.SKILL_CRAFTING); + + // crafting is disabled... + if (!Config.IS_CRAFTING_ENABLED) + { + SystemMessage sm = new SystemMessage(614); + sm.addString("Crafting is currently disabled."); + if (customer == null) + manufacturer.sendPacket(sm); + else + customer.sendPacket(sm); + manufacturer.isInCraftMode(false); + return; + } + + if (manufacturer.isInCraftMode()) + { + if(Config.DEBUG) _log.fine("manufacturer.isInCraftMode()==true, in RecipeItemMaker constructor"); + SystemMessage sm = new SystemMessage(614); + + if (customer == null) + { + sm.addString("You are busy crafting"); + manufacturer.sendPacket(sm); + } + else + { + sm.addString("Manufacturer is busy crafting"); + customer.sendPacket(sm); + }; + return; + } + + if (skillLevel <= 0) + { + manufacturer.sendPacket(new ActionFailed()); + manufacturer.isInCraftMode(false); + + if(customer!=null) + { + customer.sendPacket(new ActionFailed()); + if(Config.DEBUG) + _log.warning("skillLevel <= 0 and customer!=null, so why can manufacturer open manufacture shop if he has no skill?"); + } + return; + } + + if ((recipeList == null) || (recipeList.getRecipes().length == 0)) + { + SystemMessage sm = new SystemMessage(614); + sm.addString("No such recipe"); + manufacturer.sendPacket(sm); + + if(customer!=null) + { + customer.sendPacket(sm); + if(Config.DEBUG) + _log.warning("customer!=null, so why can manufacturer offer manufacture for item if he has no recipe ?"); + } + + return; + } + + if (customer != null) + { + for (L2ManufactureItem temp : manufacturer.getCreateList().getList()) + if (temp.getRecipeId() == recipeList.getId()) + { + price = temp.getCost(); + if (customer.getAdena() < price) + { + customer.sendPacket(new SystemMessage(SystemMessage.YOU_NOT_ENOUGH_ADENA)); + return; + } + break; + } + } + + if (recipeList.getLevel()>skillLevel) + { + SystemMessage sm = new SystemMessage(614); + sm.addString("Need skill level "+recipeList.getLevel()); + manufacturer.sendPacket(sm); + return; + } + + L2RecipeInstance[] recipes = recipeList.getRecipes(); + + Inventory inv = null; + + if (customer == null) + inv = manufacturer.getInventory(); + else + inv = customer.getInventory(); + + for (L2RecipeInstance recipe : recipes) + { + if (recipe.getQuantity() != 0) + { + L2ItemInstance invItem = inv.getItemByItemId(recipe.getItemId()); + if ((invItem == null) || (recipe.getQuantity()>invItem.getCount())) + { + SystemMessage sm = new SystemMessage(614); + sm.addString("You dont have the right elements for making this item"); + + if (customer == null) manufacturer.sendPacket(sm); + else customer.sendPacket(sm); + + return; + } + } + } + + if (manufacturer.getCurrentMp() < recipeList.getMpCost()) + { + if (Config.DEBUG) _log.fine("not enough mana in RecipeItemMaker constructor"); + SystemMessage sm = new SystemMessage(SystemMessage.NOT_ENOUGH_MP); + if (customer == null) + manufacturer.sendPacket(sm); + else + customer.sendPacket(sm); + + return; + } + + creationPasses=0; + for (L2RecipeInstance recipe : recipes) + { + if (recipe.getQuantity() != 0) + { + L2ItemInstance invItem = inv.getItemByItemId(recipe.getItemId()); + invItem = inv.dropItem(invItem, recipe.getQuantity()); + items.add(invItem); + materialsRefPrice += invItem.getReferencePrice()*invItem.getCount(); + totalItems += invItem.getCount(); + creationPasses+=invItem.getCount()/skillLevel; + if((invItem.getCount()%skillLevel)>0) creationPasses++; + } + } + + if(Config.DEBUG) + { + //_log.warning("calculated creation passes: "+creationPasses); + + if(creationPasses==0) + { + creationPasses++; + _log.warning("creationPasses was ZERO so creationPasses++ and it is now " + creationPasses); + } + } + isValid = true; + + manufacturer.isInCraftMode(true); // here we say craf mode started, no reason to do it sooner, just makes problems + + //ClientScheduler.scheduleCraftAction(this, 100); + run(); // for not-alternative crafting -> no reason why not craft immediately, cause it uses really little cpu + // and will never make lag ... scheduled things tend to make lag, things that are immediately done don't if you + // have sufficient cpu anyway ... how long can craft take ? few nanoseconds ? + // and for ALT_CRAFTING=true, first run is innitial, and takes no time also, and on end, if needed, another run + // is scheduled + + } + public void run() + { + if (!Config.ALT_GAME_CREATION || items.isEmpty()) // this method does the actual creation of item, + { // it is called immediately for normal crafting, + completeCreation(); // cause normal crafting does not take time, bug gives no XP/SP + manufacturer.isInCraftMode(false); // for ALT_CRAFTING it is called only when all items are "equiped" + // thru multiple scheduled runs using + // ClientScheduler.ScheduleCraftAction() - separate thread pool + // there should be no thread launching at all + + if(Config.DEBUG) + { + //_log.warning("MP_Cost: "+recipeList.getMpCost()+" "); + //_log.warning("passes: "+creationPasses+" "); + //_log.warning("mana/pass:"+recipeList.getMpCost()/creationPasses+" "); + //_log.warning("error: "+(recipeList.getMpCost()-((recipeList.getMpCost()/creationPasses)*creationPasses))); + } + + return; + } + + + // all this code is for ALT_GAME_CREATION only + // previous code was very confusing, which led + // to "craft lag" due to misunderstanding of + // "crafting" in normal mode. + // normal mode takes no time but gives no XP/SP + // ALT_MODE takes time but gives XP/SP as reward + // --------------------------------------------- + // run() is scheduled multiple times, + // (equiping) skillLevel items on every run, until + // all items are "equiped", and then on next run, + // completeCreation() will produce the result + // and remove equiped materials from inventory + // + // on every run() part of mana is deducted from + // manufacturer, amount is calculated as sum of + // all item counts from recipe. + + double currentManufacturerMp = manufacturer.getCurrentMp(); // we need player to have only mana needed + if (currentManufacturerMp < ((double)recipeList.getMpCost()/(double)creationPasses)) + { // for this pass, next pass is in 1 second + if (Config.DEBUG) _log.warning("not enough mana in run()"); // so we can allow mp regen to help manufacturer + SystemMessage sm = new SystemMessage(SystemMessage.NOT_ENOUGH_MP); + if (customer == null) + manufacturer.sendPacket(sm); + else + customer.sendPacket(sm); + + manufacturer.isInCraftMode(false); + activeMakers.remove(manufacturer); + return; + } + + + manufacturer.reduceCurrentMp((double)recipeList.getMpCost()/(double)creationPasses); + + int numItems = skillLevel; + + while (numItems > 0 && !items.isEmpty()) // equip # of items we can in one run() + { // if players complain they lose items during craft on server crashes, try + L2ItemInstance item = items.get(0); // not to item.remove(), but instead copy it somehow and return if crafting + int count = item.getCount(); // did not finish for some reason ?? umh don't know how it works really + // when is sql db updated ? all the time ? sometimes ? + + if (count >= numItems) count = numItems; + item.setCount(item.getCount() - count); + if (item.getCount() <= 0) items.remove(0); + numItems -= count; + usedItems += count; + + SystemMessage sm = new SystemMessage(368); + sm.addNumber(count); + sm.addItemName(item.getItemId()); + + if (customer == null) manufacturer.sendPacket(sm); + else customer.sendPacket(sm); + } + + int delay = ((int)(manufacturer.getMReuseRate(manufacturer.getKnownSkill(L2Skill.SKILL_CRAFTING)) * GameTimeController.TICKS_PER_SECOND)) * GameTimeController.MILLIS_IN_TICK; + + MagicSkillUser msk = new MagicSkillUser(manufacturer, 1050, 1, delay, 0); + manufacturer.broadcastPacket(msk); + + SetupGauge sg = new SetupGauge(0, delay); + manufacturer.sendPacket(sg); + + StatusUpdate su = new StatusUpdate(manufacturer.getObjectId()); + su.addAttribute(StatusUpdate.CUR_MP, (int) manufacturer.getCurrentMp()); + manufacturer.sendPacket(su); +// // this works but it makes craft of level1 items very fast for alt mode ... uhm +// // I'd allow that, cause crafting "braided hemp" is not very fun and you need to do it +// // in huge quantities, even if you are high level, so you get no XP/SP +// // but it's not my call +// if (items.isEmpty()) +// { +// if(Config.DEBUG) _log.fine("saved "+delay+" miliseconds"); +// completeCreation(); +// manufacturer.isInCraftMode(false); +// activeMakers.remove(manufacturer); +// } else + ClientScheduler.scheduleCraftAction(this, 1+delay); // Craft thread pool has nothing to do with other pools, so + // only way this can make any kind of lag is when CPU usage is 100% + // when nobody is "in craft mode" scheduled tasks for + // craft thread pool must be 0 or we have a bug again :/ + } + + private void completeCreation() // this is where real item production is done + { + int createdItemCount=0; + if(Config.DEBUG) + _log.fine(manufacturer.getName()+" : completeCreation() "); + + if(!Config.ALT_GAME_CREATION) // we reduce Mp in run() for ALT_GAME_CREATION + manufacturer.reduceCurrentMp(recipeList.getMpCost()); + + StatusUpdate su = new StatusUpdate(manufacturer.getObjectId()); + + L2ItemInstance createdItem = ItemTable.getInstance().createItem(recipeList.getItemId()); + createdItem.setCount(recipeList.getCount()); + + int randCheck = _rnd.nextInt(100); + + if(recipeList.getSuccessRate() <= randCheck ) + { + SystemMessage sm = new SystemMessage(614); + sm.addString("Item(s) failed to create"); + manufacturer.sendPacket(sm); + manufacturer.isInCraftMode(false); + if(Config.ALT_GAME_CREATION && activeMakers.get(manufacturer)!=null) activeMakers.remove(manufacturer); + } else + { // item succesfully created + createdItemCount = createdItem.getCount(); + SystemMessage sm = new SystemMessage(SystemMessage.EARNED_ITEM); + sm.addItemName(createdItem.getItemId()); + sm.addNumber(createdItemCount); + + if (customer == null) + { + manufacturer.getInventory().addItem(createdItem); + manufacturer.sendPacket(sm); + su.addAttribute(StatusUpdate.CUR_LOAD, manufacturer.getCurrentLoad()); + } else + { + if (price > 0) + { + customer.reduceAdena(price); + manufacturer.addAdena(price); + L2ItemInstance adenaupdate = manufacturer.getInventory().findItemByItemId(57); + InventoryUpdate iu = new InventoryUpdate(); + iu.addModifiedItem(adenaupdate); + manufacturer.sendPacket(iu); + SystemMessage sm2 = new SystemMessage(SystemMessage.DISSAPEARED_ADENA); + sm2.addNumber(price); + customer.sendPacket(sm2); + sm2 = new SystemMessage(SystemMessage.EARNED_ADENA); + sm2.addNumber(price); + manufacturer.sendPacket(sm2); + } + + customer.getInventory().addItem(createdItem); + customer.sendPacket(sm); + StatusUpdate su2 = new StatusUpdate(customer.getObjectId()); + su2.addAttribute(StatusUpdate.CUR_LOAD, customer.getCurrentLoad()); + customer.sendPacket(su2); + } + } + + if (Config.ALT_GAME_CREATION) + { + int RecipeLevel = recipeList.getLevel(); + int exp; + int sp; + + // if sitting, default formula, standing my new formula based on MP used to craft item(s) + if(!Config.ALT_GAME_CREATION_BY_MANA) // standard formula, tried to fix but no luck + { + exp = createdItem.getReferencePrice()*createdItemCount; + // ensure at least some profit + materialsRefPrice=(int)((double)materialsRefPrice*(double)0.95); + + // one variation + if(Config.DEBUG) + { + _log.fine("BASED ON ITEM PRICE - MATERIALS PRICE"); + _log.fine("createdItemCount: "+createdItemCount); + _log.fine("exp: "+exp); + _log.fine("referent price: "+createdItem.getReferencePrice()); + _log.fine("referent total: "+createdItem.getReferencePrice()*createdItemCount); + _log.fine("materials price: "+materialsRefPrice); + _log.fine("exp: "+(exp-materialsRefPrice)); + } + + exp -= materialsRefPrice; + + if (exp < 0) exp = 0; + + exp/=RecipeLevel; + + for (int i=skillLevel; i > RecipeLevel; i--) exp /= 4; + + sp = exp / 10; + + if(Config.DEBUG) _log.fine("exp with mods: "+exp); + + } else + { + exp=2*(recipeList.getLevel() * recipeList.getMpCost()) + /skillLevel; + + sp = exp / 10; + + // one variation + if(Config.DEBUG) + { + _log.fine("NEW METHOD - BASED ON MANA"); + _log.fine("createdItemCount: "+createdItemCount); + _log.fine("exp: "+exp); + } + + } + manufacturer.addExpAndSp((int)manufacturer.calcStat(Stats.EXPSP_RATE, exp * Config.RATE_XP, null, null), + (int)manufacturer.calcStat(Stats.EXPSP_RATE, sp * Config.RATE_SP, null, null)); + + if(activeMakers.get(manufacturer)!=null) activeMakers.remove(manufacturer); + } + + manufacturer.isInCraftMode(false); + + su.addAttribute(StatusUpdate.CUR_MP, (int) manufacturer.getCurrentMp()); + manufacturer.sendPacket(su); + if (customer == null){ + manufacturer.sendPacket(new ItemList(manufacturer, false)); + manufacturer.sendPacket(new RecipeItemMakeInfo(recipeList.getId(),manufacturer)); + } else + { + customer.sendPacket(new ItemList(customer, false)); + customer.sendPacket(new RecipeShopItemInfo(manufacturer.getObjectId(),recipeList.getId())); + } + } + } } Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ClientScheduler.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ClientScheduler.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/ClientScheduler.java (working copy) @@ -31,16 +31,6 @@ import net.sf.l2j.Config; import net.sf.l2j.gameserver.clientpackets.ClientBasePacket; -/** - * This class permit to create 3 Threads pools and to add to it tasks to execute in function of their priority (HIGH, MEDIUM,LOW).

- * - * Threads pools :

- *
  • A pool containing 4 Hight Threads
  • - *
  • A pool containing 10 Medium Threads
  • - *
  • A pool containing 4 Low priority Threads


  • - * - */ - public final class ClientScheduler { static Logger _log = Logger.getLogger(ClientScheduler.class.getName()); @@ -53,8 +43,11 @@ private static final ClientScheduler _instance = new ClientScheduler(); private final ScheduledThreadPoolExecutor _executorHighPriority; + private final ScheduledThreadPoolExecutor _executorMedHighPriority; private final ScheduledThreadPoolExecutor _executorMedPriority; private final ScheduledThreadPoolExecutor _executorLowPriority; + private final ScheduledThreadPoolExecutor _executorAi; + private final ScheduledThreadPoolExecutor _executorCraft; /** @@ -67,15 +60,18 @@ /** - * Create a pool of 4 Hight Threads, a pool of 10 Medium Threads, and a pool of 4 Low priority Threads to execute Task.

    + * Create a pool of 4 Hight Threads, a pool of 4 Medium Threads, and a pool of 4 Low priority Threads to execute Task.

    */ private ClientScheduler() { if (Config.ASSERT) assert _instance == null; _executorHighPriority = new ScheduledThreadPoolExecutor(Config.THREAD_P_HIGH, new ThrFactory(Config.EXECUTOR_PRI_HIGH, "PoolHIGH")); - _executorMedPriority = new ScheduledThreadPoolExecutor(Config.THREAD_P_MED, new ThrFactory(Config.EXECUTOR_PRI_MED, "PoolMED")); + _executorMedHighPriority = new ScheduledThreadPoolExecutor(Config.THREAD_P_HIGH, new ThrFactory(Config.EXECUTOR_PRI_HIGH-1, "PoolHIGH")); + _executorMedPriority = new ScheduledThreadPoolExecutor(Config.THREAD_P_MED, new ThrFactory(Config.EXECUTOR_PRI_MED, "PoolMED")); _executorLowPriority = new ScheduledThreadPoolExecutor(Config.THREAD_P_LOW, new ThrFactory(Config.EXECUTOR_PRI_LOW, "PoolLOW")); + _executorAi = new ScheduledThreadPoolExecutor(Config.THREAD_P_MED, new ThrFactory((Config.EXECUTOR_PRI_HIGH-1), "PoolMED")); + _executorCraft = new ScheduledThreadPoolExecutor(Config.THREAD_P_MED, new ThrFactory((Config.EXECUTOR_PRI_MED-1), "PoolLOW")); } /** @@ -83,17 +79,26 @@ */ public void closeAll() { - try { _executorHighPriority.shutdown(); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } + try { _executorHighPriority.shutdown(); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } + try { _executorMedHighPriority.shutdown(); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } try { _executorMedPriority.shutdown(); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } try { _executorLowPriority.shutdown(); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } + try { _executorAi.shutdown(); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } + try { _executorCraft.shutdown(); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } - try { _executorHighPriority.awaitTermination(1000, TimeUnit.MILLISECONDS); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } + try { _executorHighPriority.awaitTermination(1000, TimeUnit.MILLISECONDS); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } + try { _executorMedHighPriority.awaitTermination(1000, TimeUnit.MILLISECONDS); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } try { _executorMedPriority.awaitTermination(1000, TimeUnit.MILLISECONDS); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } try { _executorLowPriority.awaitTermination(1000, TimeUnit.MILLISECONDS); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } + try { _executorAi.awaitTermination(1000, TimeUnit.MILLISECONDS); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } + try { _executorCraft.awaitTermination(1000, TimeUnit.MILLISECONDS); } catch (Throwable t) { _log.log(Level.WARNING, "", t); } _executorHighPriority.shutdownNow(); - _executorHighPriority.shutdownNow(); - _executorHighPriority.shutdownNow(); + _executorMedHighPriority.shutdownNow(); + _executorMedPriority.shutdownNow(); + _executorLowPriority.shutdownNow(); + _executorAi.shutdownNow(); + _executorCraft.shutdownNow(); } @@ -105,7 +110,10 @@ TaskPriority pr = pkt.getPriority(); if (pr == null) - pr = PR_LOW; + { + _log.warning("Packet without priority defaulted to PR_LOW: "+pkt.getType()); + pr = PR_LOW; + } // Add a task to one of the pool of thread in function of its priority (HIGH, MEDIUM,LOW) // This has effect equivalent to schedule(command, 0, anyUnit) @@ -121,9 +129,9 @@ _instance._executorMedPriority.execute(pkt); return; case PR_LOW: - default: - _instance._executorLowPriority.execute(pkt); - return; + default: + _instance._executorLowPriority.execute(pkt); + return; } } @@ -146,8 +154,9 @@ { case PR_HIGH: return scheduleHighAtFixedRate(r, initial, delay); case PR_MEDIUM: return scheduleMedAtFixedRate(r, initial, delay); - default: - case PR_LOW: return scheduleLowAtFixedRate(r, initial, delay); + case PR_LOW: return scheduleLowAtFixedRate(r, initial, delay); + default: + return scheduleLowAtFixedRate(r, initial, delay); } } @@ -169,7 +178,42 @@ } catch (RejectedExecutionException e) { return null; /* shutdown, ignore */ } } - + /** + * Create a MedHigh priority task that is executed after an initial time (in ms) and each delay ms.

    + * + * @param r The task to launch + * @param initial The initial delay (in ms) after what the task is executed for the first time + * @param delay The delay (in ms) between 2 consecutive executions of the task + * + */ + public ScheduledFuture scheduleMedHighAtFixedRate(Runnable r, long initial, long delay) + { + try + { + if (delay < 0) delay = 0; + return _executorMedHighPriority.scheduleAtFixedRate(r, initial, delay, TimeUnit.MILLISECONDS); + } catch (RejectedExecutionException e) { return null; /* shutdown, ignore */ } + } + + public ScheduledFuture scheduleAiAtFixedRate(Runnable r, long initial, long delay) + { + try + { + if (delay < 0) delay = 0; + return _executorAi.scheduleAtFixedRate(r, initial, delay, TimeUnit.MILLISECONDS); + } catch (RejectedExecutionException e) { return null; /* shutdown, ignore */ } + } + + public ScheduledFuture scheduleCraftAtFixedRate(Runnable r, long initial, long delay) + { + try + { + if (delay < 0) delay = 0; + return _executorCraft.scheduleAtFixedRate(r, initial, delay, TimeUnit.MILLISECONDS); + } catch (RejectedExecutionException e) { return null; /* shutdown, ignore */ } + } + + /** * Create a Medium priority task that is executed after an initial time (in ms) and each delay ms.

    * @@ -231,8 +275,9 @@ { case PR_HIGH: return scheduleHigh(r, delay); case PR_MEDIUM: return scheduleMed(r, delay); + case PR_LOW: return scheduleLow(r, delay); default: - case PR_LOW: return scheduleLow(r, delay); + return scheduleLow(r,delay); } } @@ -254,7 +299,22 @@ } catch (RejectedExecutionException e) { return null; /* shutdown, ignore */ } } - + /** + * Create a Medium priority task that is executed after an initial time (in ms).

    + * + * @param r The task to launch + * @param initial The initial delay (in ms) after what the task is executed for the first time + * @param delay The delay (in ms) between 2 consecutive executions of the task + * + */ + public ScheduledFuture scheduleMedHigh(Runnable r, long delay) + { + try + { + if (delay < 0) delay = 0; + return _executorMedHighPriority.schedule(r, delay, TimeUnit.MILLISECONDS); + } catch (RejectedExecutionException e) { return null; /* shutdown, ignore */ } + } /** * Create a Medium priority task that is executed after an initial time (in ms).

    * @@ -263,6 +323,7 @@ * @param delay The delay (in ms) between 2 consecutive executions of the task * */ + public ScheduledFuture scheduleMed(Runnable r, long delay) { try @@ -289,7 +350,24 @@ } catch (RejectedExecutionException e) { return null; /* shutdown, ignore */ } } - + public ScheduledFuture scheduleAi(Runnable r, long delay) + { + try + { + if (delay < 0) delay = 0; + return _executorAi.schedule(r, delay, TimeUnit.MILLISECONDS); + } catch (RejectedExecutionException e) { return null; /* shutdown, ignore */ } + } + + public ScheduledFuture scheduleCraft(Runnable r, long delay) + { + try + { + if (delay < 0) delay = 0; + return _executorCraft.schedule(r, delay, TimeUnit.MILLISECONDS); + } catch (RejectedExecutionException e) { return null; /* shutdown, ignore */ } + } + class ThrFactory implements ThreadFactory { private final String _prefix; @@ -316,30 +394,49 @@ { return new String[] { "HIGH ("+Config.EXECUTOR_PRI_HIGH+")", - "ActiveThreads: "+_executorHighPriority.getActiveCount(), - "CompletedTasks: "+_executorHighPriority.getCompletedTaskCount(), - "getCorePoolSize: "+_executorHighPriority.getCorePoolSize(), - "MaximumPoolSize: "+_executorHighPriority.getMaximumPoolSize(), - "LargestPoolSize: "+_executorHighPriority.getLargestPoolSize(), - "PoolSize: "+_executorHighPriority.getPoolSize(), - "ScheduledTasks: "+(_executorHighPriority.getTaskCount() - _executorHighPriority.getCompletedTaskCount()), - "MEDIUM ("+Config.EXECUTOR_PRI_MED+")", - "ActiveThreads: "+_executorMedPriority.getActiveCount(), - "CompletedTasks: "+_executorMedPriority.getCompletedTaskCount(), - "getCorePoolSize: "+_executorMedPriority.getCorePoolSize(), - "MaximumPoolSize: "+_executorMedPriority.getMaximumPoolSize(), - "LargestPoolSize: "+_executorMedPriority.getLargestPoolSize(), - "PoolSize: "+_executorMedPriority.getPoolSize(), - "ScheduledTasks: "+(_executorMedPriority.getTaskCount() - _executorMedPriority.getCompletedTaskCount()), + "ActiveThreads: "+_executorHighPriority.getActiveCount(), + "CompletedTasks: "+_executorHighPriority.getCompletedTaskCount(), + "ScheduledTasks: "+(_executorHighPriority.getTaskCount() - _executorHighPriority.getCompletedTaskCount()), + "TaskCount(total): "+_executorHighPriority.getTaskCount(), + "PoolSize: "+_executorHighPriority.getPoolSize(), + "", + "MedHigh ("+Config.EXECUTOR_PRI_MEDHIGH+")", + "ActiveThreads: "+_executorMedHighPriority.getActiveCount(), + "CompletedTasks: "+_executorMedHighPriority.getCompletedTaskCount(), + "ScheduledTasks: "+(_executorMedHighPriority.getTaskCount() - _executorMedHighPriority.getCompletedTaskCount()), + "TaskCount(total): "+_executorMedHighPriority.getTaskCount(), + "PoolSize: "+_executorMedHighPriority.getPoolSize(), + "", + "MEDIUM ("+(Config.EXECUTOR_PRI_MED)+")", + "ActiveThreads: "+_executorMedPriority.getActiveCount(), + "CompletedTasks: "+_executorMedPriority.getCompletedTaskCount(), + "ScheduledTasks: "+(_executorMedPriority.getTaskCount() - _executorMedPriority.getCompletedTaskCount()), + "TaskCount(total): "+_executorMedPriority.getTaskCount(), + "PoolSize: "+_executorMedPriority.getPoolSize(), + "", "LOW ("+Config.EXECUTOR_PRI_LOW+")", - "ActiveThreads: "+_executorLowPriority.getActiveCount(), - "CompletedTasks: "+_executorLowPriority.getCompletedTaskCount(), - "getCorePoolSize: "+_executorLowPriority.getCorePoolSize(), - "MaximumPoolSize: "+_executorLowPriority.getMaximumPoolSize(), - "LargestPoolSize: "+_executorLowPriority.getLargestPoolSize(), - "PoolSize: "+_executorLowPriority.getPoolSize(), - "ScheduledTasks: "+(_executorLowPriority.getTaskCount() - _executorLowPriority.getCompletedTaskCount()) + "ActiveThreads: "+_executorLowPriority.getActiveCount(), + "CompletedTasks: "+_executorLowPriority.getCompletedTaskCount(), + "ScheduledTasks: "+(_executorLowPriority.getTaskCount() - _executorLowPriority.getCompletedTaskCount()), + "TaskCount(total): "+_executorLowPriority.getTaskCount(), + "PoolSize: "+_executorLowPriority.getPoolSize(), + "", + "AI ("+Config.EXECUTOR_PRI_AI+")", + "ActiveThreads: "+_executorAi.getActiveCount(), + "CompletedTasks: "+_executorAi.getCompletedTaskCount(), + "ScheduledTasks: "+(_executorAi.getTaskCount() - _executorAi.getCompletedTaskCount()), + "TaskCount(total): "+_executorAi.getTaskCount(), + "PoolSize: "+_executorAi.getPoolSize(), + "", + "CRAFT ("+Config.EXECUTOR_PRI_CRAFT+")", + "ActiveThreads: "+_executorCraft.getActiveCount(), + "CompletedTasks: "+_executorCraft.getCompletedTaskCount(), + "ScheduledTasks: "+(_executorCraft.getTaskCount() - _executorCraft.getCompletedTaskCount()), + "TaskCount(total): "+_executorCraft.getTaskCount(), + "PoolSize: "+_executorCraft.getPoolSize(), + "" }; + } @@ -348,4 +445,14 @@ return getInstance().scheduleLow(event, delay); } + public static ScheduledFuture scheduleAiAction(Runnable event, long delay) + { + return getInstance().scheduleAi(event, delay); + } + + public static ScheduledFuture scheduleCraftAction(Runnable event, long delay) + { + return getInstance().scheduleCraft(event, delay); + } + } Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/taskmanager/tasks/TaskCleanUp.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/taskmanager/tasks/TaskCleanUp.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/taskmanager/tasks/TaskCleanUp.java (working copy) @@ -1,35 +0,0 @@ -/** - * - */ -package net.sf.l2j.gameserver.taskmanager.tasks; - -import net.sf.l2j.gameserver.taskmanager.Task; -import net.sf.l2j.gameserver.taskmanager.TaskManager; -import net.sf.l2j.gameserver.taskmanager.TaskTypes; -import net.sf.l2j.gameserver.taskmanager.TaskManager.ExecutedTask; - -/** - * @author Tempy - * - */ -public final class TaskCleanUp extends Task -{ - public static String NAME = "CleanUp"; - - public String getName() - { - return NAME; - } - - public void onTimeElapsed(ExecutedTask task) - { - System.runFinalization(); - System.gc(); - } - - public void initializate() - { - super.initializate(); - TaskManager.addUniqueTask(NAME, TaskTypes.TYPE_FIXED_SHEDULED, "0", "1800000", ""); - } -} Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/taskmanager/TaskManager.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/taskmanager/TaskManager.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/taskmanager/TaskManager.java (working copy) @@ -24,12 +24,12 @@ import javolution.util.FastMap; import net.sf.l2j.L2DatabaseFactory; import net.sf.l2j.gameserver.ClientScheduler; -import net.sf.l2j.gameserver.taskmanager.tasks.TaskCleanUp; import net.sf.l2j.gameserver.taskmanager.tasks.TaskJython; import net.sf.l2j.gameserver.taskmanager.tasks.TaskRecom; import net.sf.l2j.gameserver.taskmanager.tasks.TaskRestart; import net.sf.l2j.gameserver.taskmanager.tasks.TaskSevenSignsUpdate; import net.sf.l2j.gameserver.taskmanager.tasks.TaskShutdown; +import net.sf.l2j.gameserver.taskmanager.tasks.TaskSevenSignsStatus; /** * @author Layane @@ -163,12 +163,12 @@ private void initializate() { - registerTask(new TaskCleanUp()); registerTask(new TaskJython()); registerTask(new TaskRecom()); registerTask(new TaskRestart()); registerTask(new TaskSevenSignsUpdate()); registerTask(new TaskShutdown()); + registerTask(new TaskSevenSignsStatus()); } public void registerTask(Task task) Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/script/faenor/FaenorInterface.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/script/faenor/FaenorInterface.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/script/faenor/FaenorInterface.java (working copy) @@ -33,6 +33,7 @@ import net.sf.l2j.gameserver.script.EngineInterface; import net.sf.l2j.gameserver.script.Expression; import net.sf.l2j.gameserver.templates.L2NpcTemplate; +import net.sf.l2j.gameserver.NpcTable; import org.apache.bsf.BSFException; import org.apache.bsf.BSFManager; @@ -77,7 +78,7 @@ */ public void addQuestDrop(int npcID, int itemID, int min, int max, int chance, String questID, String[] states) { - L2NpcTemplate npc = _npcTable.getTemplate(npcID); + L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcID); if (npc == null) { throw new NullPointerException(); @@ -100,7 +101,7 @@ */ public void addDrop(int npcID, int itemID, int min, int max, boolean sweep, int chance) throws NullPointerException { - L2NpcTemplate npc = _npcTable.getTemplate(npcID); + L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcID); if (npc == null) { if (Config.DEBUG) System.out.print("Npc doesnt Exist"); @@ -120,7 +121,7 @@ */ public List getQuestDrops(int npcID) { - L2NpcTemplate npc = _npcTable.getTemplate(npcID); + L2NpcTemplate npc = NpcTable.getInstance().getTemplate(npcID); if (npc == null) { return null; Index: C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/GameTimeController.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/GameTimeController.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/gameserver/GameTimeController.java (working copy) @@ -72,7 +72,7 @@ _timer = new TimerThread(); _timer.start(); - ClientScheduler.getInstance().scheduleLowAtFixedRate( + ClientScheduler.getInstance().scheduleMedHighAtFixedRate( new TimerWatcher(), 0, 1000); ClientScheduler.getInstance().scheduleLowAtFixedRate( new BroadcastSunState(), 0, 60*60*1000 @@ -151,7 +151,7 @@ // Create a task to update the _knownObject and _knowPlayers of each L2Character that finished its movement and of their already known L2Object // then notify AI with EVT_ARRIVED if (ended != null) - ClientScheduler.getInstance().scheduleLow(new MovingObjectArrived(ended), 10); + ClientScheduler.getInstance().scheduleMed(new MovingObjectArrived(ended), 10); } @@ -169,7 +169,7 @@ { super("TimerThread"); setDaemon(true); - setPriority(MAX_PRIORITY); + setPriority(MAX_PRIORITY-1); _stop = false; _error = null; } Index: C:/workspace/L2_GameServer/java/net/sf/l2j/L2DatabaseFactory.java =================================================================== --- C:/workspace/L2_GameServer/java/net/sf/l2j/L2DatabaseFactory.java (revision 2218) +++ C:/workspace/L2_GameServer/java/net/sf/l2j/L2DatabaseFactory.java (working copy) @@ -63,9 +63,9 @@ config.setMinPoolSize(1); config.setMaxPoolSize(Config.DATABASE_MAX_CONNECTIONS); config.setMaxStatements(100); - config.setIdleConnectionTestPeriod(0); // test idle connection every 1 minute - config.setMaxIdleTime(0); // remove unused connection after 10 minutes - + config.setIdleConnectionTestPeriod(60); // test idle connection every 1 minute + config.setMaxIdleTime(600); // remove unused connection after 10 minutes + config.setNumHelperThreads(5); Class.forName(Config.DATABASE_DRIVER).newInstance(); if (Config.DEBUG) _log.fine("Database Connection Working"); Index: C:/workspace/L2_GameServer/dist/LoginServer_loop.sh =================================================================== --- C:/workspace/L2_GameServer/dist/LoginServer_loop.sh (revision 2218) +++ C:/workspace/L2_GameServer/dist/LoginServer_loop.sh (working copy) @@ -5,7 +5,7 @@ do mv log/java0.log.0 "log/`date +%Y-%m-%d_%H-%M-%S`_java.log" mv log/stdout.log "log/`date +%Y-%m-%d_%H-%M-%S`_stdout.log" - nice -n -2 java -Xms512m -Xmx512m -cp javolution.jar:c3p0-0.9.0.jar:mysql-connector-java-3.1.10-bin.jar:sqljdbc.jar:l2jserver.jar net.sf.l2j.loginserver.LoginServer > log/stdout.log 2>&1 + nice -n -2 java -Xss96k -Xincgc -Xms64m -Xmx128m -cp javolution.jar:c3p0-0.9.0.jar:mysql-connector-java-3.1.10-bin.jar:sqljdbc.jar:l2jserver.jar net.sf.l2j.loginserver.LoginServer > log/stdout.log 2>&1 err=$? # /etc/init.d/mysql restart sleep 10; Index: C:/workspace/L2_GameServer/dist/GameServer_loop.sh =================================================================== --- C:/workspace/L2_GameServer/dist/GameServer_loop.sh (revision 2218) +++ C:/workspace/L2_GameServer/dist/GameServer_loop.sh (working copy) @@ -5,7 +5,7 @@ do mv log/java0.log.0 "log/`date +%Y-%m-%d_%H-%M-%S`_java.log" mv log/stdout.log "log/`date +%Y-%m-%d_%H-%M-%S`_stdout.log" - nice -n -2 java -Xms512m -Xmx512m -cp bsf.jar:javolution.jar:bsh-2.0.jar:jython.jar:c3p0-0.9.0.jar:mysql-connector-java-3.1.10-bin.jar:sqljdbc.jar:l2jserver.jar net.sf.l2j.gameserver.GameServer > log/stdout.log 2>&1 + nice -n -2 java -Xincgc -Xss128k -Xms128m -Xmx768m -cp bsf.jar:javolution.jar:bsh-2.0.jar:jython.jar:c3p0-0.9.0.jar:mysql-connector-java-3.1.10-bin.jar:sqljdbc.jar:l2jserver.jar net.sf.l2j.gameserver.GameServer > log/stdout.log 2>&1 err=$? # /etc/init.d/mysql restart sleep 10;