Kaynağa Gözat

BETA: Reworking npc reload during runtime:
* No more creation of new L2NpcTemplate instances - reusing existing ones.
* '''Note''': Fields of L2NpcTemplate, L2CharTemplate are unfinalized and setters are moved into new method called set.
* Fixing problem causing reload of npc to do not take any effect until mob is respawned.
* Added ability to reload each part of npc (base, ai, elements, skills, drops, etc..)
* Patch by: Nos

Rumen Nikiforov 12 yıl önce
ebeveyn
işleme
3a71bcc0ca

+ 148 - 57
L2J_Server_BETA/java/com/l2jserver/gameserver/datatables/NpcTable.java

@@ -23,6 +23,7 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -39,8 +40,6 @@ import com.l2jserver.gameserver.model.L2NpcAIData;
 import com.l2jserver.gameserver.model.StatsSet;
 import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
 import com.l2jserver.gameserver.model.base.ClassId;
-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.stats.BaseStats;
 
@@ -181,40 +180,55 @@ public class NpcTable
 		npcDat.set("baseHolyRes", 20);
 		npcDat.set("baseDarkRes", 20);
 		
-		_npcs.put(id, new L2NpcTemplate(npcDat));
+		final L2NpcTemplate template = getTemplate(id);
+		if (template == null)
+		{
+			_npcs.put(id, new L2NpcTemplate(npcDat));
+		}
+		else
+		{
+			template.set(npcDat);
+		}
 	}
 	
 	/**
 	 * Reload npc.
 	 * @param id of the NPC to reload.
+	 * @param base reloads base npc data.
+	 * @param ai reloads AI npc data.
+	 * @param element reloads elemental npc data
+	 * @param skills reloads skills npc data.
+	 * @param drops reloads drop npc data
+	 * @param minions reloads minions npc data.
 	 */
