Bladeren bron

BETA: Updating unloading method of Quest class
* Now it will unload all quest events from L2NpcTemplate
* Reworked many FastList/FastMap to ArrayList/HashMap where synchronization isn't required.
* Reworked L2NpcTemplate

Rumen Nikiforov 13 jaren geleden
bovenliggende
commit
203dd4e430

+ 15 - 12
L2J_Server_BETA/java/com/l2jserver/gameserver/ai/L2AttackableAI.java

@@ -18,11 +18,11 @@ import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
 import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
 import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 import java.util.concurrent.Future;
 
-import javolution.util.FastList;
-
 import com.l2jserver.Config;
 import com.l2jserver.gameserver.GameTimeController;
 import com.l2jserver.gameserver.GeoData;
@@ -50,6 +50,7 @@ import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
 import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate.AIType;
 import com.l2jserver.gameserver.model.effects.L2EffectType;
 import com.l2jserver.gameserver.model.quest.Quest;
+import com.l2jserver.gameserver.model.quest.Quest.QuestEventType;
 import com.l2jserver.gameserver.model.skills.L2Skill;
 import com.l2jserver.gameserver.model.skills.L2SkillType;
 import com.l2jserver.gameserver.model.skills.targets.L2TargetType;
@@ -84,8 +85,8 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
 	private int timepass = 0;
 	private int chaostime = 0;
 	private final L2NpcTemplate _skillrender;
-	private FastList<L2Skill> shortRangeSkills = new FastList<>();
-	private FastList<L2Skill> longRangeSkills = new FastList<>();
+	private List<L2Skill> shortRangeSkills = new ArrayList<>();
+	private List<L2Skill> longRangeSkills = new ArrayList<>();
 	int lastBuffTick;
 	
 	/**
@@ -708,15 +709,17 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
 									&& called.getInstanceId() == npc.getInstanceId())
 //									&& GeoData.getInstance().canSeeTarget(called, npc))
 							{
-								if (originalAttackTarget instanceof L2Playable)
+								if (originalAttackTarget.isPlayable())
 								{
-									Quest[] quests = called.getTemplate().getEventQuests(Quest.QuestEventType.ON_FACTION_CALL);
-									if (quests != null)
+									List<Quest> quests = called.getTemplate().getEventQuests(QuestEventType.ON_FACTION_CALL);
+									if (quests != null && !quests.isEmpty())
 									{
 										L2PcInstance player = originalAttackTarget.getActingPlayer();
-										boolean isSummon = originalAttackTarget instanceof L2Summon;
+										boolean isSummon = originalAttackTarget.isSummon();
 										for (Quest quest : quests)
+										{
 											quest.notifyFactionCall(called, getActiveChar(), player, isSummon);
+										}
 									}
 								}
 								else if (called instanceof L2Attackable && getAttackTarget() != null && called.getAI()._intention != CtrlIntention.AI_INTENTION_ATTACK)
@@ -1078,7 +1081,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
 			// Long/Short Range skill usage.
 			if (npc.hasLSkill() || npc.hasSSkill())
 			{
-				final FastList<L2Skill> shortRangeSkills = shortRangeSkillRender();
+				final List<L2Skill> shortRangeSkills = shortRangeSkillRender();
 				if (!shortRangeSkills.isEmpty() && npc.hasSSkill() && (dist2 <= 150) && Rnd.get(100) <= npc.getSSkillChance())
 				{
 					final L2Skill shortRangeSkill = shortRangeSkills.get(Rnd.get(shortRangeSkills.size()));
@@ -1095,7 +1098,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
 					}
 				}
 				
-				final FastList<L2Skill> longRangeSkills = longRangeSkillRender();
+				final List<L2Skill> longRangeSkills = longRangeSkillRender();
 				if (!longRangeSkills.isEmpty() && npc.hasLSkill() && (dist2 > 150) && Rnd.get(100) <= npc.getLSkillChance())
 				{
 					final L2Skill longRangeSkill = longRangeSkills.get(Rnd.get(longRangeSkills.size()));
@@ -2344,7 +2347,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
 		}
 	}
 	
-	private FastList<L2Skill> longRangeSkillRender()
+	private List<L2Skill> longRangeSkillRender()
 	{
 		longRangeSkills = _skillrender.getLongRangeSkills();
 		if (longRangeSkills.isEmpty())
@@ -2354,7 +2357,7 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
 		return longRangeSkills;
 	}
 	
-	private FastList<L2Skill> shortRangeSkillRender()
+	private List<L2Skill> shortRangeSkillRender()
 	{
 		shortRangeSkills = _skillrender.getShortRangeSkills();
 		if (shortRangeSkills.isEmpty())

+ 6 - 5
L2J_Server_BETA/java/com/l2jserver/gameserver/datatables/NpcTable.java

@@ -20,6 +20,8 @@ import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -27,7 +29,6 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import javolution.util.FastList;
-import javolution.util.FastMap;
 
 import com.l2jserver.Config;
 import com.l2jserver.L2DatabaseFactory;
@@ -149,11 +150,11 @@ public class NpcTable
 			// save a copy of the old data
 			L2NpcTemplate old = getTemplate(id);
 			
+			Map<QuestEventType, List<Quest>> quests = new HashMap<>();
 			TIntObjectHashMap<L2Skill> skills = new TIntObjectHashMap<>();
-			List<L2MinionData> minions = new FastList<>();
-			Map<QuestEventType, Quest[]> quests = new FastMap<>();
-			List<ClassId> classIds = new FastList<>();
-			FastList<L2DropCategory> categories = new FastList<>();
+			List<L2MinionData> minions = new ArrayList<>();
+			List<ClassId> classIds = new ArrayList<>();
+			List<L2DropCategory> categories = new ArrayList<>();
 			
 			if (old != null)
 			{

+ 2 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/L2Attackable.java

@@ -15,6 +15,7 @@
 package com.l2jserver.gameserver.model.actor;
 
 import java.util.List;
+import java.util.Set;
 import java.util.logging.Level;
 
 import javolution.util.FastList;
@@ -2208,7 +2209,7 @@ public class L2Attackable extends L2Npc
 		_seedType = id;
 		int count = 1;
 		
-		int[] skillIds = getTemplate().getSkills().keys();
+		Set<Integer> skillIds = getTemplate().getSkills().keySet();
 		
 		if (skillIds != null)
 		{

+ 15 - 5
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2GuardInstance.java

@@ -14,6 +14,7 @@
  */
 package com.l2jserver.gameserver.model.actor.instance;
 
