Jelajahi Sumber

BETA: Implementing ability to plug any object to any L2Object:
* You could attach any object and retrieve it later when you need it, that would help a lot while creating some customs or even implementing retail like features without messing with L2PcInstance or L2Character.
* By default it comes with new implementation of !PlayerVariables which gives you ability to store any key,value for each player anywhere, anytime!
* !PlayerVariables is basically !StatsSet so u could use all of its features.
* Example usage of !PlayerVariables:
{{{
PlayerVariables vars = player.getScript(PlayerVariables.class);
if (vars == null)
{
vars = player.addScript(new PlayerVariables());
}
vars.set("some key name", "some value here");
}}}

* NOTE: '''Be careful when using addScript/getScript there is known issue with DP classes if you use same datapack class in two others to add/get it may result into Class Cast Exception because of ECJ (Eclipse Java Compiler) issues while compiling the code it recreates every class that's imported out of core, until its fixed avoid doing that'''.

Rumen Nikiforov 12 tahun lalu
induk
melakukan
c93530a4ba

+ 55 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/L2Object.java

@@ -18,6 +18,10 @@
  */
 package com.l2jserver.gameserver.model;
 
+import java.util.Map;
+
+import javolution.util.FastMap;
+
 import com.l2jserver.gameserver.handler.ActionHandler;
 import com.l2jserver.gameserver.handler.ActionShiftHandler;
 import com.l2jserver.gameserver.handler.IActionHandler;
@@ -54,6 +58,7 @@ public abstract class L2Object
 	private int _instanceId = 0;
 	
 	private InstanceType _instanceType = null;
+	private volatile Map<String, Object> _scripts;
 	
 	public L2Object(int objectId)
 	{
@@ -873,4 +878,54 @@ public abstract class L2Object
 	public void rechargeShots(boolean physical, boolean magical)
 	{
 	}
+	
+	/**
+	 * @param <T>
+	 * @param script
+	 * @return
+	 */
+	public final <T> T addScript(T script)
+	{
+		if (_scripts == null)
+		{
+			// Double-checked locking
+			synchronized (this)
+			{
+				if (_scripts == null)
+				{
+					_scripts = new FastMap<String, Object>().shared();
+				}
+			}
+		}
+		_scripts.put(script.getClass().getName(), script);
+		return script;
+	}
+	
+	/**
+	 * @param <T>
+	 * @param script
+	 */
+	public final <T> void removeScript(T script)
+	{
+		if (_scripts == null)
+		{
+			return;
+		}
+		_scripts.remove(script.getClass().getName());
+	}
+	
+	/**
+	 * @param <T>
+	 * @param script
+	 * @return
+	 */
+	@SuppressWarnings("unchecked")
+	public final <T> T getScript(Class<T> script)
+	{
+		if (_scripts == null)
+		{
+			return null;
+		}
+		return (T) _scripts.get(script.getName());
+	}
 }

+ 164 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/PlayerVariables.java