-	public void reloadNpc(int id)
+	public void reloadNpc(int id, boolean base, boolean ai, boolean element, boolean skills, boolean drops, boolean minions)
 	{
-		Map<QuestEventType, List<Quest>> quests = null;
 		try
 		{
-			// save a copy of the old data
-			L2NpcTemplate old = getTemplate(id);
-			
-			if (old != null)
+			if (base)
 			{
-				quests = old.getEventQuests();
+				loadNpcs(id);
 			}
-			
-			loadNpcs(id);
-			loadNpcsSkills(id);
-			loadNpcsDrop(id);
-			loadNpcsSkillLearn(id);
-			loadMinions(id);
-			loadNpcsAI(id);
-			loadNpcsElement(id);
-			
-			// restore additional data from saved copy
-			L2NpcTemplate created = getTemplate(id);
-			
-			if ((old != null) && (created != null))
+			if (ai)
 			{
-				created.getEventQuests().putAll(quests);
+				loadNpcsAI(id);
+			}
+			if (element)
+			{
+				loadNpcsElement(id);
+			}
+			if (skills)
+			{
+				loadNpcsSkills(id);
+				loadNpcsSkillLearn(id);
+			}
+			if (drops)
+			{
+				loadNpcsDrop(id);
+			}
+			if (minions)
+			{
+				loadMinions(id);
 			}
 		}
 		catch (Exception e)
@@ -232,41 +246,113 @@ public class NpcTable
 	}
 	
 	/**
-	 * Save npc.
+	 * Save npc into the database.
 	 * @param npc the npc
 	 */
 	public void saveNpc(StatsSet npc)
 	{
-		final Map<String, Object> set = npc.getSet();
-		int length = 0;
-		for (Object obj : set.keySet())
-		{
-			// 15 is just guessed npc name length
-			length += ((String) obj).length() + 7 + 15;
-		}
+		final int npcId = npc.getInteger("npcId");
+		
+		final StringBuilder npcAttributes = new StringBuilder();
+		final ArrayList<Object> npcAttributeValues = new ArrayList<>();
+		
+		final StringBuilder npcaidataAttributes = new StringBuilder();
+		final ArrayList<Object> npcaidataAttributeValues = new ArrayList<>();
 		
-		final StringBuilder npcSb = new StringBuilder(length);
-		final StringBuilder npcAiSb = new StringBuilder(30);
-		String attribute;
-		String value;
-		for (Entry<String, Object> entry : set.entrySet())
+		final StringBuilder npcElementAttributes = new StringBuilder();
+		final ArrayList<Object> npcElementAttributeValues = new ArrayList<>();
+		
+		for (Entry<String, Object> entry : npc.getSet().entrySet())
 		{
-			attribute = entry.getKey();
-			value = String.valueOf(entry.getValue());
-			switch (attribute)
+			switch (entry.getKey())
 			{
 				case "npcId":
 					break;
-				case "aggro":
-				case "showName":
+				case "serverSideName":
+				case "serverSideTitle":
+				case "sex":
+				case "enchant":
+				case "level":
+				case "str":
+				case "con":
+				case "dex":
+				case "int":
+				case "wit":
+				case "men":
+				case "critical":
+				case "dropHerbGroup":
+				case "atkspd":
+				case "matkspd":
+				case "attackrange":
+				case "rhand":
+				case "lhand":
+				case "idTemplate":
+				case "exp":
+				case "sp":
+				case "collision_radius":
+				case "collision_height":
+				case "walkspd":
+				case "runspd":
+				case "patk":
+				case "pdef":
+				case "matk":
+				case "mdef":
+				case "hp":
+				case "mp":
+				case "hpreg":
+				case "mpreg":
+				case "type":
+				case "title":
+				case "name":
+				{
+					appendEntry(npcAttributes, entry.getKey());
+					npcAttributeValues.add(entry.getValue());
+					break;
+				}
+				case "canMove":
 				case "targetable":
+				case "showName":
+				case "isChaos":
+				case "dodge":
+				case "minSkillChance":
+				case "maxSkillChance":
+				case "minRangeChance":
+				case "maxRangeChance":
+				case "ssChance":
+				case "spsChance":
+				case "aggro":
+				case "clanRange":
+				case "enemyRange":
+				case "primarySkillId":
+				case "minRangeSkill":
+				case "maxRangeSkill":
+				case "soulShot":
+				case "spiritShot":
+				case "clan":
+				case "enemyClan":
+				case "aiType":
+				{
+					appendEntry(npcaidataAttributes, entry.getKey());
+					npcaidataAttributeValues.add(entry.getValue());
+					break;
+				}
+				case "elemAtkType":
+				case "elemAtkValue":
+				case "fireDefValue":
+				case "waterDefValue":
+				case "windDefValue":
+				case "earthDefValue":
+				case "holyDefValue":
+				case "darkDefValue":
 				{
-					appendEntry(npcAiSb, attribute, value);
+					appendEntry(npcElementAttributes, entry.getKey());
+					npcElementAttributeValues.add(entry.getValue());
 					break;
 				}
 				default:
 				{
-					appendEntry(npcSb, attribute, value);
+					_log.warning("Unknown stat " + entry.getKey() + " can't set.");
+					return;
 				}
 			}
 		}
@@ -274,17 +360,18 @@ public class NpcTable
 		try (Connection con = L2DatabaseFactory.getInstance().getConnection())
 		{
 			int updated = 0;
-			final int npcId = npc.getInteger("npcId");
 			if (Config.CUSTOM_NPC_TABLE)
 			{
-				updated = performUpdate(npcSb, "custom_npc", "id", npcId, con);
-				performUpdate(npcAiSb, "custom_npcaidata", "npcId", npcId, con);
+				updated += performUpdate(npcAttributes, "custom_npc", "id", npcAttributeValues, npcId, con);
+				updated += performUpdate(npcaidataAttributes, "custom_npcaidata", "npcId", npcaidataAttributeValues, npcId, con);
+				updated += performUpdate(npcElementAttributes, "custom_npc_elementals", "npc_id", npcElementAttributeValues, npcId, con);
 			}
 			
 			if (updated == 0)
 			{
-				performUpdate(npcSb, "npc", "id", npcId, con);
-				performUpdate(npcAiSb, "npcaidata", "npcId", npcId, con);
+				updated += performUpdate(npcAttributes, "npc", "id", npcAttributeValues, npcId, con);
+				updated += performUpdate(npcaidataAttributes, "npcaidata", "npcId", npcaidataAttributeValues, npcId, con);
+				updated += performUpdate(npcElementAttributes, "npc_elementals", "npc_id", npcElementAttributeValues, npcId, con);
 			}
 		}
 		catch (Exception e)
@@ -297,19 +384,16 @@ public class NpcTable
 	 * Append entry.
 	 * @param sb the string builder to append the attribute and value.
 	 * @param attribute the attribute to append.
-	 * @param value the value to append.
 	 */
-	private final void appendEntry(StringBuilder sb, String attribute, String value)
+	private final void appendEntry(StringBuilder sb, String attribute)
 	{
 		if (sb.length() > 0)
 		{
 			sb.append(", ");
 		}
-		
+		sb.append("`");
 		sb.append(attribute);
-		sb.append(" = '");
-		sb.append(value);
-		sb.append('\'');
+		sb.append("` = ?");
 	}
 	
 	/**
@@ -317,12 +401,13 @@ public class NpcTable
 	 * @param sb the string builder with the parameters
 	 * @param table the table to update.
 	 * @param key the key of the table.
+	 * @param values the values of keys.
 	 * @param npcId the Npc Id.
 	 * @param con the current database connection.
 	 * @return the count of updated NPCs.
 	 * @throws SQLException the SQL exception.
 	 */
-	private final int performUpdate(StringBuilder sb, String table, String key, int npcId, Connection con) throws SQLException
+	private final int performUpdate(StringBuilder sb, String table, String key, Collection<Object> values, int npcId, Connection con) throws SQLException
 	{
 		int updated = 0;
 		if ((sb != null) && !sb.toString().isEmpty())
@@ -337,7 +422,13 @@ public class NpcTable
 			sbQuery.append(" = ?");
 			try (PreparedStatement ps = con.prepareStatement(sbQuery.toString()))
 			{
-				ps.setInt(1, npcId);
+				int i = 1;
+				for (Object value : values)
+				{
+					ps.setObject(i, value);
+					i++;
+				}
+				ps.setInt(i, npcId);
 				updated = ps.executeUpdate();
 			}
 		}

+ 53 - 48
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/templates/L2CharTemplate.java

@@ -30,49 +30,49 @@ import com.l2jserver.gameserver.model.stats.MoveType;
 public class L2CharTemplate
 {
 	// BaseStats
-	private final int _baseSTR;
-	private final int _baseCON;
-	private final int _baseDEX;
-	private final int _baseINT;
-	private final int _baseWIT;
-	private final int _baseMEN;
-	private final float _baseHpMax;
-	private final float _baseCpMax;
-	private final float _baseMpMax;
-	private final float _baseHpReg;
-	private final float _baseMpReg;
-	private final int _basePAtk;
-	private final int _baseMAtk;
-	private final int _basePDef;
-	private final int _baseMDef;
-	private final int _basePAtkSpd;
-	private final int _baseMAtkSpd;
-	private final float _baseMReuseRate;
-	private final int _baseShldDef;
-	private final int _baseAtkRange;
-	private final int _baseShldRate;
-	private final int _baseCritRate;
-	private final int _baseMCritRate;
-	private final int _baseWalkSpd;
-	private final int _baseRunSpd;
+	private int _baseSTR;
+	private int _baseCON;
+	private int _baseDEX;
+	private int _baseINT;
+	private int _baseWIT;
+	private int _baseMEN;
+	private float _baseHpMax;
+	private float _baseCpMax;
+	private float _baseMpMax;
+	private float _baseHpReg;
+	private float _baseMpReg;
+	private int _basePAtk;
+	private int _baseMAtk;
+	private int _basePDef;
+	private int _baseMDef;
+	private int _basePAtkSpd;
+	private int _baseMAtkSpd;
+	private float _baseMReuseRate;
+	private int _baseShldDef;
+	private int _baseAtkRange;
+	private int _baseShldRate;
+	private int _baseCritRate;
+	private int _baseMCritRate;
+	private int _baseWalkSpd;
+	private int _baseRunSpd;
 	// SpecialStats
-	private final int _baseBreath;
-	private final int _baseAggression;
-	private final int _baseBleed;
-	private final int _basePoison;
-	private final int _baseStun;
-	private final int _baseRoot;
-	private final int _baseMovement;
-	private final int _baseConfusion;
-	private final int _baseSleep;
-	private final double _baseAggressionVuln;
-	private final double _baseBleedVuln;
-	private final double _basePoisonVuln;
-	private final double _baseStunVuln;
-	private final double _baseRootVuln;
-	private final double _baseMovementVuln;
-	private final double _baseSleepVuln;
-	private final double _baseCritVuln;
+	private int _baseBreath;
+	private int _baseAggression;
+	private int _baseBleed;
+	private int _basePoison;
+	private int _baseStun;
+	private int _baseRoot;
+	private int _baseMovement;
+	private int _baseConfusion;
+	private int _baseSleep;
+	private double _baseAggressionVuln;
+	private double _baseBleedVuln;
+	private double _basePoisonVuln;
+	private double _baseStunVuln;
+	private double _baseRootVuln;
+	private double _baseMovementVuln;
+	private double _baseSleepVuln;
+	private double _baseCritVuln;
 	private int _baseFire;
 	private int _baseWind;
 	private int _baseWater;
@@ -86,23 +86,28 @@ public class L2CharTemplate
 	private double _baseHolyRes;
 	private double _baseDarkRes;
 	
-	private final int _baseMpConsumeRate;
-	private final int _baseHpConsumeRate;
+	private int _baseMpConsumeRate;
+	private int _baseHpConsumeRate;
 	
 	/**
 	 * For client info use {@link #_fCollisionRadius}
 	 */
-	private final int _collisionRadius;
+	private int _collisionRadius;
 	
 	/**
 	 * For client info use {@link #_fCollisionHeight}
 	 */
-	private final int _collisionHeight;
+	private int _collisionHeight;
 	
-	private final double _fCollisionRadius;
-	private final double _fCollisionHeight;
+	private double _fCollisionRadius;
+	private double _fCollisionHeight;
 	
 	public L2CharTemplate(StatsSet set)
+	{
+		set(set);
+	}
+	
+	public void set(StatsSet set)
 	{
 		// Base stats
 		_baseSTR = set.getInteger("baseSTR", 0);

+ 69 - 68
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/templates/L2NpcTemplate.java

@@ -46,31 +46,31 @@ public final class L2NpcTemplate extends L2CharTemplate
 {
 	private static final Logger _log = Logger.getLogger(L2NpcTemplate.class.getName());
 	
-	private final int _npcId;
-	private final int _idTemplate;
-	private final String _type;
-	private final String _name;
-	private final boolean _serverSideName;
-	private final String _title;
-	private final boolean _serverSideTitle;
-	private final String _sex;
-	private final byte _level;
-	private final int _rewardExp;
-	private final int _rewardSp;
-	private final int _rHand;
-	private final int _lHand;
-	private final int _enchantEffect;
-	
-	private Race _race;
-	private final String _clientClass;
-	
-	private final int _dropHerbGroup;
-	private final boolean _isCustom;
+	private int _npcId;
+	private int _idTemplate;
+	private String _type;
+	private String _name;
+	private boolean _serverSideName;
+	private String _title;
+	private boolean _serverSideTitle;
+	private String _sex;
+	private byte _level;
+	private int _rewardExp;
+	private int _rewardSp;
+	private int _rHand;
+	private int _lHand;
+	private int _enchantEffect;
+	
+	private Race _race = Race.NONE;
+	private String _clientClass;
+	
+	private int _dropHerbGroup;
+	private boolean _isCustom;
 	/**
 	 * Doesn't include all mobs that are involved in quests, just plain quest monsters for preventing champion spawn.
 	 */
-	private final boolean _isQuestMonster;
-	private final float _baseVitalityDivider;
+	private boolean _isQuestMonster;
+	private float _baseVitalityDivider;
 	
 	// Skill AI
 	private final List<L2Skill> _buffSkills = new ArrayList<>();
@@ -156,6 +156,53 @@ public final class L2NpcTemplate extends L2CharTemplate
 		NONE
 	}
 	
+	/**
+	 * Constructor of L2Character.
+	 * @param set The StatsSet object to transfer data to the method
+	 */
+	public L2NpcTemplate(StatsSet set)
+	{
+		super(set);
+	}
+	
+	@Override
+	public void set(StatsSet set)
+	{
+		super.set(set);
+		_npcId = set.getInteger("npcId");
+		_idTemplate = set.getInteger("idTemplate");
+		_type = set.getString("type");
+		_name = set.getString("name");
+		_serverSideName = set.getBool("serverSideName");
+		_title = set.getString("title");
+		_isQuestMonster = getTitle().equalsIgnoreCase("Quest Monster");
+		_serverSideTitle = set.getBool("serverSideTitle");
+		_sex = set.getString("sex");
+		_level = set.getByte("level");
+		_rewardExp = set.getInteger("rewardExp");
+		_rewardSp = set.getInteger("rewardSp");
+		_rHand = set.getInteger("rhand");
+		_lHand = set.getInteger("lhand");
+		_enchantEffect = set.getInteger("enchant");
+		final int herbGroup = set.getInteger("dropHerbGroup");
+		if ((herbGroup > 0) && (HerbDropTable.getInstance().getHerbDroplist(herbGroup) == null))
+		{
+			_log.warning("Missing Herb Drop Group for npcId: " + getNpcId());
+			_dropHerbGroup = 0;
+		}
+		else
+		{
+			_dropHerbGroup = herbGroup;
+		}
+		
+		_clientClass = set.getString("client_class");
+		
+		// TODO: Could be loaded from db.
+		_baseVitalityDivider = (getLevel() > 0) && (getRewardExp() > 0) ? (getBaseHpMax() * 9 * getLevel() * getLevel()) / (100 * getRewardExp()) : 0;
+		
+		_isCustom = _npcId != _idTemplate;
+	}
+	
 	public static boolean isAssignableTo(Class<?> sub, Class<?> clazz)
 	{
 		// If clazz represents an interface
@@ -199,48 +246,6 @@ public final class L2NpcTemplate extends L2CharTemplate
 		return L2NpcTemplate.isAssignableTo(obj.getClass(), clazz);
 	}
 	
-	/**
-	 * Constructor of L2Character.
-	 * @param set The StatsSet object to transfer data to the method
-	 */
-	public L2NpcTemplate(StatsSet set)
-	{
-		super(set);
-		_npcId = set.getInteger("npcId");
-		_idTemplate = set.getInteger("idTemplate");
-		_type = set.getString("type");
-		_name = set.getString("name");
-		_serverSideName = set.getBool("serverSideName");
-		_title = set.getString("title");
-		_isQuestMonster = getTitle().equalsIgnoreCase("Quest Monster");
-		_serverSideTitle = set.getBool("serverSideTitle");
-		_sex = set.getString("sex");
-		_level = set.getByte("level");
-		_rewardExp = set.getInteger("rewardExp");
-		_rewardSp = set.getInteger("rewardSp");
-		_rHand = set.getInteger("rhand");
-		_lHand = set.getInteger("lhand");
-		_enchantEffect = set.getInteger("enchant");
-		_race = null;
-		final int herbGroup = set.getInteger("dropHerbGroup");
-		if ((herbGroup > 0) && (HerbDropTable.getInstance().getHerbDroplist(herbGroup) == null))
-		{
-			_log.warning("Missing Herb Drop Group for npcId: " + getNpcId());
-			_dropHerbGroup = 0;
-		}
-		else
-		{
-			_dropHerbGroup = herbGroup;
-		}
-		
-		_clientClass = set.getString("client_class");
-		
-		// TODO: Could be loaded from db.
-		_baseVitalityDivider = (getLevel() > 0) && (getRewardExp() > 0) ? (getBaseHpMax() * 9 * getLevel() * getLevel()) / (100 * getRewardExp()) : 0;
-		
-		_isCustom = _npcId != _idTemplate;
-	}
-	
 	public void addAtkSkill(L2Skill skill)
 	{
 		_atkSkills.add(skill);
@@ -736,10 +741,6 @@ public final class L2NpcTemplate extends L2CharTemplate
 	 */
 	public Race getRace()
 	{
-		if (_race == null)
-		{
-			_race = Race.NONE;
-		}
 		return _race;
 	}