+import java.util.List;
 import java.util.logging.Logger;
 
 import com.l2jserver.Config;
@@ -28,6 +29,7 @@ import com.l2jserver.gameserver.model.actor.L2Character;
 import com.l2jserver.gameserver.model.actor.knownlist.GuardKnownList;
 import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
 import com.l2jserver.gameserver.model.quest.Quest;
+import com.l2jserver.gameserver.model.quest.Quest.QuestEventType;
 import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
 import com.l2jserver.gameserver.network.serverpackets.MyTargetSelected;
 import com.l2jserver.gameserver.network.serverpackets.SocialAction;
@@ -221,14 +223,22 @@ public class L2GuardInstance extends L2Attackable
 					broadcastPacket(sa);
 					
 					// Open a chat window on client with the text of the L2GuardInstance
-					Quest[] qlsa = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
-					if ( (qlsa != null) && qlsa.length > 0)
+					List<Quest> qlsa = getTemplate().getEventQuests(QuestEventType.QUEST_START);
+					List<Quest> qlst = getTemplate().getEventQuests(QuestEventType.ON_FIRST_TALK);
+					
+					if ((qlsa != null) && !qlsa.isEmpty())
+					{
 						player.setLastQuestNpcObject(getObjectId());
-					Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.ON_FIRST_TALK);
-					if ( (qlst != null) && qlst.length == 1)
-						qlst[0].notifyFirstTalk(this, player);
+					}
+					
+					if ((qlst != null) && qlst.size() == 1)
+					{
+						qlst.get(0).notifyFirstTalk(this, player);
+					}
 					else
+					{
 						showChatWindow(player, 0);
+					}
 				}
 			}
 		}

+ 13 - 5
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java

@@ -183,6 +183,7 @@ import com.l2jserver.gameserver.model.olympiad.OlympiadGameManager;
 import com.l2jserver.gameserver.model.olympiad.OlympiadGameTask;
 import com.l2jserver.gameserver.model.olympiad.OlympiadManager;
 import com.l2jserver.gameserver.model.quest.Quest;