@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2004-2013 L2J DataPack
+ * 
+ * This file is part of L2J DataPack.
+ * 
+ * L2J DataPack is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J DataPack is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.gameserver.model;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * @author UnAfraid
+ */
+public class PlayerVariables extends StatsSet
+{
+	private static final Logger _log = Logger.getLogger(PlayerVariables.class.getName());
+	
+	// SQL Queries.
+	private static final String SELECT_QUERY = "SELECT * FROM character_variables WHERE charId = ?";
+	private static final String DELETE_QUERY = "DELETE FROM character_variables WHERE charId = ?";
+	private static final String INSERT_QUERY = "INSERT INTO character_variables (charId, var, val) VALUES (?, ?, ?)";
+	
+	private final int _objectId;
+	private final AtomicBoolean _hasChanges = new AtomicBoolean(false);
+	
+	public PlayerVariables(int objectId)
+	{
+		_objectId = objectId;
+		load();
+	}
+	
+	private void load()
+	{
+		// Restore previous variables.
+		try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement st = con.prepareStatement(SELECT_QUERY))
+		{
+			st.setInt(1, _objectId);
+			try (ResultSet rset = st.executeQuery())
+			{
+				while (rset.next())
+				{
+					super.set(rset.getString("var"), rset.getString("val"));
+				}
+			}
+		}
+		catch (SQLException e)
+		{
+			_log.log(Level.WARNING, getClass().getSimpleName() + ": Couldn't restore variables for: " + getPlayer(), e);
+		}
+	}
+	
+	public void store()
+	{
+		// No changes, nothing to store.
+		if (!_hasChanges.get())
+		{
+			return;
+		}
+		
+		try (Connection con = L2DatabaseFactory.getInstance().getConnection())
+		{
+			// Clear previous entries.
+			try (PreparedStatement st = con.prepareStatement(DELETE_QUERY))
+			{
+				st.setInt(1, _objectId);
+				st.execute();
+			}
+			
+			// Insert all variables.
+			try (PreparedStatement st = con.prepareStatement(INSERT_QUERY))
+			{
+				st.setInt(1, _objectId);
+				for (Entry<String, Object> entry : getSet().entrySet())
+				{
+					st.setString(2, entry.getKey());
+					st.setObject(3, entry.getValue());
+					st.execute();
+				}
+			}
+		}
+		catch (SQLException e)
+		{
+			_log.log(Level.WARNING, getClass().getSimpleName() + ": Couldn't update variables for: " + getPlayer(), e);
+		}
+		finally
+		{
+			_hasChanges.compareAndSet(true, false);
+		}
+	}
+	
+	/**
+	 * Overriding following methods to prevent from doing useless database operations if there is no changes since player's login.
+	 */
+	
+	@Override
+	public void set(String name, boolean value)
+	{
+		_hasChanges.compareAndSet(false, true);
+		super.set(name, value);
+	}
+	
+	@Override
+	public void set(String name, double value)
+	{
+		_hasChanges.compareAndSet(false, true);
+		super.set(name, value);
+	}
+	
+	@Override
+	public void set(String name, Enum<?> value)
+	{
+		_hasChanges.compareAndSet(false, true);
+		super.set(name, value);
+	}
+	
+	@Override
+	public void set(String name, int value)
+	{
+		_hasChanges.compareAndSet(false, true);
+		super.set(name, value);
+	}
+	
+	@Override
+	public void set(String name, long value)
+	{
+		_hasChanges.compareAndSet(false, true);
+		super.set(name, value);
+	}
+	
+	@Override
+	public void set(String name, String value)
+	{
+		_hasChanges.compareAndSet(false, true);
+		super.set(name, value);
+	}
+	
+	public L2PcInstance getPlayer()
+	{
+		return L2World.getInstance().getPlayer(_objectId);
+	}
+}

+ 1 - 1
L2J_Server_BETA/java/com/l2jserver/gameserver/model/StatsSet.java

@@ -32,7 +32,7 @@ import javolution.util.FastMap;
  *         This class is used in order to have a set of couples (key,value).<BR>
  *         Methods deployed are accessors to the set (add/get value from its key) and addition of a whole set in the current one.
  */
-public final class StatsSet
+public class StatsSet
 {
 	private static final Logger _log = Logger.getLogger(StatsSet.class.getName());
 	private final Map<String, Object> _set;

+ 7 - 0
L2J_Server_BETA/java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java

@@ -131,6 +131,7 @@ import com.l2jserver.gameserver.model.PartyMatchRoom;
 import com.l2jserver.gameserver.model.PartyMatchRoomList;
 import com.l2jserver.gameserver.model.PartyMatchWaitingList;
 import com.l2jserver.gameserver.model.PcCondOverride;
+import com.l2jserver.gameserver.model.PlayerVariables;
 import com.l2jserver.gameserver.model.ShortCuts;
 import com.l2jserver.gameserver.model.ShotType;
 import com.l2jserver.gameserver.model.TerritoryWard;
@@ -8186,6 +8187,12 @@ public final class L2PcInstance extends L2Playable
 			storeUISettings();
 		}
 		SevenSigns.getInstance().saveSevenSignsData(getObjectId());
+		
+		final PlayerVariables vars = getScript(PlayerVariables.class);
+		if (vars != null)
+		{
+			vars.store();
+		}
 	}
 	
 	@Override