+import com.l2jserver.gameserver.model.quest.Quest.QuestEventType;
 import com.l2jserver.gameserver.model.quest.QuestState;
 import com.l2jserver.gameserver.model.quest.State;
 import com.l2jserver.gameserver.model.skills.L2Skill;
@@ -1706,7 +1707,7 @@ public final class L2PcInstance extends L2Playable
 		QuestState[] states = null;
 		
 		// Go through the QuestState of the L2PcInstance quests
-		for (Quest quest : npc.getTemplate().getEventQuests(Quest.QuestEventType.ON_ATTACK))
+		for (Quest quest : npc.getTemplate().getEventQuests(QuestEventType.ON_ATTACK))
 		{
 			// Check if the Identifier of the L2Attackable attck is needed for the current quest
 			if (getQuestState(quest.getName())!=null)
@@ -1733,7 +1734,7 @@ public final class L2PcInstance extends L2Playable
 		QuestState[] states = null;
 		
 		// Go through the QuestState of the L2PcInstance quests
-		for (Quest quest : npc.getTemplate().getEventQuests(Quest.QuestEventType.ON_KILL))
+		for (Quest quest : npc.getTemplate().getEventQuests(QuestEventType.ON_KILL))
 		{
 			// Check if the Identifier of the L2Attackable killed is needed for the current quest
 			if (getQuestState(quest.getName())!=null)
@@ -1760,7 +1761,7 @@ public final class L2PcInstance extends L2Playable
 		QuestState[] states = null;
 		
 		// Go through the QuestState of the L2PcInstance quests
-		Quest[] quests = NpcTable.getInstance().getTemplate(npcId).getEventQuests(Quest.QuestEventType.ON_TALK);
+		List<Quest> quests = NpcTable.getInstance().getTemplate(npcId).getEventQuests(QuestEventType.ON_TALK);
 		if (quests != null)
 		{
 			for (Quest quest: quests)
@@ -1768,12 +1769,19 @@ public final class L2PcInstance extends L2Playable
 				if (quest != null)
 				{
 					// Copy the current L2PcInstance QuestState in the QuestState table
-					if (getQuestState(quest.getName())!=null)
+					if (getQuestState(quest.getName()) != null)
 					{
 						if (states == null)
-							states = new QuestState[]{getQuestState(quest.getName())};
+						{
+							states = new QuestState[]
+							{
+								getQuestState(quest.getName())
+							};
+						}
 						else
+						{
 							states = addToQuestStateArray(states, getQuestState(quest.getName()));
+						}
 					}
 				}
 			}

+ 14 - 5
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2SepulcherNpcInstance.java

@@ -16,6 +16,7 @@ package com.l2jserver.gameserver.model.actor.instance;
 
 import gnu.trove.procedure.TObjectProcedure;
 
+import java.util.List;
 import java.util.concurrent.Future;
 
 import com.l2jserver.Config;
@@ -251,14 +252,22 @@ public class L2SepulcherNpcInstance extends L2Npc
 				
 			default:
 			{
-				Quest[] qlsa = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
-				if ( (qlsa != null) && qlsa.length > 0)
+				List<Quest> qlsa = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
+				List<Quest> qlst = getTemplate().getEventQuests(Quest.QuestEventType.ON_FIRST_TALK);
+				
+				if ((qlsa != null) && !qlsa.isEmpty())
+				{
 					player.setLastQuestNpcObject(getObjectId());
-				Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.ON_FIRST_TALK);
-				if ( (qlst != null) && qlst.length == 1)
-					qlst[0].notifyFirstTalk(this, player);
+				}
+				
+				if ((qlst != null) && qlst.size() == 1)
+				{
+					qlst.get(0).notifyFirstTalk(this, player);
+				}
 				else
+				{
 					showChatWindow(player, 0);
+				}
 			}
 		}
 		player.sendPacket(ActionFailed.STATIC_PACKET);

+ 4 - 4
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2TamedBeastInstance.java

@@ -249,7 +249,7 @@ public final class L2TamedBeastInstance extends L2FeedableBeastInstance
 			{
 				// instead of calculating this value each time, let's get this now and pass it on
 				int totalBuffsAvailable = 0;
-				for (L2Skill skill: getTemplate().getSkillsArray())
+				for (L2Skill skill: getTemplate().getSkills().values())
 				{
 					// if the skill is a buff, check if the owner has it already [  owner.getEffect(L2Skill skill) ]
 					if (skill.getSkillType() == L2SkillType.BUFF)
@@ -325,7 +325,7 @@ public final class L2TamedBeastInstance extends L2FeedableBeastInstance
 		// use of more than one debuff at this moment is acceptable
 		if (HPRatio >= 0.8)
 		{
-			for (L2Skill skill: getTemplate().getSkillsArray())
+			for (L2Skill skill: getTemplate().getSkills().values())
 			{
 				// if the skill is a debuff, check if the attacker has it already [  attacker.getEffect(L2Skill skill) ]
 				if ((skill.getSkillType() == L2SkillType.DEBUFF) && Rnd.get(3) < 1 && (attacker != null && attacker.getFirstEffect(skill) != null))
@@ -343,7 +343,7 @@ public final class L2TamedBeastInstance extends L2FeedableBeastInstance
 				chance = 2;
 			
 			// if the owner has a lot of HP, then debuff the enemy with a random debuff among the available skills
-			for (L2Skill skill: getTemplate().getSkillsArray())
+			for (L2Skill skill: getTemplate().getSkills().values())
 			{
 				// if the skill is a buff, check if the owner has it already [  owner.getEffect(L2Skill skill) ]
 				if ( (Rnd.get(5) < chance) && ((skill.getSkillType() == L2SkillType.HEAL) ||
@@ -499,7 +499,7 @@ public final class L2TamedBeastInstance extends L2FeedableBeastInstance
 			L2Skill buffToGive = null;
 			
 			// get this npc's skills:  getSkills()
-			for (L2Skill skill: _tamedBeast.getTemplate().getSkillsArray())
+			for (L2Skill skill: _tamedBeast.getTemplate().getSkills().values())
 			{
 				// if the skill is a buff, check if the owner has it already [  owner.getEffect(L2Skill skill) ]
 				if (skill.getSkillType() == L2SkillType.BUFF)

+ 78 - 106
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/templates/L2NpcTemplate.java

@@ -14,13 +14,13 @@
  */
 package com.l2jserver.gameserver.model.actor.templates;
 
-import gnu.trove.map.hash.TIntObjectHashMap;
-
+import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.logging.Logger;
 
-import javolution.util.FastList;
 import javolution.util.FastMap;
 
 import com.l2jserver.gameserver.datatables.HerbDropTable;
@@ -69,48 +69,48 @@ public final class L2NpcTemplate extends L2CharTemplate
 	private final float _baseVitalityDivider;
 	
 	// Skill AI
-	private final FastList<L2Skill> _buffSkills = new FastList<>();
-	private final FastList<L2Skill> _negativeSkills = new FastList<>();
-	private final FastList<L2Skill> _debuffSkills = new FastList<>();
-	private final FastList<L2Skill> _atkSkills = new FastList<>();
-	private final FastList<L2Skill> _rootSkills = new FastList<>();
-	private final FastList<L2Skill> _stunskills = new FastList<>();
-	private final FastList<L2Skill> _sleepSkills = new FastList<>();
-	private final FastList<L2Skill> _paralyzeSkills = new FastList<>();
-	private final FastList<L2Skill> _fossilSkills = new FastList<>();
-	private final FastList<L2Skill> _floatSkills = new FastList<>();
-	private final FastList<L2Skill> _immobilizeSkills = new FastList<>();
-	private final FastList<L2Skill> _healSkills = new FastList<>();
-	private final FastList<L2Skill> _resSkills = new FastList<>();
-	private final FastList<L2Skill> _dotSkills = new FastList<>();
-	private final FastList<L2Skill> _cotSkills = new FastList<>();
-	private final FastList<L2Skill> _universalSkills = new FastList<>();
-	private final FastList<L2Skill> _manaSkills = new FastList<>();
-	private final FastList<L2Skill> _longRangeSkills = new FastList<>();
-	private final FastList<L2Skill> _shortRangeSkills = new FastList<>();
-	private final FastList<L2Skill> _generalSkills = new FastList<>();
-	private final FastList<L2Skill> _suicideSkills = new FastList<>();
+	private final List<L2Skill> _buffSkills = new ArrayList<>();
+	private final List<L2Skill> _negativeSkills = new ArrayList<>();
+	private final List<L2Skill> _debuffSkills = new ArrayList<>();
+	private final List<L2Skill> _atkSkills = new ArrayList<>();
+	private final List<L2Skill> _rootSkills = new ArrayList<>();
+	private final List<L2Skill> _stunskills = new ArrayList<>();
+	private final List<L2Skill> _sleepSkills = new ArrayList<>();
+	private final List<L2Skill> _paralyzeSkills = new ArrayList<>();
+	private final List<L2Skill> _fossilSkills = new ArrayList<>();
+	private final List<L2Skill> _floatSkills = new ArrayList<>();
+	private final List<L2Skill> _immobilizeSkills = new ArrayList<>();
+	private final List<L2Skill> _healSkills = new ArrayList<>();
+	private final List<L2Skill> _resSkills = new ArrayList<>();
+	private final List<L2Skill> _dotSkills = new ArrayList<>();
+	private final List<L2Skill> _cotSkills = new ArrayList<>();
+	private final List<L2Skill> _universalSkills = new ArrayList<>();
+	private final List<L2Skill> _manaSkills = new ArrayList<>();
+	private final List<L2Skill> _longRangeSkills = new ArrayList<>();
+	private final List<L2Skill> _shortRangeSkills = new ArrayList<>();
+	private final List<L2Skill> _generalSkills = new ArrayList<>();
+	private final List<L2Skill> _suicideSkills = new ArrayList<>();
 	
 	private L2NpcAIData _AIdataStatic = new L2NpcAIData();
 	
 	/**
 	 * The table containing all Item that can be dropped by L2NpcInstance using this L2NpcTemplate
 	 */
-	private final FastList<L2DropCategory> _categories = new FastList<>();
+	private final List<L2DropCategory> _categories = new ArrayList<>();
 	
 	/**
 	 * The table containing all Minions that must be spawn with the L2NpcInstance using this L2NpcTemplate
 	 */
-	private final List<L2MinionData> _minions = new FastList<>();
+	private final List<L2MinionData> _minions = new ArrayList<>();
 	
-	private final List<ClassId> _teachInfo = new FastList<>();
+	private final List<ClassId> _teachInfo = new ArrayList<>();
 	
-	private final TIntObjectHashMap<L2Skill> _skills = new TIntObjectHashMap<>();
+	private final Map<Integer, L2Skill> _skills = new FastMap<Integer, L2Skill>().shared();
 	
 	/**
 	 * Contains a list of quests for each event type (questStart, questAttack, questKill, etc).
 	 */
-	private final Map<QuestEventType, Quest[]> _questEvents = new FastMap<>();
+	private final Map<QuestEventType, List<Quest>> _questEvents = new FastMap<QuestEventType, List<Quest>>().shared();
 	
 	public static enum AIType
 	{
@@ -270,13 +270,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	 */
 	public void addDropData(L2DropData drop, int categoryType)
 	{
-		if (drop.isQuestDrop())
-		{
-			// if (_questDrops == null)
-			// _questDrops = new FastList<L2DropData>(0);
-			// _questDrops.add(drop);
-		}
-		else
+		if (!drop.isQuestDrop())
 		{
 			// If the category doesn't already exist, create it first
 			synchronized (_categories)
@@ -343,63 +337,47 @@ public final class L2NpcTemplate extends L2CharTemplate
 		_paralyzeSkills.add(skill);
 	}
 	
-	public void addQuestEvent(Quest.QuestEventType EventType, Quest q)
+	public void addQuestEvent(QuestEventType EventType, Quest q)
 	{
-		if (_questEvents.get(EventType) == null)
+		if (!_questEvents.containsKey(EventType))
 		{
-			_questEvents.put(EventType, new Quest[]
-			{
-				q
-			});
+			List<Quest> quests = new ArrayList<Quest>();
+			quests.add(q);
+			_questEvents.put(EventType, quests);
 		}
 		else
 		{
-			Quest[] _quests = _questEvents.get(EventType);
-			int len = _quests.length;
+			List<Quest> quests = _questEvents.get(EventType);
 			
-			// if only one registration per npc is allowed for this event type
-			// then only register this NPC if not already registered for the specified event.
-			// if a quest allows multiple registrations, then register regardless of count
-			// In all cases, check if this new registration is replacing an older copy of the SAME quest
-			// Finally, check quest class hierarchy: a parent class should never replace a child class.
-			// a child class should always replace a parent class.
-			if (!EventType.isMultipleRegistrationAllowed())
+			if (!EventType.isMultipleRegistrationAllowed() && !quests.isEmpty())
 			{
-				// if it is the same quest (i.e. reload) or the existing is a superclass of the new one, replace the existing.
-				if (_quests[0].getName().equals(q.getName()) || L2NpcTemplate.isAssignableTo(q, _quests[0].getClass()))
-				{
-					_quests[0] = q;
-				}
-				else
-				{
-					_log.warning("Quest event not allowed in multiple quests.  Skipped addition of Event Type \"" + EventType + "\" for NPC \"" + _name + "\" and quest \"" + q.getName() + "\".");
-				}
+				_log.warning("Quest event not allowed in multiple quests.  Skipped addition of Event Type \"" + EventType + "\" for NPC \"" + _name + "\" and quest \"" + q.getName() + "\".");
 			}
 			else
 			{
-				// be ready to add a new quest to a new copy of the list, with larger size than previously.
-				Quest[] tmp = new Quest[len + 1];
+				quests.add(q);
+			}
+		}
+	}
+
+	public void removeQuest(Quest q)
+	{
+		for (Entry<QuestEventType, List<Quest>> entry : _questEvents.entrySet())
+		{
+			if (entry.getValue().contains(q))
+			{
+				Iterator<Quest> it = entry.getValue().iterator();
+				while (it.hasNext())
+				{
+					Quest q1 = it.next();
+					if (q1 == q)
+						it.remove();
+				}
 				
-				// loop through the existing quests and copy them to the new list. While doing so, also
-				// check if this new quest happens to be just a replacement for a previously loaded quest.
-				// Replace existing if the new quest is the same (reload) or a child of the existing quest.
-				// Do nothing if the new quest is a superclass of an existing quest.
-				// Add the new quest in the end of the list otherwise.
-				for (int i = 0; i < len; i++)
+				if (entry.getValue().isEmpty())
 				{
-					if (_quests[i].getName().equals(q.getName()) || L2NpcTemplate.isAssignableTo(q, _quests[i].getClass()))
-					{
-						_quests[i] = q;
-						return;
-					}
-					else if (L2NpcTemplate.isAssignableTo(_quests[i], q.getClass()))
-					{
-						return;
-					}
-					tmp[i] = _quests[i];
+					_questEvents.remove(entry.getKey());
 				}
-				tmp[len] = q;
-				_questEvents.put(EventType, tmp);
 			}
 		}
 	}
@@ -563,10 +541,9 @@ public final class L2NpcTemplate extends L2CharTemplate
 	 */
 	public synchronized void clearAllDropData()
 	{
-		while (!_categories.isEmpty())
+		for (L2DropCategory cat : _categories)
 		{
-			_categories.getFirst().clearAllDrops();
-			_categories.removeFirst();
+			cat.clearAllDrops();
 		}
 		_categories.clear();
 	}
@@ -582,7 +559,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	 */
 	public List<L2DropData> getAllDropData()
 	{
-		final List<L2DropData> list = new FastList<>();
+		final List<L2DropData> list = new ArrayList<>();
 		for (L2DropCategory tmp : _categories)
 		{
 			list.addAll(tmp.getAllDrops());
@@ -593,7 +570,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the attack skills.
 	 */
-	public FastList<L2Skill> getAtkSkills()
+	public List<L2Skill> getAtkSkills()
 	{
 		return _atkSkills;
 	}
@@ -609,7 +586,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the buff skills.
 	 */
-	public FastList<L2Skill> getBuffSkills()
+	public List<L2Skill> getBuffSkills()
 	{
 		return _buffSkills;
 	}
@@ -625,7 +602,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the cost over time skills.
 	 */
-	public FastList<L2Skill> getCostOverTimeSkills()
+	public List<L2Skill> getCostOverTimeSkills()
 	{
 		return _cotSkills;
 	}
@@ -633,7 +610,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the debuff skills.
 	 */
-	public FastList<L2Skill> getDebuffSkills()
+	public List<L2Skill> getDebuffSkills()
 	{
 		return _debuffSkills;
 	}
@@ -641,7 +618,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the list of all possible UNCATEGORIZED drops of this L2NpcTemplate.
 	 */
-	public FastList<L2DropCategory> getDropData()
+	public List<L2DropCategory> getDropData()
 	{
 		return _categories;
 	}
@@ -662,12 +639,12 @@ public final class L2NpcTemplate extends L2CharTemplate
 		return _enchantEffect;
 	}
 	
-	public Map<QuestEventType, Quest[]> getEventQuests()
+	public Map<QuestEventType, List<Quest>> getEventQuests()
 	{
 		return _questEvents;
 	}
 	
-	public Quest[] getEventQuests(QuestEventType EventType)
+	public List<Quest> getEventQuests(QuestEventType EventType)
 	{
 		return _questEvents.get(EventType);
 	}
@@ -675,7 +652,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the general skills.
 	 */
-	public FastList<L2Skill> getGeneralskills()
+	public List<L2Skill> getGeneralskills()
 	{
 		return _generalSkills;
 	}
@@ -683,7 +660,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the heal skills.
 	 */
-	public FastList<L2Skill> getHealSkills()
+	public List<L2Skill> getHealSkills()
 	{
 		return _healSkills;
 	}
@@ -699,7 +676,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the immobilize skills.
 	 */
-	public FastList<L2Skill> getImmobiliseSkills()
+	public List<L2Skill> getImmobiliseSkills()
 	{
 		return _immobilizeSkills;
 	}
@@ -723,7 +700,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the long range skills.
 	 */
-	public FastList<L2Skill> getLongRangeSkills()
+	public List<L2Skill> getLongRangeSkills()
 	{
 		return _longRangeSkills;
 	}
@@ -747,7 +724,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the negative skills.
 	 */
-	public FastList<L2Skill> getNegativeSkills()
+	public List<L2Skill> getNegativeSkills()
 	{
 		return _negativeSkills;
 	}
@@ -775,7 +752,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the resurrection skills.
 	 */
-	public FastList<L2Skill> getResSkills()
+	public List<L2Skill> getResSkills()
 	{
 		return _resSkills;
 	}
@@ -815,22 +792,17 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the short range skills.
 	 */
-	public FastList<L2Skill> getShortRangeSkills()
+	public List<L2Skill> getShortRangeSkills()
 	{
 		return _shortRangeSkills;
 	}
 	
-	public TIntObjectHashMap<L2Skill> getSkills()
+	public Map<Integer, L2Skill> getSkills()
 	{
 		return _skills;
 	}
 	
-	public L2Skill[] getSkillsArray()
-	{
-		return _skills.values(new L2Skill[0]);
-	}
-	
-	public FastList<L2Skill> getSuicideSkills()
+	public List<L2Skill> getSuicideSkills()
 	{
 		return _suicideSkills;
 	}
@@ -859,7 +831,7 @@ public final class L2NpcTemplate extends L2CharTemplate
 	/**
 	 * @return the universal skills.
 	 */
-	public FastList<L2Skill> getUniversalSkills()
+	public List<L2Skill> getUniversalSkills()
 	{
 		return _universalSkills;
 	}

+ 19 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/quest/Quest.java

@@ -17,7 +17,9 @@ package com.l2jserver.gameserver.model.quest;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.logging.Level;
@@ -80,10 +82,12 @@ public class Quest extends ManagedScript
 	 * HashMap containing events from String value of the event.
 	 */
 	private static Map<String, Quest> _allEventsS = new FastMap<String, Quest>();
+	
 	/**
 	 * HashMap containing lists of timers from the name of the timer.
 	 */
 	private final Map<String, FastList<QuestTimer>> _allEventTimers = new FastMap<String, FastList<QuestTimer>>().shared();
+	private final List<Integer> _questInvolvedNpcs = new ArrayList<>();
 	
 	private final ReentrantReadWriteLock _rwLock = new ReentrantReadWriteLock();
 	
@@ -1737,6 +1741,12 @@ public class Quest extends ManagedScript
 			{
 				t.addQuestEvent(eventType, this);
 			}
+			
+			if (!_questInvolvedNpcs.contains(Integer.valueOf(npcId)))
+			{
+				_questInvolvedNpcs.add(npcId);
+			}
+			
 			return t;
 		}
 		catch (Exception e)
@@ -2618,6 +2628,15 @@ public class Quest extends ManagedScript
 			}
 		}
 		_allEventTimers.clear();
+		
+		for (Integer npcId : _questInvolvedNpcs)
+		{
+			L2NpcTemplate template = NpcTable.getInstance().getTemplate(npcId);
+			if (template != null)
+				template.removeQuest(this);
+		}
+		_questInvolvedNpcs.clear();
+		
 		if (removeFromList)
 		{
 			return QuestManager.getInstance().removeQuest(this);