Noticias:

No tienes permiso para ver los enlaces. Para poder verlos Registrate o Conectate.

Menú Principal

Community Board Rank Engine

Iniciado por Swarlog, Jul 29, 2025, 12:00 AM

Tema anterior - Siguiente tema

Swarlog

CitarCORE:

### Eclipse Workspace Patch 1.0
#P L2J_SunriseProject_Core
Index: dist/game/config/extra/elemental/ranking.ini
===================================================================
--- dist/game/config/extra/elemental/ranking.ini	(revision 0)
+++ dist/game/config/extra/elemental/ranking.ini	(working copy)
@@ -0,0 +1,27 @@
+# ---------------------------------------------------------------------------
+# Database Configs. Copy from Server configs
+# ---------------------------------------------------------------------------
+
+# Specify the appropriate driver and url for the database you're using.
+Driver = com.mysql.jdbc.Driver
+
+# Database URL
+URL = jdbc:mysql://localhost/l2jgs
+
+# Database user info (default is "root" but it's not recommended)
+Login = root
+
+# Database connection password
+Password = 
+
+# Default: 100
+MaximumDbConnections = 100
+
+# Default: 0
+MaximumDbIdleTime = 0
+
+# Datapack root directory.
+# Defaults to current directory from which the server is started unless the below line is uncommented.
+# WARNING: <u><b><font color="red">If the specified path is invalid, it will lead to multiple errors!</font></b></u>
+#Default: .
+DatapackRoot = .
\ No newline at end of file
Index: java/gr/sr/rankEngine/datatables/ranking/ServerRanking.java
===================================================================
--- java/gr/sr/rankEngine/datatables/ranking/ServerRanking.java	(revision 0)
+++ java/gr/sr/rankEngine/datatables/ranking/ServerRanking.java	(working copy)
@@ -0,0 +1,537 @@
+package gr.sr.rankEngine.datatables.ranking;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+import l2r.L2DatabaseFactory;
+import l2r.gameserver.ThreadPoolManager;
+import l2r.util.Files;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import gr.sr.rankEngine.clan.ClanStats;
+import gr.sr.rankEngine.datatables.TranslationMessagesTable;
+import gr.sr.rankEngine.datatables.character.CharacterMonthlyRanking;
+import gr.sr.rankEngine.enums.RankTime;
+import gr.sr.rankEngine.pc.PcStats;
+import gr.sr.rankEngine.templates.RankingHolder;
+
+public final class ServerRanking
+{
+	protected static final Logger _log = LoggerFactory.getLogger(ServerRanking.class);
+	private static final DecimalFormat _format = new DecimalFormat("#,##0");
+	public static final boolean NO_POINTS = false;
+	public static final boolean SHOW_POINTS = true;
+	public static final boolean ORDER_ASC = false;
+	public static final boolean ORDER_DESC = true;
+	public static final boolean STAT_UNIQUE = false;
+	public static final boolean STAT_STACKABLE = true;
+	protected final Map<Integer, RankingTop> _rankingStats = new ConcurrentHashMap<>();
+	private final Map<String, List<Integer>> _rankCategories = new TreeMap<>();
+	private static String serverRankingHtml = "data/html/CommunityBoard/elemental/ranking/serverRanking.htm";
+	private static String playerRankingHtml = "data/html/CommunityBoard/elemental/ranking/playerRanking.htm";
+	
+	protected ServerRanking()
+	{
+		RankingHolder.generateRankings(_rankingStats);
+		load();
+		ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new ReloadStatsFromDB(), 3600000L, 3600000L);
+	}
+	
+	private void load()
+	{
+		_rankCategories.clear();
+		
+		try (final Connection connection = L2DatabaseFactory.getInstance().getConnection())
+		{
+			for (final RankingTop rankingTop : _rankingStats.values())
+			{
+				String s;
+				rankingTop.cleanPlayers();
+				final String dbLocation = rankingTop.getDbLocation();
+				switch (dbLocation)
+				{
+					case "characters":
+					{
+						s = "SELECT char_name," + rankingTop.getDbName() + " FROM characters WHERE level>=40 AND accesslevel=0 ORDER BY " + rankingTop.getDbName() + (rankingTop.isDescendent() ? " DESC" : " ASC") + " LIMIT 10";
+						break;
+					}
+					case "clan_stats":
+					{
+						s = "SELECT t1.clan_name,t2.value FROM clan_data AS t1 INNER JOIN clan_stats AS t2 INNER JOIN characters AS t3 WHERE t3.accesslevel=0 AND t1.clan_id=t2.clanId AND t2.variable='" + rankingTop.getDbName() + "' AND t1.leader_id=t3.charId " + "ORDER BY t2.value " + (rankingTop.isDescendent() ? "DESC" : "ASC") + " LIMIT 10";
+						break;
+					}
+					default:
+					{
+						s = "SELECT t1.char_name,t2.value FROM characters AS t1 INNER JOIN " + rankingTop.getDbLocation() + " AS t2 " + "WHERE t1.level>=40 AND t1.accesslevel=0 AND t1.charId=t2.charId AND t2.variable='" + rankingTop.getDbName() + "' ORDER BY t2.value " + (rankingTop.isDescendent() ? "DESC" : "ASC") + " LIMIT 10";
+						break;
+					}
+				}
+				
+				try (final PreparedStatement prepareStatement = connection.prepareStatement(s);
+					final ResultSet executeQuery = prepareStatement.executeQuery())
+				{
+					while (executeQuery.next())
+					{
+						final String dbLocation2 = rankingTop.getDbLocation();
+						switch (dbLocation2)
+						{
+							case "characters":
+							{
+								rankingTop.addPlayer(new RankingTopMember(executeQuery.getString("char_name"), executeQuery.getLong(rankingTop.getDbName())));
+								continue;
+							}
+							case "clan_stats":
+							{
+								rankingTop.addPlayer(new RankingTopMember(executeQuery.getString("clan_name"), executeQuery.getLong("value")));
+								continue;
+							}
+							default:
+							{
+								rankingTop.addPlayer(new RankingTopMember(executeQuery.getString("char_name"), executeQuery.getLong("value")));
+								continue;
+							}
+						}
+					}
+				}
+			}
+			_log.info(getClass().getSimpleName() + ": Loaded " + _rankingStats.size() + " statics categories for the ranking");
+		}
+		catch (SQLException ex)
+		{
+			_log.warn(getClass().getSimpleName() + ": Error while loading rankings:" + ex);
+		}
+		
+		for (final RankingTop rankingTop2 : _rankingStats.values())
+		{
+			if (!_rankCategories.containsKey(rankingTop2.getCategory(null)))
+			{
+				_rankCategories.put(rankingTop2.getCategory(null), new ArrayList<Integer>());
+			}
+			_rankCategories.get(rankingTop2.getCategory(null)).add(rankingTop2.getTopId());
+		}
+		final Iterator<List<Integer>> iterator3 = _rankCategories.values().iterator();
+		while (iterator3.hasNext())
+		{
+			Collections.sort(iterator3.next(), (n, n2) -> _rankingStats.get(n).getTopName(null).compareTo(_rankingStats.get(n2).getTopName(null)));
+		}
+	}
+	
+	public RankingTop getRankingById(int var1)
+	{
+		return _rankingStats.get(Integer.valueOf(var1));
+	}
+	
+	public Map<Integer, RankingTop> getAllRankings()
+	{
+		return _rankingStats;
+	}
+	
+	public Map<String, List<Integer>> getRankingsByCategory()
+	{
+		return _rankCategories;
+	}
+	
+	public final String makeServerRankingHtm(final int n, final String s)
+	{
+		String content = getServerRankingHtml();
+		if (content == null)
+		{
+			return "<html><body><br><br><center>Server Ranking Html is missing!!!!!</center></body></html>";
+		}
+		
+		final RankingTop rankingById = getRankingById(n);
+		final RankingTop rankingById2 = CharacterMonthlyRanking.getInstance().getRankingById(n);
+		int i = 1;
+		for (final RankingTopMember rankingTopMember : rankingById2.getPlayers())
+		{
+			if (rankingById2.isDescendent() && (rankingTopMember.getPoints() < 1L))
+			{
+				break;
+			}
+			final String replace = content.replace("%mNombre" + i + "%", rankingTopMember.getCharName());
+			if (rankingById2.mustShowPoints())
+			{
+				content = replace.replace("%mCantidad" + i + "%", getTime(rankingById2.getTime(), rankingTopMember.getPoints()));
+			}
+			else
+			{
+				content = replace.replace("%mCantidad" + i + "%", "");
+			}
+			if (++i > 10)
+			{
+				break;
+			}
+		}
+		while (i < 11)
+		{
+			final String replace2 = content.replace("%mNombre" + i + "%", "None");
+			if (rankingById2.mustShowPoints())
+			{
+				content = replace2.replace("%mCantidad" + i + "%", "0");
+			}
+			else
+			{
+				content = replace2.replace("%mCantidad" + i + "%", "");
+			}
+			++i;
+		}
+		int j = 1;
+		for (final RankingTopMember rankingTopMember2 : rankingById.getPlayers())
+		{
+			if (rankingById.isDescendent() && (rankingTopMember2.getPoints() < 1L))
+			{
+				break;
+			}
+			final String replace3 = content.replace("%tNombre" + j + "%", rankingTopMember2.getCharName());
+			if (rankingById.mustShowPoints())
+			{
+				content = replace3.replace("%tCantidad" + j + "%", getTime(rankingById.getTime(), rankingTopMember2.getPoints()));
+			}
+			else
+			{
+				content = replace3.replace("%tCantidad" + j + "%", "");
+			}
+			if (++j > 10)
+			{
+				break;
+			}
+		}
+		while (j < 11)
+		{
+			final String replace4 = content.replace("%tNombre" + j + "%", "None");
+			if (rankingById.mustShowPoints())
+			{
+				content = replace4.replace("%tCantidad" + j + "%", "0");
+			}
+			else
+			{
+				content = replace4.replace("%tCantidad" + j + "%", "");
+			}
+			++j;
+		}
+		final String replace5 = content.replace("%rank_tab_server_record%", TranslationMessagesTable.getInstance().getMessage(s, "rank_tab_server_record")).replace("%rank_tab_my_record%", TranslationMessagesTable.getInstance().getMessage(s, "rank_tab_my_record")).replace("%rank_tab_monthly_ranking%", TranslationMessagesTable.getInstance().getMessage(s, "rank_tab_monthly_ranking")).replace("%rank_tab_total_ranking%", TranslationMessagesTable.getInstance().getMessage(s, "rank_tab_total_ranking"));
+		final StringBuilder sb = new StringBuilder();
+		int k = 1;
+		for (final Map.Entry<String, List<Integer>> entry : getRankingsByCategory().entrySet())
+		{
+			if (entry.getKey().equalsIgnoreCase(rankingById.getCategory(null)))
+			{
+				sb.append("<table width=260 cellspacing=-2>");
+				sb.append("<tr><td width=6></td><td><button value=\"" + TranslationMessagesTable.getInstance().getMessage(s, entry.getKey()) + "\" width=258 height=32 action=\"\" fore=L2UI_CT1.Button_DF_Calculator_Down back=L2UI_CT1.Button_DF_Calculator_Down></td></tr>");
+				sb.append(" </table>");
+				sb.append("<table width=260 height=360 cellspacing=-1>");
+				for (final Integer n2 : entry.getValue())
+				{
+					if (n2 == n)
+					{
+						sb.append("<tr><td align=center height=25><button value=\"" + getRankingById(n2).getTopName(s) + "\" width=255 height=25 action=\"\" fore=L2UI_CH3.chatting_system back=L2UI_CH3.chatting_system></td></tr>");
+					}
+					else
+					{
+						sb.append("<tr><td align=center height=25><button value=\"" + getRankingById(n2).getTopName(s) + "\" width=255 height=25 action=\"bypass _bbsrank;server;" + n2 + "\" fore=L2UI_CT1.ChatBalloon_DF_MiddleCenter back=L2UI_CT1.ChatBalloon_DF_MiddleCenter></td></tr>");
+					}
+					++k;
+				}
+				while (k < 16)
+				{
+					sb.append("<tr><td align=center height=25><button value=\"\" width=255 height=25 action=\"\" fore=L2UI_CT1.ChatBalloon_DF_MiddleCenter back=L2UI_CT1.ChatBalloon_DF_MiddleCenter></td></tr>");
+					++k;
+				}
+				sb.append("</table>");
+			}
+			else
+			{
+				sb.append("<table width=260 cellspacing=-3>");
+				sb.append("<tr><td width=7></td><td><button value=\"" + TranslationMessagesTable.getInstance().getMessage(s, entry.getKey()) + "\" width=260 height=24 action=\"bypass _bbsrank;server;" + entry.getValue().get(0) + "\" fore=L2UI_CT1.Button_DF back=L2UI_CT1.Button_DF_Calculator_Down></td></tr>");
+				sb.append("</table>");
+			}
+		}
+		return replace5.replace("%categorias%", sb.toString());
+	}
+	
+	public final String makeSelfRankingHtm(final PcStats pcStats, final ClanStats clanStats, final int n, final String s)
+	{
+		String content = getPlayerRankingHtml();
+		if (content == null)
+		{
+			return "<html><body><br><br><center>Player Ranking Html is missing!!!!!</center></body></html>";
+		}
+		
+		final RankingTop rankingById = getRankingById(n);
+		final String replace = content.replace("%rank_tab_server_record%", TranslationMessagesTable.getInstance().getMessage(s, "rank_tab_server_record")).replace("%rank_tab_my_record%", TranslationMessagesTable.getInstance().getMessage(s, "rank_tab_my_record")).replace("%rank_tab_category%", TranslationMessagesTable.getInstance().getMessage(s, "rank_tab_category")).replace("%rank_tab_monthly_total%", TranslationMessagesTable.getInstance().getMessage(s, "rank_tab_monthly_total")).replace("%rank_tab_total%", TranslationMessagesTable.getInstance().getMessage(s, "rank_tab_total"));
+		final StringBuilder sb = new StringBuilder();
+		final StringBuilder sb2 = new StringBuilder();
+		boolean b = false;
+		for (final Map.Entry<String, List<Integer>> entry : getRankingsByCategory().entrySet())
+		{
+			if (entry.getKey().equalsIgnoreCase(rankingById.getCategory(null)))
+			{
+				sb.append("<tr><td width=15></td><td><button value=\"" + TranslationMessagesTable.getInstance().getMessage(s, entry.getKey()) + "\" width=150 height=40 action=\"\" fore=L2UI_CT1.Button_DF_Calculator_Over back=L2UI_CT1.Button_DF_Calculator_Over></td></tr>");
+				for (final Integer n2 : entry.getValue())
+				{
+					final RankingTop rankingById2 = getRankingById(n2);
+					sb2.append("<table width=598 height=26 cellpadding=-2 bgcolor=" + (b ? "171612" : "23221e") + ">");
+					sb2.append("<tr>");
+					sb2.append("<td fixwidth=240 align=center>" + rankingById2.getTopName(s) + "</td>");
+					sb2.append("<td fixwidth=180 align=center>" + getTime(rankingById2.getTime(), CharacterMonthlyRanking.getInstance().getPlayerStats((rankingById2.isClanStat() && (clanStats != null)) ? clanStats.getClanId() : pcStats.getOwnerId(), n2)) + "</td>");
+					sb2.append("<td fixwidth=180 align=center>" + getTime(rankingById2.getTime(), (rankingById2.isClanStat() && (clanStats != null)) ? clanStats.getClanStats(n2) : pcStats.getPlayerStats(n2)) + "</td>");
+					sb2.append("</tr>");
+					sb2.append("</table>");
+					b = !b;
+				}
+			}
+			else
+			{
+				sb.append("<tr><td width=15></td><td><button value=\"" + TranslationMessagesTable.getInstance().getMessage(s, entry.getKey()) + "\" width=150 height=40 action=\"bypass _bbsrank;my;" + entry.getValue().get(0) + "\" fore=L2UI_CT1.Button_DF back=L2UI_CT1.Button_DF_Calculator_Down></td></tr>");
+			}
+		}
+		return replace.replace("%categorias%", sb.toString()).replace("%tablas%", sb2.toString());
+	}
+	
+	private String getTime(RankTime var1, long var2)
+	{
+		switch (var1.ordinal())
+		{
+			case 1:
+				var2 /= 60000L;
+				break;
+			case 2:
+				var2 /= 60L;
+			case 3:
+				break;
+			case 4:
+				var2 *= 60L;
+				break;
+			case 5:
+			default:
+				return _format.format(var2).replace(".", ",");
+		}
+		
+		return var2 > 1000L ? _format.format(((int) (var2 / 60L))).replace(".", ",") + " Hour(s)" : _format.format(var2).replace(".", ",") + " Minute(s)";
+	}
+	
+	public final void shutdown()
+	{
+		ThreadPoolManager.getInstance().shutdown();
+		CharacterMonthlyRanking.getInstance().saveMonthlyStats();
+	}
+	
+	public static class RankingTopMember
+	{
+		public long _points = 0L;
+		private String _topMemberName = "";
+		
+		public RankingTopMember(String name, long points)
+		{
+			_topMemberName = name;
+			_points = points;
+		}
+		
+		public String getCharName()
+		{
+			return _topMemberName;
+		}
+		
+		public long getPoints()
+		{
+			return _points;
+		}
+	}
+	
+	public static class RankingTop
+	{
+		private final int _topId;
+		private final String _topName;
+		private final String _category;
+		private final String _dbName;
+		private final boolean _showPoints;
+		private final String _dbLocation;
+		private final boolean _isDescendent;
+		private final boolean _isStackable;
+		private final RankTime _time;
+		private final ArrayList<RankingTopMember> _players = new ArrayList<>();
+		
+		public RankingTop(int topId, String topName, String category, String dbName, boolean showPoints, String dbLocation, boolean isDescendent, boolean isStackable, RankTime time)
+		{
+			_topId = topId;
+			_topName = topName;
+			_category = category;
+			_dbName = dbName;
+			_showPoints = showPoints;
+			_dbLocation = dbLocation;
+			_isDescendent = isDescendent;
+			_isStackable = isStackable;
+			_time = time;
+		}
+		
+		public void addPlayer(RankingTopMember player)
+		{
+			_players.add(player);
+		}
+		
+		public void cleanPlayers()
+		{
+			_players.clear();
+		}
+		
+		public int getTopId()
+		{
+			return _topId;
+		}
+		
+		public String getTopName(String var1)
+		{
+			return TranslationMessagesTable.getInstance().getMessage(var1, _topName);
+		}
+		
+		public String getCategory(String var1)
+		{
+			return TranslationMessagesTable.getInstance().getMessage(var1, _category);
+		}
+		
+		public String getDbName()
+		{
+			return _dbName;
+		}
+		
+		public boolean mustShowPoints()
+		{
+			return _showPoints;
+		}
+		
+		public String getDbLocation()
+		{
+			return _dbLocation;
+		}
+		
+		public boolean isDescendent()
+		{
+			return _isDescendent;
+		}
+		
+		public boolean isStackable()
+		{
+			return _isStackable;
+		}
+		
+		public boolean isClanStat()
+		{
+			return getDbLocation().equalsIgnoreCase("clan_stats");
+		}
+		
+		public RankTime getTime()
+		{
+			return _time;
+		}
+		
+		public ArrayList<ServerRanking.RankingTopMember> getPlayers()
+		{
+			return _players;
+		}
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final ServerRanking _instance = new ServerRanking();
+		
+		private SingletonHolder()
+		{
+		}
+	}
+	
+	protected class ReloadStatsFromDB implements Runnable
+	{
+		@Override
+		public void run()
+		{
+			synchronized (_rankingStats)
+			{
+				try (final Connection connection = L2DatabaseFactory.getInstance().getConnection())
+				{
+					for (final RankingTop rankingTop : _rankingStats.values())
+					{
+						String s;
+						rankingTop.cleanPlayers();
+						final String dbLocation = rankingTop.getDbLocation();
+						switch (dbLocation)
+						{
+							case "characters":
+							{
+								s = "SELECT char_name," + rankingTop.getDbName() + " FROM characters WHERE level>=40 AND accesslevel=0 ORDER BY " + rankingTop.getDbName() + (rankingTop.isDescendent() ? " DESC" : " ASC") + " LIMIT 10";
+								break;
+							}
+							case "clan_stats":
+							{
+								s = "SELECT t1.clan_name,t2.value FROM clan_data AS t1 INNER JOIN clan_stats AS t2 INNER JOIN characters AS t3 WHERE t3.accesslevel=0 AND t1.clan_id=t2.clanId AND t2.variable='" + rankingTop.getDbName() + "' AND t1.leader_id=t3.charId " + "ORDER BY t2.value " + (rankingTop.isDescendent() ? "DESC" : "ASC") + " LIMIT 10";
+								break;
+							}
+							default:
+							{
+								s = "SELECT t1.char_name,t2.value FROM characters AS t1 INNER JOIN " + rankingTop.getDbLocation() + " AS t2 " + "WHERE t1.level>=40 AND t1.accesslevel=0 AND t1.charId=t2.charId AND t2.variable='" + rankingTop.getDbName() + "' ORDER BY t2.value " + (rankingTop.isDescendent() ? "DESC" : "ASC") + " LIMIT 10";
+								break;
+							}
+						}
+						
+						try (final PreparedStatement prepareStatement = connection.prepareStatement(s);
+							final ResultSet executeQuery = prepareStatement.executeQuery())
+						{
+							while (executeQuery.next())
+							{
+								final String dbLocation2 = rankingTop.getDbLocation();
+								switch (dbLocation2)
+								{
+									case "characters":
+									{
+										rankingTop.addPlayer(new RankingTopMember(executeQuery.getString("char_name"), executeQuery.getLong(rankingTop.getDbName())));
+										continue;
+									}
+									case "clan_stats":
+									{
+										rankingTop.addPlayer(new RankingTopMember(executeQuery.getString("clan_name"), executeQuery.getLong("value")));
+										continue;
+									}
+									default:
+									{
+										rankingTop.addPlayer(new RankingTopMember(executeQuery.getString("char_name"), executeQuery.getLong("value")));
+										continue;
+									}
+								}
+							}
+						}
+					}
+				}
+				catch (SQLException ex)
+				{
+					ex.printStackTrace();
+				}
+			}
+		}
+	}
+	
+	public final String getServerRankingHtml()
+	{
+		return Files.read(serverRankingHtml);
+	}
+	
+	public final String getPlayerRankingHtml()
+	{
+		return Files.read(playerRankingHtml);
+	}
+	
+	public static ServerRanking getInstance()
+	{
+		return ServerRanking.SingletonHolder._instance;
+	}
+}
Index: java/gr/sr/rankEngine/general/ThreadPoolManager.java
===================================================================
--- java/gr/sr/rankEngine/general/ThreadPoolManager.java	(revision 0)
+++ java/gr/sr/rankEngine/general/ThreadPoolManager.java	(working copy)
@@ -0,0 +1,164 @@
+package gr.sr.rankEngine.general;
+
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.RunnableScheduledFuture;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import l2r.Config;
+
+public class ThreadPoolManager
+{
+	protected static Logger _log = Logger.getLogger(ThreadPoolManager.class.getName());
+	protected ScheduledThreadPoolExecutor _generalScheduledThreadPool;
+	
+	protected ThreadPoolManager()
+	{
+		_generalScheduledThreadPool = new ScheduledThreadPoolExecutor(Config.THREAD_P_GENERAL, new PriorityThreadFactory("GeneralSTPool", Thread.NORM_PRIORITY));
+		scheduleGeneralAtFixedRate(new PurgeTask(), 600000L, 300000L);
+	}
+	
+	public static long validateDelay(long paramLong)
+	{
+		if (paramLong < 0L)
+		{
+			paramLong = 0L;
+		}
+		else if (paramLong > 4611686018427L)
+		{
+			paramLong = 4611686018427L;
+		}
+		return paramLong;
+	}
+	
+	public ScheduledFuture<?> scheduleGeneral(Runnable paramRunnable, long paramLong)
+	{
+		try
+		{
+			paramLong = validateDelay(paramLong);
+			return _generalScheduledThreadPool.schedule(new RunnableWrapper(paramRunnable), paramLong, TimeUnit.MILLISECONDS);
+		}
+		catch (RejectedExecutionException localRejectedExecutionException)
+		{
+		}
+		return null;
+	}
+	
+	public ScheduledFuture<?> scheduleGeneralAtFixedRate(Runnable paramRunnable, long paramLong1, long paramLong2)
+	{
+		try
+		{
+			paramLong2 = validateDelay(paramLong2);
+			paramLong1 = validateDelay(paramLong1);
+			return _generalScheduledThreadPool.scheduleAtFixedRate(new RunnableWrapper(paramRunnable), paramLong1, paramLong2, TimeUnit.MILLISECONDS);
+		}
+		catch (RejectedExecutionException localRejectedExecutionException)
+		{
+		}
+		return null;
+	}
+	
+	public boolean removeGeneral(RunnableScheduledFuture<?> paramRunnableScheduledFuture)
+	{
+		return _generalScheduledThreadPool.remove(paramRunnableScheduledFuture);
+	}
+	
+	public boolean removeGeneral(Runnable paramRunnable)
+	{
+		return _generalScheduledThreadPool.remove(paramRunnable);
+	}
+	
+	public void shutdown()
+	{
+		try
+		{
+			_generalScheduledThreadPool.awaitTermination(1L, TimeUnit.SECONDS);
+			_generalScheduledThreadPool.shutdown();
+		}
+		catch (InterruptedException localInterruptedException)
+		{
+			_log.log(Level.WARNING, "", localInterruptedException);
+		}
+	}
+	
+	public static ThreadPoolManager getInstance()
+	{
+		return SingletonHolder.a;
+	}
+	
+	static
+	{
+		_log = Logger.getLogger(ThreadPoolManager.class.getName());
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final ThreadPoolManager a = new ThreadPoolManager();
+	}
+	
+	protected class PurgeTask implements Runnable
+	{
+		@Override
+		public void run()
+		{
+			_generalScheduledThreadPool.purge();
+		}
+	}
+	
+	private static class PriorityThreadFactory implements ThreadFactory
+	{
+		private final int jdField_a_of_type_Int;
+		private final String jdField_a_of_type_JavaLangString;
+		private final AtomicInteger jdField_a_of_type_JavaUtilConcurrentAtomicAtomicInteger = new AtomicInteger(1);
+		private final ThreadGroup jdField_a_of_type_JavaLangThreadGroup;
+		
+		public PriorityThreadFactory(String paramString, int paramInt)
+		{
+			jdField_a_of_type_Int = paramInt;
+			jdField_a_of_type_JavaLangString = paramString;
+			jdField_a_of_type_JavaLangThreadGroup = new ThreadGroup(jdField_a_of_type_JavaLangString);
+		}
+		
+		@Override
+		public Thread newThread(Runnable paramRunnable)
+		{
+			Thread localThread = new Thread(jdField_a_of_type_JavaLangThreadGroup, paramRunnable);
+			localThread.setName(jdField_a_of_type_JavaLangString + "-" + jdField_a_of_type_JavaUtilConcurrentAtomicAtomicInteger.getAndIncrement());
+			localThread.setPriority(jdField_a_of_type_Int);
+			return localThread;
+		}
+	}
+	
+	private static final class RunnableWrapper implements Runnable
+	{
+		private final Runnable a;
+		
+		public RunnableWrapper(Runnable paramRunnable)
+		{
+			a = paramRunnable;
+		}
+		
+		@Override
+		public final void run()
+		{
+			try
+			{
+				a.run();
+			}
+			catch (Throwable localThrowable)
+			{
+				Thread localThread = Thread.currentThread();
+				Thread.UncaughtExceptionHandler localUncaughtExceptionHandler = localThread.getUncaughtExceptionHandler();
+				if (localUncaughtExceptionHandler != null)
+				{
+					localUncaughtExceptionHandler.uncaughtException(localThread, localThrowable);
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
Index: java/l2r/gameserver/network/clientpackets/RequestEnchantItem.java
===================================================================
--- java/l2r/gameserver/network/clientpackets/RequestEnchantItem.java	(revision 122)
+++ java/l2r/gameserver/network/clientpackets/RequestEnchantItem.java	(working copy)
@@ -43,6 +43,7 @@
 import l2r.gameserver.network.serverpackets.SystemMessage;
 import l2r.gameserver.util.Util;
 import gr.sr.antibotEngine.AntibotSystem;
+import gr.sr.rankEngine.templates.Ranking;
 
 public final class RequestEnchantItem extends L2GameClientPacket
 {
@@ -218,6 +219,12 @@
 				}
 				case SUCCESS:
 				{
+					// Synerge - Add a enchant succesful to the stats
+					if (scrollTemplate.getChance(activeChar, item) < 100)
+					{
+						activeChar.addPlayerStats(Ranking.STAT_TOP_ENCHANTS_SUCCEED);
+					}
+					
 					L2Skill enchant4Skill = null;
 					L2Item it = item.getItem();
 					// Increase enchant level only if scroll's base template has chance, some armors can success over +20 but they shouldn't have increased.
@@ -276,6 +283,12 @@
 				}
 				case FAILURE:
 				{
+					// Synerge - Add a failed enchant to the stats
+					if (scrollTemplate.getChance(activeChar, item) < 100)
+					{
+						activeChar.addPlayerStats(Ranking.STAT_TOP_ENCHANTS_FAILED);
+					}
+					
 					if (scrollTemplate.isSafe())
 					{
 						// safe enchant - remain old value
Index: java/gr/sr/rankEngine/datatables/TranslationMessagesTable.java
===================================================================
--- java/gr/sr/rankEngine/datatables/TranslationMessagesTable.java	(revision 0)
+++ java/gr/sr/rankEngine/datatables/TranslationMessagesTable.java	(working copy)
@@ -0,0 +1,132 @@
+package gr.sr.rankEngine.datatables;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import l2r.Config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Node;
+
+import gr.sr.rankEngine.filter.XMLFilter;
+
+public class TranslationMessagesTable
+{
+	private static final Logger _log = LoggerFactory.getLogger(TranslationMessagesTable.class.getName());
+	private final Map<String, TranslationMessage> languages = new HashMap<>();
+	
+	protected TranslationMessagesTable()
+	{
+		load();
+	}
+	
+	public void reload()
+	{
+		languages.clear();
+		load();
+	}
+	
+	public void load()
+	{
+		final File[] listFiles = new File(Config.DATAPACK_ROOT, "data/translation/").listFiles(new XMLFilter());
+		for (File listFile : listFiles)
+		{
+			parseTranslationFile(listFile);
+		}
+		_log.info(getClass().getSimpleName() + ": Loaded " + languages.size() + " translation messages");
+	}
+	
+	public void parseTranslationFile(File file)
+	{
+		try
+		{
+			final DocumentBuilderFactory instance = DocumentBuilderFactory.newInstance();
+			instance.setValidating(false);
+			instance.setIgnoringComments(true);
+			for (Node node = instance.newDocumentBuilder().parse(file).getFirstChild(); node != null; node = node.getNextSibling())
+			{
+				if ("list".equalsIgnoreCase(node.getNodeName()))
+				{
+					for (Node node2 = node.getFirstChild(); node2 != null; node2 = node2.getNextSibling())
+					{
+						if ("message".equalsIgnoreCase(node2.getNodeName()))
+						{
+							final String nodeValue = node2.getAttributes().getNamedItem("id").getNodeValue();
+							final TranslationMessage translationMessage = new TranslationMessage(nodeValue);
+							for (Node node3 = node2.getFirstChild(); node3 != null; node3 = node3.getNextSibling())
+							{
+								if ("set".equalsIgnoreCase(node3.getNodeName()))
+								{
+									translationMessage.addNewMessage(node3.getAttributes().getNamedItem("lang").getNodeValue(), node3.getAttributes().getNamedItem("val").getNodeValue());
+								}
+							}
+							languages.put(nodeValue, translationMessage);
+						}
+					}
+				}
+			}
+		}
+		catch (IOException ex)
+		{
+			_log.warn(getClass().getSimpleName() + ": can not find " + file.getAbsolutePath() + " ! " + ex.getMessage(), ex);
+		}
+		catch (Exception ex2)
+		{
+			_log.warn(getClass().getSimpleName() + ": error while loading " + file.getAbsolutePath() + " ! " + ex2.getMessage(), ex2);
+		}
+	}
+	
+	public String getMessage(String string1, String string2)
+	{
+		if ((string1 == null) || (!languages.containsKey(string2)))
+		{
+			return string2;
+		}
+		if (languages.get(string2).getMessageByLang(string1) != null)
+		{
+			return languages.get(string2).getMessageByLang(string1);
+		}
+		return languages.get(string2).getMessageByLang("en");
+	}
+	
+	public static TranslationMessagesTable getInstance()
+	{
+		return SingletonHolder._instance;
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final TranslationMessagesTable _instance = new TranslationMessagesTable();
+	}
+	
+	public class TranslationMessage
+	{
+		private final String _translationId;
+		private final Map<String, String> languages = new HashMap<>();
+		
+		public TranslationMessage(String translationId)
+		{
+			_translationId = translationId;
+		}
+		
+		public void addNewMessage(String paramString1, String paramString2)
+		{
+			languages.put(paramString1, paramString2);
+		}
+		
+		public String getTranslationId()
+		{
+			return _translationId;
+		}
+		
+		public String getMessageByLang(String paramString)
+		{
+			return languages.get(paramString);
+		}
+	}
+}
\ No newline at end of file
Index: java/gr/sr/rankEngine/general/RankingConfig.java
===================================================================
--- java/gr/sr/rankEngine/general/RankingConfig.java	(revision 0)
+++ java/gr/sr/rankEngine/general/RankingConfig.java	(working copy)
@@ -0,0 +1,53 @@
+package gr.sr.rankEngine.general;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class RankingConfig
+{
+	private static final Logger _log = LoggerFactory.getLogger(RankingConfig.class);
+	public static final String CONFIGURATION_FILE = "./config/extra/elemental/ranking.ini";
+	public static String DATABASE_DRIVER;
+	public static String DATABASE_URL;
+	public static String DATABASE_LOGIN;
+	public static String DATABASE_PASSWORD;
+	public static int DATABASE_MAX_CONNECTIONS;
+	public static int DATABASE_MAX_IDLE_TIME;
+	public static File DATAPACK_ROOT;
+	
+	public static void load()
+	{
+		// Load Ranking L2Properties file (if exists)
+		L2Properties L2RankingProperties = new L2Properties();
+		final File l2jranking = new File(CONFIGURATION_FILE);
+		try (InputStream is = new FileInputStream(l2jranking))
+		{
+			L2RankingProperties.load(is);
+		}
+		catch (Exception e)
+		{
+			_log.error("Error while loading Ranking settings!", e);
+		}
+		
+		DATABASE_DRIVER = L2RankingProperties.getProperty("Driver", "com.mysql.jdbc.Driver");
+		DATABASE_URL = L2RankingProperties.getProperty("URL", "jdbc:mysql://localhost/l2jgs");
+		DATABASE_LOGIN = L2RankingProperties.getProperty("Login", "root");
+		DATABASE_PASSWORD = L2RankingProperties.getProperty("Password", "");
+		DATABASE_MAX_CONNECTIONS = Integer.parseInt(L2RankingProperties.getProperty("MaximumDbConnections", "10"));
+		DATABASE_MAX_IDLE_TIME = Integer.parseInt(L2RankingProperties.getProperty("MaximumDbIdleTime", "0"));
+		try
+		{
+			DATAPACK_ROOT = new File(L2RankingProperties.getProperty("DatapackRoot", ".").replaceAll("\\\\", "/")).getCanonicalFile();
+		}
+		catch (IOException localIOException)
+		{
+			localIOException.printStackTrace();
+			DATAPACK_ROOT = new File(".");
+		}
+	}
+}
\ No newline at end of file
Index: java/l2r/gameserver/communitybbs/Managers/RankingBBSManager.java
===================================================================
--- java/l2r/gameserver/communitybbs/Managers/RankingBBSManager.java	(revision 0)
+++ java/l2r/gameserver/communitybbs/Managers/RankingBBSManager.java	(working copy)
@@ -0,0 +1,86 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package l2r.gameserver.communitybbs.Managers;
+
+import java.util.StringTokenizer;
+
+import l2r.gameserver.model.actor.instance.L2PcInstance;
+import gr.sr.rankEngine.datatables.ranking.ServerRanking;
+
+public class RankingBBSManager extends BaseBBSManager
+{
+	@Override
+	public void cbByPass(String command, L2PcInstance activeChar)
+	{
+		// Char in jail cannot use bbs
+		if (activeChar.isJailed())
+		{
+			return;
+		}
+		
+		// Synerge - Shows the initial htm for the ranking. That would be the first page
+		if (command.equals("_bbsrank"))
+		{
+			final String content = ServerRanking.getInstance().makeServerRankingHtm(0, activeChar.getLang());
+			separateAndSend(content, activeChar);
+		}
+		// Synerge - Shows the ranking, comes with parameters to see what category to see and if personal or server stats
+		else if (command.startsWith("_bbsrank;"))
+		{
+			try
+			{
+				StringTokenizer st = new StringTokenizer(command, ";");
+				st.nextToken();
+				final boolean isServerStats = st.nextToken().equalsIgnoreCase("server");
+				final int idTop = Integer.parseInt(st.nextToken());
+				
+				if (isServerStats)
+				{
+					final String content = ServerRanking.getInstance().makeServerRankingHtm(idTop, activeChar.getLang());
+					separateAndSend(content, activeChar);
+				}
+				else
+				{
+					final String content = ServerRanking.getInstance().makeSelfRankingHtm(activeChar.getStats(), (activeChar.getClan() != null ? activeChar.getClan().getStats() : null), idTop, activeChar.getLang());
+					separateAndSend(content, activeChar);
+				}
+			}
+			catch (Exception e)
+			{
+				e.printStackTrace();
+			}
+		}
+		else
+		{
+			separateAndSend("<html><body><br><br><center>the command: " + command + " is not implemented yet</center><br><br></body></html>", activeChar);
+		}
+	}
+	
+	@Override
+	public void parsewrite(String url, String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
+	{
+		
+	}
+	
+	public static RankingBBSManager getInstance()
+	{
+		return SingletonHolder._instance;
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final RankingBBSManager _instance = new RankingBBSManager();
+	}
+}
\ No newline at end of file
Index: java/l2r/gameserver/model/actor/stat/PlayableStat.java
===================================================================
--- java/l2r/gameserver/model/actor/stat/PlayableStat.java	(revision 122)
+++ java/l2r/gameserver/model/actor/stat/PlayableStat.java	(working copy)
@@ -34,6 +34,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import gr.sr.rankEngine.templates.Ranking;
+
 public class PlayableStat extends CharStat
 {
 	protected static final Logger _log = LoggerFactory.getLogger(PlayableStat.class);
@@ -102,6 +104,15 @@
 		
 		setExp(getExp() - value);
 		
+		// Synerge - Add the exp lost to the player stats
+		if (getActiveChar().isPlayer())
+		{
+			if (value > 0)
+			{
+				getActiveChar().getActingPlayer().addPlayerStats(Ranking.STAT_TOP_EXP_LOST, value);
+			}
+		}
+		
 		byte minimumLevel = 1;
 		if (getActiveChar() instanceof L2PetInstance)
 		{
Index: java/l2r/gameserver/model/actor/instance/L2PcInstance.java
===================================================================
--- java/l2r/gameserver/model/actor/instance/L2PcInstance.java	(revision 122)
+++ java/l2r/gameserver/model/actor/instance/L2PcInstance.java	(working copy)
@@ -349,6 +349,8 @@
 import gr.sr.protection.network.ProtectionManager;
 import gr.sr.pvpColorEngine.ColorSystemHandler;
 import gr.sr.pvpRewardEngine.pvpRewardHandler;
+import gr.sr.rankEngine.pc.PcStats;
+import gr.sr.rankEngine.templates.Ranking;
 import gr.sr.spreeEngine.SpreeHandler;
 import gr.sr.zones.FlagZoneHandler;
 
@@ -1177,6 +1179,9 @@
 		// Create a L2Radar object
 		_radar = new L2Radar(this);
 		
+		// Synerge - Create the statics holder for this pc
+		_stats = new PcStats(getObjectId());
+		
 		startVitalityTask();
 		
 		_cubics.shared();
@@ -2362,7 +2367,15 @@
 	public void setFame(int fame)
 	{
 		EventDispatcher.getInstance().notifyEventAsync(new OnPlayerFameChanged(this, _fame, fame), this);
-		_fame = (fame > Config.MAX_PERSONAL_FAME_POINTS) ? Config.MAX_PERSONAL_FAME_POINTS : fame;
+		fame = (fame > Config.MAX_PERSONAL_FAME_POINTS) ? Config.MAX_PERSONAL_FAME_POINTS : fame;
+		
+		// Synerge - Add the fame acquired to the stats
+		if (fame > _fame)
+		{
+			addPlayerStats(Ranking.STAT_TOP_FAME_ACQUIRED, fame - _fame);
+		}
+		
+		_fame = fame;
 	}
 	
 	/**
@@ -5856,8 +5869,27 @@
 		}
 		
 		// If in Arena, do nothing
-		if (isInsideZone(ZoneIdType.PVP) || targetPlayer.isInsideZone(ZoneIdType.PVP))
+		if (target.isInsideZone(ZoneIdType.MONSTER_TRACK))
 		{
+			// Synerge - Add the arena kill to the stats
+			if (target.isPlayer())
+			{
+				addPlayerStats(Ranking.STAT_TOP_ARENA_KILLS);
+				
+				targetPlayer.addPlayerStats(Ranking.STAT_TOP_ARENA_DEATHS);
+			}
+			return;
+		}
+		else if (isInsideZone(ZoneIdType.PVP) || targetPlayer.isInsideZone(ZoneIdType.PVP))
+		{
+			// Synerge - Add the pvp kill to the stats
+			if (target.isPlayer())
+			{
+				addPlayerStats(Ranking.STAT_TOP_SIEGE_KILLS);
+				
+				targetPlayer.addPlayerStats(Ranking.STAT_TOP_SIEGE_DEATHS);
+			}
+			
 			if ((getSiegeState() > 0) && (targetPlayer.getSiegeState() > 0) && (getSiegeState() != targetPlayer.getSiegeState()))
 			{
 				final L2Clan killerClan = getClan();
@@ -5882,6 +5914,12 @@
 		targetPlayer.isInsideZone(ZoneIdType.ZONE_CHAOTIC))) // Target player is inside chaotic zone
 		{
 			increasePvpKills(target);
+			
+			// Synerge - Add the pvp death to the stats
+			if (target.isPlayer())
+			{
+				targetPlayer.addPlayerStats(Ranking.STAT_TOP_PVP_DEATHS);
+			}
 		}
 		else
 		{
@@ -5891,6 +5929,12 @@
 			{
 				// 'Both way war' -> 'PvP Kill'
 				increasePvpKills(target);
+				
+				// Synerge - Add the pvp death to the stats
+				if (target.isPlayer())
+				{
+					targetPlayer.addPlayerStats(Ranking.STAT_TOP_PVP_DEATHS);
+				}
 				return;
 			}
 			
@@ -5900,12 +5944,32 @@
 				if (Config.KARMA_AWARD_PK_KILL)
 				{
 					increasePvpKills(target);
+					
+					// Synerge - Add the pk death to the stats
+					if (target.isPlayer())
+					{
+						targetPlayer.addPlayerStats(Ranking.STAT_TOP_PK_DEATHS);
+					}
 				}
+				
+				// Synerge - Add the siege kill to the stats
+				if (target.isPlayer())
+				{
+					addPlayerStats(Ranking.STAT_TOP_SIEGE_KILLS);
+					
+					targetPlayer.addPlayerStats(Ranking.STAT_TOP_SIEGE_DEATHS);
+				}
 			}
 			else if (targetPlayer.getPvpFlag() == 0) // Target player doesn't have karma
 			{
 				increasePkKillsAndKarma(target);
 				checkItemRestriction(); // Unequip adventurer items
+				
+				// Synerge - Add the pk death to the stats
+				if (target.isPlayer())
+				{
+					targetPlayer.addPlayerStats(Ranking.STAT_TOP_PK_DEATHS);
+				}
 			}
 		}
 	}
@@ -5940,6 +6004,15 @@
 				
 				setPvpKills(getPvpKills() + 1);
 				
+				// Synerge - Adds 1 pvp kill to the stats
+				addPlayerStats(Ranking.STAT_TOP_PVP_KILLS);
+				
+				// Synerge - If the player has a clan, then we must add a new pvp kill to the clan stats
+				if (getClan() != null)
+				{
+					getClan().getStats().addClanStats(Ranking.STAT_TOP_CLAN_PVP_KILLS.getRankingInfo());
+				}
+				
 				// Send a Server->Client UserInfo packet to attacker with its Karma and PK Counter
 				sendPacket(new UserInfo(this));
 				sendPacket(new ExBrExtraUserInfo(this));
@@ -5971,6 +6044,9 @@
 		if (target.isPlayer())
 		{
 			setPkKills(getPkKills() + 1);
+			
+			// Synerge - Add the pk kill to the stats
+			addPlayerStats(Ranking.STAT_TOP_PK_KILLS);
 		}
 		
 		// Color system
@@ -7534,6 +7610,15 @@
 							}
 						}
 					}
+					
+					// Synerge - Get dinamically characters values getting names from the ranking
+					for (Ranking top : Ranking.values())
+					{
+						if (top.getDbLocation().equalsIgnoreCase("characters"))
+						{
+							player.getStats().setPlayerStats(top.getRankingInfo(), rset.getLong(top.getDbName()));
+						}
+					}
 				}
 			}
 			
@@ -7608,6 +7693,31 @@
 		{
 			_log.error("Failed loading character.", e);
 		}
+		
+		// Synerge - Now we must get all the stats from the alternative table, using the ranking values
+		try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement statement = con.prepareStatement("SELECT variable,value FROM character_stats WHERE charId=?"))
+		{
+			statement.setInt(1, objectId);
+			try (ResultSet rset = statement.executeQuery())
+			{
+				while (rset.next())
+				{
+					// Obtengo dinamicamente cada ranking perteneciente a esta tabla con su valor correspondiente
+					for (Ranking top : Ranking.values())
+					{
+						if ((player != null) && top.getDbName().equalsIgnoreCase(rset.getString("variable")) && top.getDbLocation().equalsIgnoreCase("character_stats"))
+						{
+							player.getStats().setPlayerStats(top.getRankingInfo(), rset.getLong("value"));
+						}
+					}
+				}
+			}
+		}
+		catch (Exception e)
+		{
+			_log.error("Failed loading character stats", e);
+		}
 		return player;
 	}
 	
@@ -7993,8 +8103,34 @@
 			statement.setInt(63, isKilledSpecificMob() ? 1 : 0);
 			statement.setInt(64, getObjectId());
 			
+			// Synerge - When closing character, we must add the online value to the stats for it to be saved
+			addPlayerStats(Ranking.STAT_TOP_ONLINE, _onlineTime);
+			
 			statement.execute();
 			statement.close();
+			
+			// Synerge - The same for the longest online time, we must calculate it on exit
+			addPlayerStats(Ranking.STAT_TOP_LONGEST_ONLINE_TIME, Math.max(Math.round((System.currentTimeMillis() - getOnlineBeginTime()) / 60000), getStats().getPlayerStats(Ranking.STAT_TOP_LONGEST_ONLINE_TIME.getRankingInfo())));
+			
+			// Synerge - We create a dynamic query to update the stats based on the ranking values that use the character_stats table
+			try (PreparedStatement statement1 = con.prepareStatement("REPLACE INTO character_stats VALUES (?, ?, ?)"))
+			{
+				// Agrego dinamicamente cada ranking perteneciente a esta tabla con su valor correspondiente, para lograr un update totalmente dinamico
+				for (Ranking top : Ranking.values())
+				{
+					if (top.getDbLocation().equalsIgnoreCase("character_stats"))
+					{
+						// Solo lo salvamos si el cantidad es mayor a 0, sino creamos celdas en la db al pedo, el default es 0
+						if (getStats().getPlayerStats(top.getRankingInfo()) > 0)
+						{
+							statement1.setInt(1, getObjectId());
+							statement1.setString(2, top.getDbName());
+							statement1.setLong(3, getStats().getPlayerStats(top.getRankingInfo()));
+							statement1.execute();
+						}
+					}
+				}
+			}
 		}
 		catch (Exception e)
 		{
@@ -11551,11 +11687,11 @@
 	{
 		if (getExpOn())
 		{
-			getStat().addExpAndSp(addToExp, addToSp);
+			addExpAndSp(addToExp, addToSp, false);
 		}
 		else
 		{
-			getStat().addExpAndSp(0, addToSp);
+			addExpAndSp(0, addToSp, false);
 		}
 	}
 	
@@ -11564,6 +11700,15 @@
 		if (getExpOn())
 		{
 			getStat().addExpAndSp(addToExp, addToSp, useVitality);
+			
+			// Synerge - Add the exp acquired to the stats
+			if (useVitality)
+			{
+				if (addToExp > 0)
+				{
+					addPlayerStats(Ranking.STAT_TOP_EXP_ACQUIRED, addToExp);
+				}
+			}
 		}
 		else
 		{
@@ -12694,6 +12839,12 @@
 		sendPacket(SystemMessageId.REEL_LINE_AND_STOP_FISHING);
 		setIsImmobilized(false);
 		stopLookingForFishTask();
+		
+		// Synerge - Add one fish captured to the stats if succesful
+		if (win)
+		{
+			addPlayerStats(Ranking.STAT_TOP_FISHES_CAPTURED);
+		}
 	}
 	
 	public L2Fishing getFishCombat()
@@ -14562,7 +14713,7 @@
 	
 	public String getLang()
 	{
-		return _lang;
+		return _lang != null ? _lang : "en";
 	}
 	
 	public boolean setLang(String lang)
@@ -15932,6 +16083,29 @@
 		_lastMovePacket = System.currentTimeMillis();
 	}
 	
+	// Synerge - Custom stats holder
+	private PcStats _stats;
+	
+	public PcStats getStats()
+	{
+		return _stats;
+	}
+	
+	public long getOnlineBeginTime()
+	{
+		return _onlineBeginTime;
+	}
+	
+	public final void addPlayerStats(Ranking rank)
+	{
+		getStats().addPlayerStats(rank.getRankingInfo());
+	}
+	
+	public final void addPlayerStats(Ranking rank, long points)
+	{
+		getStats().addPlayerStats(rank.getRankingInfo(), points);
+	}
+	
 	// ============================================== //
 	// Premium Engine By L][Sunrise Team //
 	// ============================================== //
Index: java/l2r/gameserver/model/entity/olympiad/OlympiadGameNormal.java
===================================================================
--- java/l2r/gameserver/model/entity/olympiad/OlympiadGameNormal.java	(revision 122)
+++ java/l2r/gameserver/model/entity/olympiad/OlympiadGameNormal.java	(working copy)
@@ -41,6 +41,7 @@
 import l2r.gameserver.network.serverpackets.L2GameServerPacket;
 import l2r.gameserver.network.serverpackets.SystemMessage;
 import l2r.util.Rnd;
+import gr.sr.rankEngine.templates.Ranking;
 import gr.sr.utils.PcDualBoxCheck;
 
 /**
@@ -468,6 +469,16 @@
 					
 					winside = 1;
 					
+					// Synerge - Add the new oly match win and lost for the players
+					if (_playerOne.getPlayer() != null)
+					{
+						_playerOne.getPlayer().addPlayerStats(Ranking.STAT_TOP_OLY_KILLS);
+					}
+					if (_playerTwo.getPlayer() != null)
+					{
+						_playerTwo.getPlayer().addPlayerStats(Ranking.STAT_TOP_OLY_DEATHS);
+					}
+					
 					rewardParticipant(_playerOne.getPlayer(), getReward());
 					
 					if (Config.ALT_OLY_LOG_FIGHTS)
@@ -673,6 +684,16 @@
 				winner = _playerTwo.getName() + " won";
 				winside = 2;
 				
+				// Synerge - Add the new oly match win and lost for the players
+				if (_playerTwo.getPlayer() != null)
+				{
+					_playerTwo.getPlayer().addPlayerStats(Ranking.STAT_TOP_OLY_KILLS);
+				}
+				if (_playerOne.getPlayer() != null)
+				{
+					_playerOne.getPlayer().addPlayerStats(Ranking.STAT_TOP_OLY_DEATHS);
+				}
+				
 				// Save Fight Result
 				if (_startTime != 0) // TODO: Check why this can happen
 				{
Index: java/gr/sr/rankEngine/enums/RankTime.java
===================================================================
--- java/gr/sr/rankEngine/enums/RankTime.java	(revision 0)
+++ java/gr/sr/rankEngine/enums/RankTime.java	(working copy)
@@ -0,0 +1,8 @@
+package gr.sr.rankEngine.enums;
+
+public enum RankTime
+{
+	NONE,
+	SECONDS,
+	MINUTES
+}
\ No newline at end of file
Index: java/l2r/gameserver/model/actor/instance/L2GrandBossInstance.java
===================================================================
--- java/l2r/gameserver/model/actor/instance/L2GrandBossInstance.java	(revision 122)
+++ java/l2r/gameserver/model/actor/instance/L2GrandBossInstance.java	(working copy)
@@ -18,6 +18,8 @@
  */
 package l2r.gameserver.model.actor.instance;
 
+import java.util.Collection;
+
 import l2r.gameserver.Announcements;
 import l2r.gameserver.enums.InstanceType;
 import l2r.gameserver.instancemanager.RaidBossPointsManager;
@@ -30,6 +32,7 @@
 import l2r.util.Rnd;
 import gr.sr.achievementEngine.AchievementsManager;
 import gr.sr.configsEngine.configs.impl.CustomServerConfigs;
+import gr.sr.rankEngine.templates.Ranking;
 
 /**
  * This class manages all Grand Bosses.
@@ -92,6 +95,16 @@
 				player.setKilledSpecificMob(true);
 			}
 			
+			// Synerge - Add a new raid killed stat to all that participated in it
+			final Collection<L2PcInstance> plrs = getKnownList().getKnownPlayersInRadius(1000);
+			for (L2PcInstance knowns : plrs)
+			{
+				if ((knowns != null) && (getHating(knowns) > 0))
+				{
+					knowns.addPlayerStats(Ranking.STAT_TOP_RAIDS_KILLED);
+				}
+			}
+			
 			broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.RAID_WAS_SUCCESSFUL));
 			
 			if (CustomServerConfigs.ANNOUNCE_DEATH_REVIVE_OF_RAIDS)
Index: java/l2r/gameserver/communitybbs/Managers/BaseBBSManager.java
===================================================================
--- java/l2r/gameserver/communitybbs/Managers/BaseBBSManager.java	(revision 122)
+++ java/l2r/gameserver/communitybbs/Managers/BaseBBSManager.java	(working copy)
@@ -62,10 +62,7 @@
 	 */
 	protected void send1001(String html, L2PcInstance acha)
 	{
-		if (html.length() < 8192)
-		{
-			acha.sendPacket(new ShowBoard(html, "1001"));
-		}
+		acha.sendPacket(new ShowBoard(html, "1001"));
 	}
 	
 	/**
Index: java/l2r/gameserver/model/L2Clan.java
===================================================================
--- java/l2r/gameserver/model/L2Clan.java	(revision 122)
+++ java/l2r/gameserver/model/L2Clan.java	(working copy)
@@ -78,6 +78,9 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import gr.sr.rankEngine.clan.ClanStats;
+import gr.sr.rankEngine.templates.Ranking;
+
 public class L2Clan implements IIdentifiable, INamable
 {
 	private static final Logger _log = LoggerFactory.getLogger(L2Clan.class);
@@ -164,6 +167,10 @@
 	public L2Clan(int clanId)
 	{
 		_clanId = clanId;
+		
+		// Synerge - Initialize the clan stats module
+		_stats = new ClanStats(clanId);
+		
 		initializePrivs();
 		restore();
 		getWarehouse().restore();
@@ -178,6 +185,10 @@
 	{
 		_clanId = clanId;
 		_name = clanName;
+		
+		// Synerge - Initialize the clan stats module
+		_stats = new ClanStats(clanId);
+		
 		initializePrivs();
 	}
 	
@@ -365,6 +376,12 @@
 		
 		// Notify to scripts
 		EventDispatcher.getInstance().notifyEventAsync(new OnPlayerClanJoin(member, this));
+		
+		// Synerge - Update the clan stats with the new total member count
+		getStats().addClanStats(Ranking.STAT_TOP_CLAN_MEMBERS_COUNT.getRankingInfo(), getMembersCount());
+		
+		// Synerge - Add a new recruited member to the stats
+		getStats().addClanStats(Ranking.STAT_TOP_CLAN_MEMBERS_RECRUITED.getRankingInfo());
 	}
 	
 	/**
@@ -516,6 +533,12 @@
 		
 		// Notify to scripts
 		EventDispatcher.getInstance().notifyEventAsync(new OnPlayerClanLeft(exMember, this));
+		
+		// Synerge - We add a new member that withdrew from the clan to the stats
+		if (clanJoinExpiryTime > 0)
+		{
+			getStats().addClanStats(Ranking.STAT_TOP_CLAN_MEMBERS_WITHDREW.getRankingInfo());
+		}
 	}
 	
 	public L2ClanMember[] getMembers()
@@ -965,6 +988,9 @@
 			{
 				_log.info("New clan leader saved in db: " + getId());
 			}
+			
+			// Synerge - Save all clan stats to the database
+			getStats().updateClanStatsToDB();
 		}
 		catch (Exception e)
 		{
@@ -1143,6 +1169,9 @@
 			restoreRankPrivs();
 			restoreSkills();
 			restoreNotice();
+			
+			// Synerge - Restore all clan stats from the database
+			getStats().restoreClanStats();
 		}
 		catch (Exception e)
 		{
@@ -2192,6 +2221,9 @@
 	public synchronized void addReputationScore(int value, boolean save)
 	{
 		setReputationScore(getReputationScore() + value, save);
+		
+		// Synerge - Add the new reputation to the stats
+		getStats().addClanStats(Ranking.STAT_TOP_CLAN_FAME.getRankingInfo(), value);
 	}
 	
 	public synchronized void takeReputationScore(int value, boolean save)
@@ -3135,4 +3167,12 @@
 	{
 		_siegeDeaths.set(0);
 	}
+	
+	// Synerge - Clan Stats support for Server Ranking
+	private final ClanStats _stats;
+	
+	public final ClanStats getStats()
+	{
+		return _stats;
+	}
 }
Index: java/gr/sr/rankEngine/templates/RankingInfo.java
===================================================================
--- java/gr/sr/rankEngine/templates/RankingInfo.java	(revision 0)
+++ java/gr/sr/rankEngine/templates/RankingInfo.java	(working copy)
@@ -0,0 +1,74 @@
+package gr.sr.rankEngine.templates;
+
+import gr.sr.rankEngine.enums.RankTime;
+
+public class RankingInfo
+{
+	private final int _topId;
+	private final String _topName;
+	private final String _category;
+	private final String _dbName;
+	private final boolean _showPoints;
+	private final String _dbLocation;
+	private final boolean _isDescendent;
+	private final boolean _isStackable;
+	private final RankTime _time;
+	
+	public RankingInfo(int topId, String topName, String category, String dbName, boolean showPoints, String dbLocation, boolean isDescendent, boolean isStackable, RankTime time)
+	{
+		_topId = topId;
+		_topName = topName;
+		_category = category;
+		_dbName = dbName;
+		_showPoints = showPoints;
+		_dbLocation = dbLocation;
+		_isDescendent = isDescendent;
+		_isStackable = isStackable;
+		_time = time;
+	}
+	
+	public int getTopId()
+	{
+		return _topId;
+	}
+	
+	public String getTopName()
+	{
+		return _topName;
+	}
+	
+	public String getCategory()
+	{
+		return _category;
+	}
+	
+	public String getDbName()
+	{
+		return _dbName;
+	}
+	
+	public boolean mustShowPoints()
+	{
+		return _showPoints;
+	}
+	
+	public String getDbLocation()
+	{
+		return _dbLocation;
+	}
+	
+	public boolean isDescendent()
+	{
+		return _isDescendent;
+	}
+	
+	public boolean isStackable()
+	{
+		return _isStackable;
+	}
+	
+	public RankTime getTime()
+	{
+		return _time;
+	}
+}
\ No newline at end of file
Index: java/l2r/gameserver/RecipeController.java
===================================================================
--- java/l2r/gameserver/RecipeController.java	(revision 122)
+++ java/l2r/gameserver/RecipeController.java	(working copy)
@@ -57,6 +57,7 @@
 
 import gr.sr.configsEngine.configs.impl.LeaderboardsConfigs;
 import gr.sr.leaderboards.CraftLeaderboard;
+import gr.sr.rankEngine.templates.Ranking;
 
 public class RecipeController
 {
@@ -416,6 +417,12 @@
 				rewardPlayer(); // and immediately puts created item in its place
 				updateMakeInfo(true);
 				
+				// Synerge - Add a new craft succeed only for recipes with less than 100% rate
+				if (_recipeList.getSuccessRate() < 100)
+				{
+					_target.addPlayerStats(Ranking.STAT_TOP_CRAFTS_SUCCEED);
+				}
+				
 				if (LeaderboardsConfigs.RANK_CRAFT_ENABLED && (_target != _player) && (_recipeList.getSuccessRate() < 100))
 				{
 					CraftLeaderboard.getInstance().onSucess(_target.getObjectId(), _target.getName());
@@ -423,6 +430,12 @@
 			}
 			else
 			{
+				// Synerge - Add a new craft failed only for recipes with less than 100% rate
+				if (_recipeList.getSuccessRate() < 100)
+				{
+					_target.addPlayerStats(Ranking.STAT_TOP_CRAFTS_FAILED);
+				}
+				
 				if (_target != _player)
 				{
 					SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.CREATION_OF_S2_FOR_C1_AT_S3_ADENA_FAILED);
Index: java/l2r/gameserver/model/quest/QuestState.java
===================================================================
--- java/l2r/gameserver/model/quest/QuestState.java	(revision 122)
+++ java/l2r/gameserver/model/quest/QuestState.java	(working copy)
@@ -44,6 +44,7 @@
 import l2r.gameserver.network.serverpackets.TutorialShowHtml;
 import l2r.gameserver.network.serverpackets.TutorialShowQuestionMark;
 import l2r.gameserver.util.Util;
+import gr.sr.rankEngine.templates.Ranking;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -1160,6 +1161,12 @@
 			return this;
 		}
 		
+		// Synerge - Add a new quest finished to the stats
+		if (!repeatable && (getQuest().getId() > 0))
+		{
+			_player.addPlayerStats(Ranking.STAT_TOP_QUESTS_FINISHED);
+		}
+		
 		// Clean registered quest items
 		getQuest().removeRegisteredQuestItems(_player);
 		
Index: java/gr/sr/rankEngine/filter/XMLFilter.java
===================================================================
--- java/gr/sr/rankEngine/filter/XMLFilter.java	(revision 0)
+++ java/gr/sr/rankEngine/filter/XMLFilter.java	(working copy)
@@ -0,0 +1,17 @@
+package gr.sr.rankEngine.filter;
+
+import java.io.File;
+import java.io.FileFilter;
+
+public class XMLFilter implements FileFilter
+{
+	@Override
+	public boolean accept(File file)
+	{
+		if ((file == null) || (!file.isFile()))
+		{
+			return false;
+		}
+		return file.getName().toLowerCase().endsWith(".xml");
+	}
+}
\ No newline at end of file
Index: java/l2r/gameserver/Shutdown.java
===================================================================
--- java/l2r/gameserver/Shutdown.java	(revision 122)
+++ java/l2r/gameserver/Shutdown.java	(working copy)
@@ -55,6 +55,7 @@
 import gr.sr.leaderboards.CraftLeaderboard;
 import gr.sr.leaderboards.FishermanLeaderboard;
 import gr.sr.leaderboards.TvTLeaderboard;
+import gr.sr.rankEngine.datatables.ranking.ServerRanking;
 
 /**
  * This class provides the functions for shutting down and restarting the server.<br>
@@ -613,6 +614,10 @@
 			_log.info("Bot Report Table: Sucessfully saved reports to database!");
 		}
 		
+		// Synerge - Save monthly stats for each character
+		ServerRanking.getInstance().shutdown();
+		_log.info("Monthly Stats: Data saved(" + tc.getEstimatedTimeAndRestartCounter() + "ms).");
+		
 		try
 		{
 			Thread.sleep(5000);
Index: java/l2r/gameserver/model/itemcontainer/PcInventory.java
===================================================================
--- java/l2r/gameserver/model/itemcontainer/PcInventory.java	(revision 122)
+++ java/l2r/gameserver/model/itemcontainer/PcInventory.java	(working copy)
@@ -47,6 +47,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import gr.sr.rankEngine.templates.Ranking;
+
 public class PcInventory extends Inventory
 {
 	private static final Logger _log = LoggerFactory.getLogger(PcInventory.class);
@@ -592,6 +594,12 @@
 			}
 			if (actor != null)
 			{
+				// Synerge - Add the new amount of adena to the stats. Will be registered only if bigger than the last
+				if (item.getId() == ADENA_ID)
+				{
+					actor.addPlayerStats(Ranking.STAT_TOP_ADENA_ACQUIRED, item.getCount());
+				}
+				
 				// Send inventory update packet
 				if (!Config.FORCE_INVENTORY_UPDATE)
 				{
Index: java/l2r/gameserver/network/clientpackets/RequestBypassToServer.java
===================================================================
--- java/l2r/gameserver/network/clientpackets/RequestBypassToServer.java	(revision 122)
+++ java/l2r/gameserver/network/clientpackets/RequestBypassToServer.java	(working copy)
@@ -22,6 +22,7 @@
 
 import l2r.Config;
 import l2r.gameserver.communitybbs.BoardsManager;
+import l2r.gameserver.communitybbs.Managers.RankingBBSManager;
 import l2r.gameserver.data.xml.impl.AdminData;
 import l2r.gameserver.enums.CtrlIntention;
 import l2r.gameserver.handler.AdminCommandHandler;
@@ -257,6 +258,12 @@
 					EventDispatcher.getInstance().notifyEventAsync(new OnNpcManorBypass(activeChar, lastNpc, ask, state, time), lastNpc);
 				}
 			}
+			// Synerge - Separate top command for using the old community server for the Ranking System
+			// TODO handle this command properly using BoardsManager instead of direct access in RankingBBSManager
+			else if (_command.startsWith("_bbsrank"))
+			{
+				RankingBBSManager.getInstance().cbByPass(_command, activeChar);
+			}
 			else if (_command.startsWith("_bbs") || _command.startsWith("_maillist") || _command.startsWith("_friendlist"))
 			{
 				BoardsManager.getInstance().handleCommands(getClient(), _command);
Index: java/l2r/gameserver/GameServer.java
===================================================================
--- java/l2r/gameserver/GameServer.java	(revision 122)
+++ java/l2r/gameserver/GameServer.java	(working copy)
@@ -151,6 +151,9 @@
 import gr.sr.main.SunriseInfo;
 import gr.sr.main.SunriseServerMods;
 import gr.sr.protection.Protection;
+import gr.sr.rankEngine.datatables.character.CharacterMonthlyRanking;
+import gr.sr.rankEngine.datatables.ranking.ServerRanking;
+import gr.sr.rankEngine.templates.Ranking;
 
 public class GameServer
 {
@@ -396,6 +399,12 @@
 		// System.out.println("Loading static images....");
 		// CustomServerMods.getInstance().loadStaticImages();
 		
+		// Synerge - Load all the information for the Server Ranking
+		printSection("Ranking");
+		Ranking.generateRankings();
+		ServerRanking.getInstance();
+		CharacterMonthlyRanking.getInstance();
+		
 		Runtime.getRuntime().addShutdownHook(Shutdown.getInstance());
 		
 		_log.info("IdFactory: Free ObjectID's remaining: " + IdFactory.getInstance().size());
Index: java/gr/sr/rankEngine/templates/RankingHolder.java
===================================================================
--- java/gr/sr/rankEngine/templates/RankingHolder.java	(revision 0)
+++ java/gr/sr/rankEngine/templates/RankingHolder.java	(working copy)
@@ -0,0 +1,43 @@
+package gr.sr.rankEngine.templates;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import gr.sr.rankEngine.datatables.ranking.ServerRanking.RankingTop;
+import gr.sr.rankEngine.enums.RankTime;
+
+public class RankingHolder
+{
+	private static final Map<Integer, RankingInfo> rankings = new HashMap<>();
+	
+	public static void addNewStat(int Int, String String1, String String2, String String3, boolean Boolean1, String String4, boolean Boolean2, boolean Boolean3, RankTime RankTime)
+	{
+		rankings.put(Integer.valueOf(Int), new RankingInfo(Int, String1, String2, String3, Boolean1, String4, Boolean2, Boolean3, RankTime));
+	}
+	
+	public static void generateRankings(Map<Integer, RankingTop> Map)
+	{
+		Iterator<RankingInfo> Iterator = rankings.values().iterator();
+		while (Iterator.hasNext())
+		{
+			RankingInfo RankingInfo = Iterator.next();
+			Map.put(RankingInfo.getTopId(), new RankingTop(RankingInfo.getTopId(), RankingInfo.getTopName(), RankingInfo.getCategory(), RankingInfo.getDbName(), RankingInfo.mustShowPoints(), RankingInfo.getDbLocation(), RankingInfo.isDescendent(), RankingInfo.isStackable(), RankingInfo.getTime()));
+		}
+	}
+	
+	public static Map<Integer, RankingInfo> getRankings()
+	{
+		return rankings;
+	}
+	
+	public static RankingInfo getRankingInfo(int Int)
+	{
+		return rankings.get(Integer.valueOf(Int));
+	}
+	
+	public static int getRankingCount()
+	{
+		return rankings.size() + 1;
+	}
+}
\ No newline at end of file
Index: java/l2r/gameserver/model/stats/Formulas.java
===================================================================
--- java/l2r/gameserver/model/stats/Formulas.java	(revision 122)
+++ java/l2r/gameserver/model/stats/Formulas.java	(working copy)
@@ -91,6 +91,7 @@
 
 import gr.sr.balanceEngine.BalanceHandler;
 import gr.sr.configsEngine.configs.impl.FormulasConfigs;
+import gr.sr.rankEngine.templates.Ranking;
 
 /**
  * Global calculations.
@@ -637,6 +638,12 @@
 		damage *= weaponMod;
 		damage *= penaltyMod;
 		
+		// Synerge - Add the damage done to the player stats
+		if (attacker.isPlayer() && (damage > 5))
+		{
+			attacker.getActingPlayer().addPlayerStats(Ranking.STAT_TOP_DAMAGE, (long) damage);
+		}
+		
 		if (attacker.isDebug())
 		{
 			final StatsSet set = new StatsSet();
@@ -734,6 +741,12 @@
 		damage *= weaponMod;
 		damage *= penaltyMod;
 		
+		// Synerge - Add the damage done to the player stats
+		if (attacker.isPlayer() && (damage > 5))
+		{
+			attacker.getActingPlayer().addPlayerStats(Ranking.STAT_TOP_DAMAGE, (long) damage);
+		}
+		
 		if (attacker.isDebug())
 		{
 			final StatsSet set = new StatsSet();
@@ -1009,6 +1022,12 @@
 		damage = BalanceHandler.getInstance().calc(attacker, target, skill, damage, false);
 		// Reunion balancer - End
 		
+		// Synerge - Add the damage done to the player stats
+		if (attacker.isPlayer() && (damage > 5))
+		{
+			attacker.getActingPlayer().addPlayerStats(Ranking.STAT_TOP_DAMAGE, (long) damage);
+		}
+		
 		return damage;
 	}
 	
@@ -1121,6 +1140,12 @@
 		damage = BalanceHandler.getInstance().calc(attacker, target, skill, damage, true);
 		// Reunion balancer - End
 		
+		// Synerge - Add the damage done to the player stats
+		if (attacker.isPlayer() && (damage > 5))
+		{
+			attacker.getActingPlayer().addPlayerStats(Ranking.STAT_TOP_DAMAGE, (long) damage);
+		}
+		
 		return damage;
 	}
 	
@@ -1208,6 +1233,12 @@
 			}
 		}
 		
+		// Synerge - Add the damage done to the player stats
+		if ((attacker.getOwner() != null) && (damage > 5))
+		{
+			attacker.getOwner().addPlayerStats(Ranking.STAT_TOP_DAMAGE, (long) damage);
+		}
+		
 		return damage;
 	}
 	
Index: java/gr/sr/rankEngine/datatables/character/CharacterMonthlyRanking.java
===================================================================
--- java/gr/sr/rankEngine/datatables/character/CharacterMonthlyRanking.java	(revision 0)
+++ java/gr/sr/rankEngine/datatables/character/CharacterMonthlyRanking.java	(working copy)
@@ -0,0 +1,315 @@
+package gr.sr.rankEngine.datatables.character;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import l2r.L2DatabaseFactory;
+import l2r.gameserver.ThreadPoolManager;
+import gr.sr.rankEngine.datatables.ranking.ServerRanking;
+import gr.sr.rankEngine.datatables.ranking.ServerRanking.RankingTop;
+import gr.sr.rankEngine.datatables.ranking.ServerRanking.RankingTopMember;
+import gr.sr.rankEngine.templates.RankingHolder;
+
+public final class CharacterMonthlyRanking
+{
+	private static final Logger _log = Logger.getLogger(CharacterMonthlyRanking.class.getName());
+	protected final Map<Integer, RankingTop> _rankStats;
+	private final Map<Integer, MonthlyStats> _monthlyStats;
+	private long _time;
+	
+	protected static Comparator<RankingTopMember> _comparator;
+	
+	public CharacterMonthlyRanking()
+	{
+		_rankStats = new ConcurrentHashMap<>();
+		_monthlyStats = new ConcurrentHashMap<>();
+		_time = 0L;
+		
+		RankingHolder.generateRankings(_rankStats);
+		
+		try (final Connection connection = L2DatabaseFactory.getInstance().getConnection())
+		{
+			try (final PreparedStatement prepareStatement = connection.prepareStatement("SELECT t1.*, t2.char_name, t2.accesslevel FROM monthly_character_stats AS t1 INNER JOIN characters AS t2 WHERE t2.accesslevel>=0 AND t1.charId=t2.charId");
+				final ResultSet executeQuery = prepareStatement.executeQuery())
+			{
+				while (executeQuery.next())
+				{
+					final int int1 = executeQuery.getInt("charId");
+					final MonthlyStats monthlyStats = new MonthlyStats(int1);
+					for (final RankingTop rankingTop : _rankStats.values())
+					{
+						if (rankingTop.getDbName().equalsIgnoreCase(executeQuery.getString("variable")))
+						{
+							monthlyStats.setPlayerStats(rankingTop.getTopId(), executeQuery.getLong("value"));
+							if (executeQuery.getInt("accesslevel") != 0)
+							{
+								continue;
+							}
+							rankingTop.addPlayer(new ServerRanking.RankingTopMember(executeQuery.getString("char_name"), executeQuery.getLong("value")));
+						}
+					}
+					_monthlyStats.put(int1, monthlyStats);
+				}
+			}
+			try (final PreparedStatement prepareStatement2 = connection.prepareStatement("SELECT t1.*, t2.accesslevel, t3.clan_name FROM monthly_character_stats AS t1 INNER JOIN characters AS t2 INNER JOIN clan_data as t3 WHERE t2.accesslevel>=0 AND t3.leader_id=t2.charId AND t3.clan_id=t1.charId");
+				final ResultSet executeQuery2 = prepareStatement2.executeQuery())
+			{
+				while (executeQuery2.next())
+				{
+					final int int2 = executeQuery2.getInt("charId");
+					final MonthlyStats monthlyStats2 = new MonthlyStats(int2);
+					for (final RankingTop rankingTop2 : _rankStats.values())
+					{
+						if (rankingTop2.getDbName().equalsIgnoreCase(executeQuery2.getString("variable")))
+						{
+							monthlyStats2.setPlayerStats(rankingTop2.getTopId(), executeQuery2.getLong("value"));
+							if (executeQuery2.getInt("accesslevel") != 0)
+							{
+								continue;
+							}
+							rankingTop2.addPlayer(new RankingTopMember(executeQuery2.getString("clan_name"), executeQuery2.getLong("value")));
+						}
+					}
+					_monthlyStats.put(int2, monthlyStats2);
+				}
+			}
+			_log.log(Level.INFO, getClass().getSimpleName() + ": Loaded statics of this month for " + _monthlyStats.size() + " characters");
+		}
+		catch (SQLException ex)
+		{
+			_log.warning(getClass().getSimpleName() + ": Error while loading monthly rankings:" + ex);
+		}
+		
+		for (final RankingTop rankingTop3 : _rankStats.values())
+		{
+			final ArrayList<RankingTopMember> list = new ArrayList<>(rankingTop3.getPlayers());
+			Collections.sort(list, _comparator);
+			rankingTop3.cleanPlayers();
+			rankingTop3.getPlayers().addAll(list);
+		}
+		
+		final Calendar instance = Calendar.getInstance();
+		instance.add(2, 1);
+		instance.set(5, 1);
+		instance.set(11, 6);
+		instance.set(12, 0);
+		_time = instance.getTimeInMillis();
+		ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new ReloadStatsFromDB(), 3600000L, 3600000L);
+	}
+	
+	public RankingTop getRankingById(int var1)
+	{
+		return _rankStats.get(Integer.valueOf(var1));
+	}
+	
+	public final void addPlayerStats(int var1, int var2, long var3, boolean var5)
+	{
+		if (System.currentTimeMillis() >= _time)
+		{
+			cleanAllMonthlyStats();
+		}
+		
+		if (!_monthlyStats.containsKey(Integer.valueOf(var1)))
+		{
+			_monthlyStats.put(Integer.valueOf(var1), new MonthlyStats(var1));
+		}
+		
+		_monthlyStats.get(Integer.valueOf(var1)).addPlayerStats(var2, var3, var5);
+	}
+	
+	public final long getPlayerStats(int var1, int var2)
+	{
+		return !_monthlyStats.containsKey(Integer.valueOf(var1)) ? 0L : _monthlyStats.get(Integer.valueOf(var1)).getPlayerStats(var2);
+	}
+	
+	public final void cleanAllMonthlyStats()
+	{
+		_monthlyStats.clear();
+		
+		try (final Connection connection = L2DatabaseFactory.getInstance().getConnection();
+			final Statement statement = connection.createStatement())
+		{
+			statement.execute("DELETE FROM monthly_character_stats WHERE charId > 0");
+		}
+		catch (Exception ex)
+		{
+			_log.log(Level.WARNING, getClass().getSimpleName() + ": Error while removing all last month stats ! " + ex.getMessage(), ex);
+		}
+	}
+	
+	public final void saveMonthlyStats()
+	{
+		if (_monthlyStats.isEmpty())
+		{
+			return;
+		}
+		
+		try (final Connection connection = L2DatabaseFactory.getInstance().getConnection();
+			final PreparedStatement prepareStatement = connection.prepareStatement("REPLACE INTO monthly_character_stats VALUES (?, ?, ?)"))
+		{
+			for (final MonthlyStats monthlyStats : _monthlyStats.values())
+			{
+				if (!monthlyStats.isModified())
+				{
+					continue;
+				}
+				for (final ServerRanking.RankingTop rankingTop : _rankStats.values())
+				{
+					prepareStatement.setInt(1, monthlyStats.getCharId());
+					prepareStatement.setString(2, rankingTop.getDbName());
+					prepareStatement.setLong(3, monthlyStats.getPlayerStats(rankingTop.getTopId()));
+					prepareStatement.addBatch();
+				}
+				monthlyStats.setIsModified(false);
+			}
+			prepareStatement.executeBatch();
+		}
+		catch (Exception ex)
+		{
+			_log.log(Level.WARNING, getClass().getSimpleName() + ": Error while saving all character stats for this month ! " + ex.getMessage(), ex);
+		}
+	}
+	
+	public class MonthlyStats
+	{
+		private final int _charId;
+		private boolean _modified = false;
+		private final long[] _rankCount = new long[RankingHolder.getRankingCount()];
+		
+		public MonthlyStats(int charId)
+		{
+			_charId = charId;
+		}
+		
+		public int getCharId()
+		{
+			return _charId;
+		}
+		
+		public void setPlayerStats(int var1, long var2)
+		{
+			_rankCount[var1] = var2;
+		}
+		
+		public void addPlayerStats(int var1, long var2, boolean var4)
+		{
+			if (var4)
+			{
+				if (_rankCount[var1] < var2)
+				{
+					_rankCount[var1] = var2;
+				}
+			}
+			else
+			{
+				_rankCount[var1] += var2;
+			}
+			
+			_modified = true;
+		}
+		
+		public long getPlayerStats(int var1)
+		{
+			return _rankCount[var1];
+		}
+		
+		public void setIsModified(boolean modified)
+		{
+			_modified = modified;
+		}
+		
+		public boolean isModified()
+		{
+			return _modified;
+		}
+	}
+	
+	public static final CharacterMonthlyRanking getInstance()
+	{
+		return SingletonHolder._instance;
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final CharacterMonthlyRanking _instance = new CharacterMonthlyRanking();
+	}
+	
+	protected class ReloadStatsFromDB implements Runnable
+	{
+		@Override
+		public void run()
+		{
+			synchronized (_rankStats)
+			{
+				saveMonthlyStats();
+				try
+				{
+					Thread.sleep(100L);
+				}
+				catch (InterruptedException ex2)
+				{
+				}
+				final Iterator<ServerRanking.RankingTop> iterator = _rankStats.values().iterator();
+				while (iterator.hasNext())
+				{
+					iterator.next().cleanPlayers();
+				}
+				try (final Connection connection = L2DatabaseFactory.getInstance().getConnection())
+				{
+					try (final PreparedStatement prepareStatement = connection.prepareStatement("SELECT t1.*, t2.char_name, t2.accesslevel FROM monthly_character_stats AS t1 INNER JOIN characters AS t2 WHERE t2.accesslevel=0 AND t1.charId=t2.charId");
+						final ResultSet executeQuery = prepareStatement.executeQuery())
+					{
+						while (executeQuery.next())
+						{
+							for (final ServerRanking.RankingTop rankingTop : _rankStats.values())
+							{
+								if (rankingTop.getDbName().equalsIgnoreCase(executeQuery.getString("variable")))
+								{
+									rankingTop.addPlayer(new ServerRanking.RankingTopMember(executeQuery.getString("char_name"), executeQuery.getLong("value")));
+								}
+							}
+						}
+					}
+					try (final PreparedStatement prepareStatement2 = connection.prepareStatement("SELECT t1.*, t2.accesslevel, t3.clan_name FROM monthly_character_stats AS t1 INNER JOIN characters AS t2 INNER JOIN clan_data as t3 WHERE t2.accesslevel=0 AND t3.leader_id=t2.charId AND t3.clan_id=t1.charId");
+						final ResultSet executeQuery2 = prepareStatement2.executeQuery())
+					{
+						while (executeQuery2.next())
+						{
+							for (final ServerRanking.RankingTop rankingTop2 : _rankStats.values())
+							{
+								if (rankingTop2.getDbName().equalsIgnoreCase(executeQuery2.getString("variable")))
+								{
+									rankingTop2.addPlayer(new ServerRanking.RankingTopMember(executeQuery2.getString("clan_name"), executeQuery2.getLong("value")));
+								}
+							}
+						}
+					}
+				}
+				catch (SQLException ex)
+				{
+					ex.printStackTrace();
+				}
+				
+				for (final RankingTop rankingTop3 : _rankStats.values())
+				{
+					final ArrayList<RankingTopMember> list = new ArrayList<>(rankingTop3.getPlayers());
+					Collections.sort(list, _comparator);
+					rankingTop3.cleanPlayers();
+					rankingTop3.getPlayers().addAll(list);
+				}
+			}
+		}
+	}
+}
Index: java/gr/sr/rankEngine/clan/ClanStats.java
===================================================================
--- java/gr/sr/rankEngine/clan/ClanStats.java	(revision 0)
+++ java/gr/sr/rankEngine/clan/ClanStats.java	(working copy)
@@ -0,0 +1,122 @@
+package gr.sr.rankEngine.clan;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.Iterator;
+
+import l2r.L2DatabaseFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import gr.sr.rankEngine.datatables.character.CharacterMonthlyRanking;
+import gr.sr.rankEngine.templates.RankingHolder;
+import gr.sr.rankEngine.templates.RankingInfo;
+
+public class ClanStats
+{
+	private static final Logger _log = LoggerFactory.getLogger(ClanStats.class);
+	private final int clanId;
+	private final long[] clanStats = new long[RankingHolder.getRankingCount()];
+	
+	public ClanStats(int Int)
+	{
+		clanId = Int;
+	}
+	
+	public int getClanId()
+	{
+		return clanId;
+	}
+	
+	public void setClanStats(RankingInfo RankingInfo, long Long)
+	{
+		clanStats[RankingInfo.getTopId()] = Long;
+	}
+	
+	public void addClanStats(RankingInfo RankingInfo)
+	{
+		addClanStats(RankingInfo, 1L);
+	}
+	
+	public void addClanStats(RankingInfo RankingInfo, long Long)
+	{
+		if (clanStats[RankingInfo.getTopId()] > (9223372036854775807L - Long))
+		{
+			return;
+		}
+		if (RankingInfo.isStackable())
+		{
+			clanStats[RankingInfo.getTopId()] += Long;
+			CharacterMonthlyRanking.getInstance().addPlayerStats(clanId, RankingInfo.getTopId(), Long, false);
+		}
+		else if (Long > clanStats[RankingInfo.getTopId()])
+		{
+			clanStats[RankingInfo.getTopId()] = Long;
+			CharacterMonthlyRanking.getInstance().addPlayerStats(clanId, RankingInfo.getTopId(), Long, true);
+		}
+	}
+	
+	public long getClanStats(RankingInfo RankingInfo)
+	{
+		return clanStats[RankingInfo.getTopId()];
+	}
+	
+	public long getClanStats(int Int)
+	{
+		return clanStats[Int];
+	}
+	
+	public void restoreClanStats()
+	{
+		try (Connection con = L2DatabaseFactory.getInstance().getConnection())
+		{
+			PreparedStatement PreparedStatement = con.prepareStatement("SELECT variable,value FROM clan_stats WHERE clanId=?");
+			PreparedStatement.setInt(1, clanId);
+			ResultSet rset = PreparedStatement.executeQuery();
+			
+			while (rset.next())
+			{
+				Iterator<RankingInfo> Iterator = RankingHolder.getRankings().values().iterator();
+				while (Iterator.hasNext())
+				{
+					RankingInfo RankingInfo = Iterator.next();
+					if ((RankingInfo.getDbName().equalsIgnoreCase(rset.getString("variable"))) && (RankingInfo.getDbLocation().equalsIgnoreCase("clan_stats")))
+					{
+						setClanStats(RankingInfo, rset.getLong("value"));
+					}
+				}
+			}
+		}
+		catch (Exception e)
+		{
+			_log.error("Failed loading clan stats", e);
+		}
+	}
+	
+	public void updateClanStatsToDB()
+	{
+		try (Connection Connection = L2DatabaseFactory.getInstance().getConnection())
+		{
+			PreparedStatement PreparedStatement = Connection.prepareStatement("REPLACE INTO clan_stats VALUES (?, ?, ?)");
+			Iterator<RankingInfo> Iterator = RankingHolder.getRankings().values().iterator();
+			while (Iterator.hasNext())
+			{
+				RankingInfo RankingInfo = Iterator.next();
+				if ((RankingInfo.getDbLocation().equalsIgnoreCase("clan_stats")) && (getClanStats(RankingInfo) > 0L))
+				{
+					PreparedStatement.setInt(1, clanId);
+					PreparedStatement.setString(2, RankingInfo.getDbName());
+					PreparedStatement.setLong(3, getClanStats(RankingInfo));
+					PreparedStatement.addBatch();
+				}
+			}
+			PreparedStatement.executeBatch();
+		}
+		catch (Exception e)
+		{
+			_log.warn("Could not update clan stats to db: " + this + " - " + e.getMessage(), e);
+		}
+	}
+}
\ No newline at end of file
Index: java/gr/sr/rankEngine/pc/PcStats.java
===================================================================
--- java/gr/sr/rankEngine/pc/PcStats.java	(revision 0)
+++ java/gr/sr/rankEngine/pc/PcStats.java	(working copy)
@@ -0,0 +1,59 @@
+package gr.sr.rankEngine.pc;
+
+import gr.sr.rankEngine.datatables.character.CharacterMonthlyRanking;
+import gr.sr.rankEngine.templates.RankingHolder;
+import gr.sr.rankEngine.templates.RankingInfo;
+
+public class PcStats
+{
+	private final int _ownerId;
+	private final long[] playerStats = new long[RankingHolder.getRankingCount()];
+	
+	public PcStats(int ownerId)
+	{
+		_ownerId = ownerId;
+	}
+	
+	public int getOwnerId()
+	{
+		return _ownerId;
+	}
+	
+	public void setPlayerStats(RankingInfo RankingInfo, long Long)
+	{
+		playerStats[RankingInfo.getTopId()] = Long;
+	}
+	
+	public void addPlayerStats(RankingInfo RankingInfo)
+	{
+		addPlayerStats(RankingInfo, 1L);
+	}
+	
+	public void addPlayerStats(RankingInfo RankingInfo, long Long)
+	{
+		if (playerStats[RankingInfo.getTopId()] > (9223372036854775807L - Long))
+		{
+			return;
+		}
+		if (RankingInfo.isStackable())
+		{
+			playerStats[RankingInfo.getTopId()] += Long;
+			CharacterMonthlyRanking.getInstance().addPlayerStats(_ownerId, RankingInfo.getTopId(), Long, false);
+		}
+		else
+		{
+			playerStats[RankingInfo.getTopId()] = Long;
+			CharacterMonthlyRanking.getInstance().addPlayerStats(_ownerId, RankingInfo.getTopId(), Long, true);
+		}
+	}
+	
+	public long getPlayerStats(RankingInfo RankingInfo)
+	{
+		return playerStats[RankingInfo.getTopId()];
+	}
+	
+	public long getPlayerStats(int Int)
+	{
+		return playerStats[Int];
+	}
+}
\ No newline at end of file
Index: java/l2r/gameserver/data/sql/ClanTable.java
===================================================================
--- java/l2r/gameserver/data/sql/ClanTable.java	(revision 122)
+++ java/l2r/gameserver/data/sql/ClanTable.java	(working copy)
@@ -64,6 +64,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import gr.sr.rankEngine.templates.Ranking;
+
 /**
  * This class loads the clan related data.
  */
@@ -452,6 +454,10 @@
 		msg = SystemMessage.getSystemMessage(SystemMessageId.CLAN_S1_HAS_DECIDED_TO_STOP);
 		msg.addString(clan1.getName());
 		clan2.broadcastToOnlineMembers(msg);
+		
+		// Synerge - Add a new clan war lost and won for each clan when a clan war is canceled
+		clan1.getStats().addClanStats(Ranking.STAT_TOP_CLAN_WARS_LOST.getRankingInfo());
+		clan2.getStats().addClanStats(Ranking.STAT_TOP_CLAN_WARS_WON.getRankingInfo());
 	}
 	
 	public void checkSurrender(L2Clan clan1, L2Clan clan2)
Index: java/l2r/gameserver/model/entity/Duel.java
===================================================================
--- java/l2r/gameserver/model/entity/Duel.java	(revision 122)
+++ java/l2r/gameserver/model/entity/Duel.java	(working copy)
@@ -42,6 +42,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import gr.sr.rankEngine.templates.Ranking;
+
 public class Duel
 {
 	protected static final Logger _log = LoggerFactory.getLogger(Duel.class);
@@ -769,6 +771,10 @@
 				
 				broadcastToTeam1(sm);
 				broadcastToTeam2(sm);
+				
+				// Synerge - Add to the stats the won and lost duel for each part
+				setWinDuel(1);
+				setLostDuel(2);
 				break;
 			case Team1Surrender:
 			case Team2Win:
@@ -786,6 +792,10 @@
 				
 				broadcastToTeam1(sm);
 				broadcastToTeam2(sm);
+				
+				// Synerge - Add to the stats the won and lost duel for each part
+				setWinDuel(2);
+				setLostDuel(1);
 				break;
 			case Canceled:
 				stopFighting();
@@ -1067,4 +1077,96 @@
 			}
 		}
 	}
+	
+	/**
+	 * Synerge - Sets stats for the winner team or player for the duel
+	 * @param nTeam
+	 */
+	public void setWinDuel(int nTeam)
+	{
+		if (nTeam == 1)
+		{
+			if (_playerA == null)
+			{
+				return;
+			}
+			
+			if (_partyDuel && (_playerA.getParty() != null))
+			{
+				for (L2PcInstance temp : _playerA.getParty().getMembers())
+				{
+					temp.addPlayerStats(Ranking.STAT_TOP_DUELS_WIN);
+				}
+			}
+			else
+			{
+				_playerA.addPlayerStats(Ranking.STAT_TOP_DUELS_WIN);
+			}
+		}
+		else
+		{
+			if (_playerB == null)
+			{
+				return;
+			}
+			
+			if (_partyDuel && (_playerB.getParty() != null))
+			{
+				for (L2PcInstance temp : _playerB.getParty().getMembers())
+				{
+					temp.addPlayerStats(Ranking.STAT_TOP_DUELS_WIN);
+				}
+			}
+			else
+			{
+				_playerB.addPlayerStats(Ranking.STAT_TOP_DUELS_WIN);
+			}
+		}
+	}
+	
+	/**
+	 * Synerge - Sets stats for the losing team or player for the duel
+	 * @param nTeam
+	 */
+	public void setLostDuel(int nTeam)
+	{
+		if (nTeam == 1)
+		{
+			if (_playerA == null)
+			{
+				return;
+			}
+			
+			if (_partyDuel && (_playerA.getParty() != null))
+			{
+				for (L2PcInstance temp : _playerA.getParty().getMembers())
+				{
+					temp.addPlayerStats(Ranking.STAT_TOP_DUELS_LOST);
+				}
+			}
+			else
+			{
+				_playerA.addPlayerStats(Ranking.STAT_TOP_DUELS_LOST);
+			}
+		}
+		else
+		{
+			if (_playerB == null)
+			{
+				return;
+			}
+			
+			if (_partyDuel && (_playerB.getParty() != null))
+			{
+				for (L2PcInstance temp : _playerB.getParty().getMembers())
+				{
+					temp.addPlayerStats(Ranking.STAT_TOP_DUELS_LOST);
+				}
+			}
+			else
+			{
+				_playerB.addPlayerStats(Ranking.STAT_TOP_DUELS_LOST);
+			}
+		}
+	}
 }
Index: java/l2r/gameserver/model/actor/L2Attackable.java
===================================================================
--- java/l2r/gameserver/model/actor/L2Attackable.java	(revision 122)
+++ java/l2r/gameserver/model/actor/L2Attackable.java	(working copy)
@@ -79,6 +79,7 @@
 import l2r.gameserver.util.Util;
 import l2r.util.Rnd;
 import gr.sr.interf.SunriseEvents;
+import gr.sr.rankEngine.templates.Ranking;
 
 public class L2Attackable extends L2Npc
 {
@@ -351,6 +352,16 @@
 			return false;
 		}
 		
+		// Synerge - Add a new mob kill to the stats
+		if ((killer != null) && killer.isPlayable() && !isRaid())
+		{
+			// Only consider player with max 9 lvls of difference
+			if (killer.getActingPlayer().getLevel() <= (getLevel() + 9))
+			{
+				killer.getActingPlayer().addPlayerStats(Ranking.STAT_TOP_MOBS_KILLS);
+			}
+		}
+		
 		if ((killer != null) && killer.isPlayable())
 		{
 			// Delayed notification
Index: java/gr/sr/rankEngine/general/L2Properties.java
===================================================================
--- java/gr/sr/rankEngine/general/L2Properties.java	(revision 0)
+++ java/gr/sr/rankEngine/general/L2Properties.java	(working copy)
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2004-2014 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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 Server 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 gr.sr.rankEngine.general;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Specialized {@link java.util.Properties} class.<br>
+ * Simplifies loading of property files and adds logging if a non existing property is requested.<br>
+ * @author Noctarius
+ */
+public final class L2Properties extends Properties
+{
+	private static final long serialVersionUID = 1L;
+	
+	private static Logger _log = LoggerFactory.getLogger(L2Properties.class);
+	
+	public L2Properties()
+	{
+		
+	}
+	
+	public L2Properties(String name) throws IOException
+	{
+		try (FileInputStream fis = new FileInputStream(name))
+		{
+			load(fis);
+		}
+	}
+	
+	public L2Properties(File file) throws IOException
+	{
+		try (FileInputStream fis = new FileInputStream(file))
+		{
+			load(fis);
+		}
+	}
+	
+	public L2Properties(InputStream inStream) throws IOException
+	{
+		load(inStream);
+	}
+	
+	public L2Properties(Reader reader) throws IOException
+	{
+		load(reader);
+	}
+	
+	public void load(String name) throws IOException
+	{
+		try (FileInputStream fis = new FileInputStream(name))
+		{
+			load(fis);
+		}
+	}
+	
+	public void load(File file) throws IOException
+	{
+		try (FileInputStream fis = new FileInputStream(file))
+		{
+			load(fis);
+		}
+	}
+	
+	@Override
+	public void load(InputStream inStream) throws IOException
+	{
+		try (InputStreamReader isr = new InputStreamReader(inStream, Charset.defaultCharset()))
+		{
+			super.load(isr);
+		}
+		finally
+		{
+			inStream.close();
+		}
+	}
+	
+	@Override
+	public void load(Reader reader) throws IOException
+	{
+		try
+		{
+			super.load(reader);
+		}
+		finally
+		{
+			reader.close();
+		}
+	}
+	
+	@Override
+	public String getProperty(String key)
+	{
+		String property = super.getProperty(key);
+		
+		if (property == null)
+		{
+			_log.info("L2Properties: Missing property for key - " + key);
+			
+			return null;
+		}
+		
+		return property.trim();
+	}
+	
+	@Override
+	public String getProperty(String key, String defaultValue)
+	{
+		String property = super.getProperty(key, defaultValue);
+		
+		if (property == null)
+		{
+			_log.warn("L2Properties: Missing defaultValue for key - " + key);
+			
+			return null;
+		}
+		
+		return property.trim();
+	}
+}
Index: java/gr/sr/rankEngine/templates/Ranking.java
===================================================================
--- java/gr/sr/rankEngine/templates/Ranking.java	(revision 0)
+++ java/gr/sr/rankEngine/templates/Ranking.java	(working copy)
@@ -0,0 +1,165 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package gr.sr.rankEngine.templates;
+
+import gr.sr.rankEngine.datatables.ranking.ServerRanking;
+import gr.sr.rankEngine.enums.RankTime;
+import gr.sr.rankEngine.general.RankingConfig;
+
+/**
+ * Statics list for the ranking
+ * @author Synerge
+ */
+public enum Ranking
+{
+	// Structure: Name, Category, DbCellName, If must show points, DbTableName, If must be ordered descendent, If is unique or stackable (set or add from the last value)
+	STAT_TOP_PVP_KILLS("rank_top_pvpkills", "rank_category_combat", "pvpkills", ServerRanking.SHOW_POINTS, "characters", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top PvP
+	STAT_TOP_PK_KILLS("rank_top_pkkills", "rank_category_combat", "real_pk_kills", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Pk
+	STAT_TOP_EXP("rank_top_experience", "rank_category_general", "exp", ServerRanking.SHOW_POINTS, "characters", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Exp
+	STAT_TOP_PVP_DEATHS("rank_top_pvpdeaths", "rank_category_combat", "pvp_deaths", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top PvP Deaths
+	STAT_TOP_PK_DEATHS("rank_top_pkdeaths", "rank_category_combat", "pk_deaths", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Pk Deaths
+	STAT_TOP_CRAFTS_SUCCEED("rank_top_crafts_succeed", "rank_category_general", "crafts_succeed", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Successful Crafts
+	STAT_TOP_CRAFTS_FAILED("rank_top_crafts_failed", "rank_category_general", "crafts_failed", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Failed Crafts
+	STAT_TOP_ONLINE("rank_top_onlinetime", "rank_category_general", "onlinetime", ServerRanking.SHOW_POINTS, "characters", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE, RankTime.SECONDS), // Top Online
+	STAT_TOP_BSOES_USED("rank_top_bsoes_used", "rank_category_general", "bsoes_used", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top BSOEs Usados
+	STAT_TOP_EVENTS_PARTICIPATED("rank_top_events_participated", "rank_category_general", "events_participated", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Eventos Participados
+	STAT_TOP_SIEGE_KILLS("rank_top_siege_kills", "rank_category_combat", "siege_kills", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Kills en Asedios
+	STAT_TOP_SIEGE_DEATHS("rank_top_siege_deaths", "rank_category_combat", "siege_deaths", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Muertes en Asedios
+	STAT_TOP_RAIDS_KILLED("rank_top_raids_killed", "rank_category_hunting", "raids_killed", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Raids Matados
+	STAT_TOP_ENCHANTS_SUCCEED("rank_top_enchants_succeed", "rank_category_general", "enchants_succeed", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Enchants Exitosos
+	STAT_TOP_ENCHANTS_FAILED("rank_top_enchants_failed", "rank_category_general", "enchants_failed", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Enchants Fallidos
+	STAT_TOP_FISHES_CAPTURED("rank_top_fishes_captured", "rank_category_hunting", "fishes_captured", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Peces Capturados
+	STAT_TOP_QUESTS_FINISHED("rank_top_quests_finished", "rank_category_general", "quests_finished", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Quests Terminadas
+	STAT_TOP_ARENA_KILLS("rank_top_arena_kills", "rank_category_combat", "arena_kills", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Kills en Arena
+	STAT_TOP_ARENA_DEATHS("rank_top_arena_deaths", "rank_category_combat", "arena_deaths", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Deaths en Arena
+	STAT_TOP_OLY_KILLS("rank_top_oly_kills", "rank_category_combat", "oly_kills", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Combates de Olys Ganados
+	STAT_TOP_OLY_DEATHS("rank_top_oly_deaths", "rank_category_combat", "oly_deaths", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Combates de Olys Perdidos
+	STAT_TOP_MOBS_KILLS("rank_top_mobs_kills", "rank_category_hunting", "mobs_kills", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Mobs Matados
+	STAT_TOP_MOBS_DEATHS("rank_top_mobs_death", "rank_category_hunting", "mobs_death", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Muertes por Mobs
+	STAT_TOP_DUELS_WIN("rank_top_duels_win", "rank_category_combat", "duels_win", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Duelos Ganados
+	STAT_TOP_DUELS_LOST("rank_top_duels_lost", "rank_category_combat", "duels_lost", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Duelos Perdidos
+	STAT_TOP_LONGEST_ONLINE_TIME("rank_top_longest_online", "rank_category_general", "longestOnline", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_UNIQUE, RankTime.MINUTES), // Top Tiempo Online mas Largo
+	STAT_TOP_EXP_ACQUIRED("rank_top_exp_acquired", "rank_category_hunting", "exp_acquired", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Experiencia Obtenida
+	STAT_TOP_EXP_LOST("rank_top_exp_lost", "rank_category_hunting", "exp_lost", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Experiencia Perdida
+	STAT_TOP_ADENA_ACQUIRED("rank_top_adena_acquired", "rank_category_general", "adena_acquired", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_UNIQUE), // Top Adena Obtenida
+	STAT_TOP_FAME_ACQUIRED("rank_top_fame_acquired", "rank_category_general", "fame_acquired", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Fama Obtenida
+	STAT_TOP_DAMAGE("rank_top_damage_done", "rank_category_general", "damage_done", ServerRanking.SHOW_POINTS, "character_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top DaΞ�οΏ½ΞΏΞ�Β½Ξ�Ξ�Ξ�οΏ½Ξ'Β½Ξ�οΏ½ΞΏΞ�Β½Ξ�Ξ�Ξ�οΏ½Ξ'Β½Ξ�οΏ½ΞΏΞ�Β½Ξ�Ξ�Ξ�οΏ½Ξ'Β½Ξ�οΏ½Ξ�οΏ½Ξ�οΏ½ΞΏΞ�Β½Ξ�’Ξ'Β½Ξ�οΏ½ΞΏΞ�Β½Ξ�Β²Ξ²β€�¬ββ€�Ξ†Ξ�οΏ½Ξ²β,¬β,,ΆΞ�’Ξ'Β½o Hecho
+	STAT_TOP_CLAN_MEMBERS_COUNT("rank_top_clan_members_count", "rank_category_clan", "clan_members_count", ServerRanking.SHOW_POINTS, "clan_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_UNIQUE), // Top Clan Members Count
+	STAT_TOP_CLAN_MEMBERS_RECRUITED("rank_top_clan_members_recruited", "rank_category_clan", "clan_members_recruited", ServerRanking.SHOW_POINTS, "clan_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Clan Members Recruited
+	STAT_TOP_CLAN_MEMBERS_WITHDREW("rank_top_clan_members_withdrew", "rank_category_clan", "clan_members_withdrew", ServerRanking.SHOW_POINTS, "clan_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Clan Members Withdrew
+	STAT_TOP_CLAN_FAME("rank_top_clan_fame", "rank_category_clan", "clan_fame", ServerRanking.SHOW_POINTS, "clan_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Clan Fame
+	STAT_TOP_CLAN_PVP_KILLS("rank_top_clan_pvp_kills", "rank_category_clan", "clan_pvp_kills", ServerRanking.SHOW_POINTS, "clan_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Clan PvP Kills
+	STAT_TOP_CLAN_WARS_WON("rank_top_clan_wars_won", "rank_category_clan", "clan_wars_won", ServerRanking.SHOW_POINTS, "clan_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE), // Top Clan Wars Won
+	STAT_TOP_CLAN_WARS_LOST("rank_top_clan_wars_lost", "rank_category_clan", "clan_wars_lost", ServerRanking.SHOW_POINTS, "clan_stats", ServerRanking.ORDER_DESC, ServerRanking.STAT_STACKABLE); // Top Clan Wars Lost
+	
+	public static final int STATS_SIZE = Ranking.values().length + 1;
+	
+	private final String _name;
+	private final String _category;
+	private final String _dbName;
+	private final boolean _mustShowPoints;
+	private final String _dbLocation;
+	private final boolean _isDescendent;
+	private final boolean _isStackable;
+	private final RankTime _time;
+	
+	private Ranking(String name, String category, String dbName, boolean mustShowPoints, String dbLocation, boolean isDescendent, boolean isStackable)
+	{
+		_name = name;
+		_category = category;
+		_dbName = dbName;
+		_mustShowPoints = mustShowPoints;
+		_dbLocation = dbLocation;
+		_isDescendent = isDescendent;
+		_isStackable = isStackable;
+		_time = RankTime.NONE;
+	}
+	
+	private Ranking(String name, String category, String dbName, boolean mustShowPoints, String dbLocation, boolean isDescendent, boolean isStackable, RankTime time)
+	{
+		_name = name;
+		_category = category;
+		_dbName = dbName;
+		_mustShowPoints = mustShowPoints;
+		_dbLocation = dbLocation;
+		_isDescendent = isDescendent;
+		_isStackable = isStackable;
+		_time = time;
+	}
+	
+	public int getTopId()
+	{
+		return ordinal();
+	}
+	
+	public String getTopName()
+	{
+		return _name;
+	}
+	
+	public String getCategory()
+	{
+		return _category;
+	}
+	
+	public String getDbName()
+	{
+		return _dbName;
+	}
+	
+	public boolean mustShowPoints()
+	{
+		return _mustShowPoints;
+	}
+	
+	public String getDbLocation()
+	{
+		return _dbLocation;
+	}
+	
+	public boolean isDescendent()
+	{
+		return _isDescendent;
+	}
+	
+	public boolean isStackable()
+	{
+		return _isStackable;
+	}
+	
+	public RankTime getTime()
+	{
+		return _time;
+	}
+	
+	public RankingInfo getRankingInfo()
+	{
+		return RankingHolder.getRankingInfo(getTopId());
+	}
+	
+	/**
+	 * Generates a ranking list into a map with RankingTop class
+	 */
+	public static void generateRankings()
+	{
+		// We must load ranking configs first
+		RankingConfig.load();
+		
+		for (Ranking rank : Ranking.values())
+		{
+			RankingHolder.addNewStat(rank.getTopId(), rank.getTopName(), rank.getCategory(), rank.getDbName(), rank.mustShowPoints(), rank.getDbLocation(), rank.isDescendent(), rank.isStackable(), rank.getTime());
+		}
+	}
+}
Index: java/l2r/gameserver/model/actor/L2Playable.java
===================================================================
--- java/l2r/gameserver/model/actor/L2Playable.java	(revision 122)
+++ java/l2r/gameserver/model/actor/L2Playable.java	(working copy)
@@ -36,6 +36,7 @@
 import l2r.gameserver.model.quest.QuestState;
 import l2r.gameserver.model.skills.L2Skill;
 import l2r.gameserver.network.serverpackets.EtcStatusUpdate;
+import gr.sr.rankEngine.templates.Ranking;
 
 /**
  * This class represents all Playable characters in the world.<br>
@@ -199,6 +200,12 @@
 			{
 				player.onKillUpdatePvPKarma(this);
 			}
+			
+			// Synerge - Add a new mob death to the stats
+			else if (isPlayer() && killer.isMonster())
+			{
+				getActingPlayer().addPlayerStats(Ranking.STAT_TOP_MOBS_DEATHS);
+			}
 		}
 		
 		// Notify L2Character AI

CitarDATA:

### Eclipse Workspace Patch 1.0
#P L2J_SunriseProject_Data
Index: dist/game/data/translation/Server Ranking.xml
===================================================================
--- dist/game/data/translation/Server Ranking.xml	(revision 0)
+++ dist/game/data/translation/Server Ranking.xml	(working copy)
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Server Ranking Messages -->
+<list>
+	<!-- Tabs -->
+	<message id="rank_tab_server_record">
+		<set lang="en" val="View Server Record" />
+		<set lang="es" val="Ver Records del Server" />
+	</message>
+	<message id="rank_tab_my_record">
+		<set lang="en" val="View My Record" />
+		<set lang="es" val="Ver Mi Record" />
+	</message>
+	<message id="rank_tab_category">
+		<set lang="en" val="Category" />
+		<set lang="es" val="Categoria" />
+	</message>
+	<message id="rank_tab_monthly_total">
+		<set lang="en" val="Monthly Total" />
+		<set lang="es" val="Total del Mes" />
+	</message>
+	<message id="rank_tab_total">
+		<set lang="en" val="Total" />
+		<set lang="es" val="Total" />
+	</message>
+	<message id="rank_tab_monthly_ranking">
+		<set lang="en" val="Monthly Rankings" />
+		<set lang="es" val="Rankings del Mes" />
+	</message>
+	<message id="rank_tab_total_ranking">
+		<set lang="en" val="Total Rankings" />
+		<set lang="es" val="Rankings Totales" />
+	</message>
+	
+	<!-- Categories -->
+	<message id="rank_category_combat">
+		<set lang="en" val="Combat" />
+		<set lang="es" val="Combate" />
+	</message>
+	<message id="rank_category_general">
+		<set lang="en" val="General" />
+		<set lang="es" val="General" />
+	</message>
+	<message id="rank_category_hunting">
+		<set lang="en" val="Hunting" />
+		<set lang="es" val="Hunting" />
+	</message>
+	<message id="rank_category_clan">
+		<set lang="en" val="Clan" />
+		<set lang="es" val="Clan" />
+	</message>
+	
+	<!-- Top Names -->
+	<message id="rank_top_pvpkills">
+		<set lang="en" val="PvP Kills" />
+		<set lang="es" val="PvP Kills" />
+	</message>
+	<message id="rank_top_pkkills">
+		<set lang="en" val="Pk Kills" />
+		<set lang="es" val="Pk Kills" />
+	</message>
+	<message id="rank_top_experience">
+		<set lang="en" val="Total Experience" />
+		<set lang="es" val="Experiencia Total" />
+	</message>
+	<message id="rank_top_pvpdeaths">
+		<set lang="en" val="PvP Deaths" />
+		<set lang="es" val="Muertes en PvP" />
+	</message>
+	<message id="rank_top_pkdeaths">
+		<set lang="en" val="Pk Deaths" />
+		<set lang="es" val="Muertes por Pk" />
+	</message>
+	<message id="rank_top_crafts_succeed">
+		<set lang="en" val="Successful Crafts" />
+		<set lang="es" val="Crafts Exitosos" />
+	</message>
+	<message id="rank_top_crafts_failed">
+		<set lang="en" val="Failed Crafts" />
+		<set lang="es" val="Crafts Fallidos" />
+	</message>
+	<message id="rank_top_onlinetime">
+		<set lang="en" val="Online Time" />
+		<set lang="es" val="Tiempo Online" />
+	</message>
+	<message id="rank_top_bsoes_used">
+		<set lang="en" val="Used BSOEs" />
+		<set lang="es" val="BSOEs Usados" />
+	</message>
+	<message id="rank_top_events_participated">
+		<set lang="en" val="Events Participated" />
+		<set lang="es" val="Eventos Participados" />
+	</message>
+	<message id="rank_top_siege_kills">
+		<set lang="en" val="Siege Kills" />
+		<set lang="es" val="Kills en Asedios" />
+	</message>
+	<message id="rank_top_siege_deaths">
+		<set lang="en" val="Siege Deaths" />
+		<set lang="es" val="Muertes en Asedios" />
+	</message>
+	<message id="rank_top_raids_killed">
+		<set lang="en" val="Raids Killed" />
+		<set lang="es" val="Raids Matados" />
+	</message>
+	<message id="rank_top_enchants_succeed">
+		<set lang="en" val="Successful Enchants" />
+		<set lang="es" val="Enchants Exitosos" />
+	</message>
+	<message id="rank_top_enchants_failed">
+		<set lang="en" val="Failed Enchants" />
+		<set lang="es" val="Enchants Fallidos" />
+	</message>
+	<message id="rank_top_fishes_captured">
+		<set lang="en" val="Fishes Captured" />
+		<set lang="es" val="Peces Capturados" />
+	</message>
+	<message id="rank_top_quests_finished">
+		<set lang="en" val="Quests Finished" />
+		<set lang="es" val="Quests Finalizadas" />
+	</message>
+	<message id="rank_top_arena_kills">
+		<set lang="en" val="Arena Kills" />
+		<set lang="es" val="Kills en Arena" />
+	</message>
+	<message id="rank_top_arena_deaths">
+		<set lang="en" val="Arena Deaths" />
+		<set lang="es" val="Muertes en Arena" />
+	</message>
+	<message id="rank_top_oly_kills">
+		<set lang="en" val="Olympiad Kills" />
+		<set lang="es" val="Combates de Olimpiadas Ganados" />
+	</message>
+	<message id="rank_top_oly_deaths">
+		<set lang="en" val="Olympiad Deaths" />
+		<set lang="es" val="Combates de Olimpiadas Perdidos" />
+	</message>
+	<message id="rank_top_mobs_kills">
+		<set lang="en" val="Mobs Kills" />
+		<set lang="es" val="Mobs Matados" />
+	</message>
+	<message id="rank_top_mobs_death">
+		<set lang="en" val="Mobs Deaths" />
+		<set lang="es" val="Muertes por Mobs" />
+	</message>
+	<message id="rank_top_duels_win">
+		<set lang="en" val="Duels Won" />
+		<set lang="es" val="Duelos Ganados" />
+	</message>
+	<message id="rank_top_duels_lost">
+		<set lang="en" val="Duels Lost" />
+		<set lang="es" val="Duelos Perdidos" />
+	</message>
+	<message id="rank_top_longest_online">
+		<set lang="en" val="Longest Online Time" />
+		<set lang="es" val="Tiempo Online mas Largo" />
+	</message>
+	<message id="rank_top_exp_acquired">
+		<set lang="en" val="Experience Acquired" />
+		<set lang="es" val="Experiencia Obtenida" />
+	</message>
+	<message id="rank_top_exp_lost">
+		<set lang="en" val="Experience Lost" />
+		<set lang="es" val="Experiencia Perdida" />
+	</message>
+	<message id="rank_top_adena_acquired">
+		<set lang="en" val="Adena Acquired" />
+		<set lang="es" val="Adena Obtenida" />
+	</message>
+	<message id="rank_top_fame_acquired">
+		<set lang="en" val="Fame Acquired" />
+		<set lang="es" val="Fama Obtenida" />
+	</message>
+	<message id="rank_top_damage_done">
+		<set lang="en" val="Damage Done" />
+		<set lang="es" val="Daño Realizado" />
+	</message>
+	<message id="rank_top_summon_kills">
+		<set lang="en" val="Summon Kills" />
+		<set lang="es" val="Summon Kills" />
+	</message>
+	<message id="rank_top_summon_deaths">
+		<set lang="en" val="Summon Deaths" />
+		<set lang="es" val="Summon Deaths" />
+	</message>
+	<message id="rank_top_treasure_box_opened">
+		<set lang="en" val="Treasure Box Opened" />
+		<set lang="es" val="Treasure Box Abiertos" />
+	</message>
+	<message id="rank_top_event_kills">
+		<set lang="en" val="Event Kills" />
+		<set lang="es" val="Kills en Eventos" />
+	</message>
+	<message id="rank_top_event_deaths">
+		<set lang="en" val="Event Deaths" />
+		<set lang="es" val="Muertes en Eventos" />
+	</message>
+	<message id="rank_top_siege_won">
+		<set lang="en" val="Sieges Won" />
+		<set lang="es" val="Asedios Ganados" />
+	</message>
+	<message id="rank_top_fortress_won">
+		<set lang="en" val="Fortress Won" />
+		<set lang="es" val="Fortress Capturados" />
+	</message>
+	<message id="rank_top_clan_members_count">
+		<set lang="en" val="Clan Members Count" />
+		<set lang="es" val="Cantidad de Miembros de Clan" />
+	</message>
+	<message id="rank_top_clan_members_recruited">
+		<set lang="en" val="Number of People Recruited" />
+		<set lang="es" val="Cantidad de Gente Reclutada" />
+	</message>
+	<message id="rank_top_clan_members_withdrew">
+		<set lang="en" val="Number of People that Withdrew" />
+		<set lang="es" val="Cantidad de Miembros que Abandonaron el Clan" />
+	</message>
+	<message id="rank_top_clan_fame">
+		<set lang="en" val="Clan Fame" />
+		<set lang="es" val="Fama de Clan" />
+	</message>
+	<message id="rank_top_clan_pvp_kills">
+		<set lang="en" val="Clan PvP Kills" />
+		<set lang="es" val="Clan PvP Kills" />
+	</message>
+	<message id="rank_top_clan_wars_won">
+		<set lang="en" val="Clan Wars Won" />
+		<set lang="es" val="Clan Wars Ganadas" />
+	</message>
+	<message id="rank_top_clan_wars_lost">
+		<set lang="en" val="Clan Wars Lost" />
+		<set lang="es" val="Clan Wars Perdidas" />
+	</message>
+</list>
\ No newline at end of file
Index: dist/game/data/html/CommunityBoard/elemental/ranking/playerRanking.htm
===================================================================
--- dist/game/data/html/CommunityBoard/elemental/ranking/playerRanking.htm	(revision 0)
+++ dist/game/data/html/CommunityBoard/elemental/ranking/playerRanking.htm	(working copy)
@@ -0,0 +1 @@
+<html><head><body scroll="no"><br1><table cellpadding=0><tr><td><button value="%rank_tab_server_record%" width=160 height=24 action="bypass _bbsrank" fore=L2UI_CT1.Tab_DF_Tab_Unselected back=L2UI_CT1.Tab_DF_Tab_Unselected_Over></td><td><button value="%rank_tab_my_record%" width=160 height=24 action="" fore=L2UI_CT1.Tab_DF_Tab_Selected back=L2UI_CT1.Tab_DF_Tab_Unselected_Over></td></tr></table><br><table border=0><tr><td width=165><table width=165 cellspacing=-8>%categorias%</table></td><td width=600><table width=600 height=26 cellpadding=-9><tr><td fixwidth=240 align=center><button value="%rank_tab_category%" width=240 height=32 action="" fore=L2UI_CT1.Button_DF_Calculator back=L2UI_CT1.Button_DF_Calculator></td><td fixwidth=180 align=center><button value="%rank_tab_monthly_total%" width=180 height=32 action="" fore=L2UI_CT1.Button_DF_Calculator back=L2UI_CT1.Button_DF_Calculator></td><td fixwidth=180 align=center><button value="%rank_tab_total%" width=180 height=32 action="" fore=L2UI_CT1.Button_DF_Calculator back=L2UI_CT1.Button_DF_Calculator></td></tr></table>%tablas%</td></tr></table></body></head></html>
\ No newline at end of file
Index: dist/game/data/scripts/handlers/itemhandlers/ItemSkillsTemplate.java
===================================================================
--- dist/game/data/scripts/handlers/itemhandlers/ItemSkillsTemplate.java	(revision 115)
+++ dist/game/data/scripts/handlers/itemhandlers/ItemSkillsTemplate.java	(working copy)
@@ -25,8 +25,10 @@
 import l2r.gameserver.model.items.instance.L2ItemInstance;
 import l2r.gameserver.model.items.type.ActionType;
 import l2r.gameserver.model.skills.L2Skill;
+import l2r.gameserver.model.skills.L2SkillType;
 import l2r.gameserver.network.SystemMessageId;
 import l2r.gameserver.network.serverpackets.SystemMessage;
+import gr.sr.rankEngine.templates.Ranking;
 
 /**
  * Template for item skills handler.
@@ -128,6 +130,12 @@
 						return false;
 					}
 					
+					// Synerge - Add a new BSOE used to the stats
+					if (itemSkill.getName().contains("Blessed") && (itemSkill.getSkillType() == L2SkillType.RECALL))
+					{
+						playable.getActingPlayer().addPlayerStats(Ranking.STAT_TOP_BSOES_USED);
+					}
+					
 					// Consume.
 					if ((itemSkill.getItemConsumeId() == 0) && (itemSkill.getItemConsumeCount() > 0))
 					{
Index: dist/game/data/html/CommunityBoard/elemental/ranking/serverRanking.htm
===================================================================
--- dist/game/data/html/CommunityBoard/elemental/ranking/serverRanking.htm	(revision 0)
+++ dist/game/data/html/CommunityBoard/elemental/ranking/serverRanking.htm	(working copy)
@@ -0,0 +1 @@
+<html><head><body scroll="no"><br1><table cellpadding=0><tr><td><button value="%rank_tab_server_record%" width=160 height=24 action="" fore=L2UI_CT1.Tab_DF_Tab_Selected back=L2UI_CT1.Tab_DF_Tab_Unselected_Over></td><td><button value="%rank_tab_my_record%" width=160 height=24 action="bypass _bbsrank;my;37" fore=L2UI_CT1.Tab_DF_Tab_Unselected back=L2UI_CT1.Tab_DF_Tab_Unselected_Over></td></tr></table><table border=0><tr><td width="260">%categorias%</td><td width="250"><button value="%rank_tab_monthly_ranking%" width=250 height=32 action="" fore=L2UI_CT1.Button_DF_Calculator back=L2UI_CT1.Button_DF_Calculator><table width=250 height=44 border=0 bgcolor="434416"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_1 width=16 height=32></td><td width=90 align=center>%mNombre1%<br1><font color=9f906a>%mCantidad1%</font></td><td width=40 valign=top align=center><img src=L2UI_CT1.Minimap_DF_ICN_TerritoryWar_Giran width=32 height=32></td></tr></table><table width=250 height=44 border=0 bgcolor="55534a"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_2 width=16 height=32></td><td width=90 align=center>%mNombre2%<br1><font color=9f906a>%mCantidad2%</font></td><td width=40 valign=top align=center><img src=L2UI_CT1.Minimap_DF_ICN_TerritoryWar_Innadril width=32 height=32></td></tr></table><table width=250 height=44 border=0 bgcolor="3b301a"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_3 width=16 height=32></td><td width=90 align=center>%mNombre3%<br1><font color=9f906a>%mCantidad3%</font></td><td width=40 valign=top align=center><img src=L2UI_CT1.Minimap_DF_ICN_TerritoryWar_Aden width=32 height=32></td></tr></table><table width=250 height=44 border=0 bgcolor="23221e"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_4 width=16 height=32></td><td width=90 align=center>%mNombre4%<br1><font color=9f906a>%mCantidad4%</font></td>    <td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="171612"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_5 width=16 height=32></td><td width=90 align=center>%mNombre5%<br1><font color=9f906a>%mCantidad5%</font></td><td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="23221e"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_6 width=16 height=32></td><td width=90 align=center>%mNombre6%<br1><font color=9f906a>%mCantidad6%</font></td><td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="171612"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_7 width=16 height=32></td><td width=90 align=center>%mNombre7%<br1><font color=9f906a>%mCantidad7%</font></td><td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="23221e"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_8 width=16 height=32></td><td width=90 align=center>%mNombre8%<br1><font color=9f906a>%mCantidad8%</font></td><td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="171612"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_9 width=16 height=32></td><td width=90 align=center>%mNombre9%<br1><font color=9f906a>%mCantidad9%</font></td><td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="23221e"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=20 align=right><img src=L2UI_CT1.MiniGame_DF_Text_Score_1 width=16 height=32></td><td width=20><img src=L2UI_CT1.MiniGame_DF_Text_Score_0 width=16 height=32></td><td width=90 align=center>%mNombre10%<br1><font color=9f906a>%mCantidad10%</font></td><td width=40 valign=top align=center></td></tr></table></td><td width="250"><button value="%rank_tab_total_ranking%" width=250 height=32 action="" fore=L2UI_CT1.Button_DF_Calculator back=L2UI_CT1.Button_DF_Calculator><table width=250 height=44 border=0 bgcolor="434416"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_1 width=16 height=32></td><td width=90 align=center>%tNombre1%<br1><font color=9f906a>%tCantidad1%</font></td><td width=40 valign=top align=center><img src=L2UI_CT1.Minimap_DF_ICN_TerritoryWar_Giran width=32 height=32></td></tr></table><table width=250 height=44 border=0 bgcolor="55534a"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_2 width=16 height=32></td><td width=90 align=center>%tNombre2%<br1><font color=9f906a>%tCantidad2%</font></td><td width=40 valign=top align=center><img src=L2UI_CT1.Minimap_DF_ICN_TerritoryWar_Innadril width=32 height=32></td></tr></table><table width=250 height=44 border=0 bgcolor="3b301a"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_3 width=16 height=32></td><td width=90 align=center>%tNombre3%<br1><font color=9f906a>%tCantidad3%</font></td><td width=40 valign=top align=center><img src=L2UI_CT1.Minimap_DF_ICN_TerritoryWar_Aden width=32 height=32></td></tr></table><table width=250 height=44 border=0 bgcolor="23221e"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_4 width=16 height=32></td><td width=90 align=center>%tNombre4%<br1><font color=9f906a>%tCantidad4%</font></td>    <td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="171612"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_5 width=16 height=32></td><td width=90 align=center>%tNombre5%<br1><font color=9f906a>%tCantidad5%</font></td><td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="23221e"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_6 width=16 height=32></td><td width=90 align=center>%tNombre6%<br1><font color=9f906a>%tCantidad6%</font></td><td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="171612"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_7 width=16 height=32></td><td width=90 align=center>%tNombre7%<br1><font color=9f906a>%tCantidad7%</font></td><td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="23221e"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_8 width=16 height=32></td><td width=90 align=center>%tNombre8%<br1><font color=9f906a>%tCantidad8%</font></td><td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="171612"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=40 align=center><img src=L2UI_CT1.MiniGame_DF_Text_Score_9 width=16 height=32></td><td width=90 align=center>%tNombre9%<br1><font color=9f906a>%tCantidad9%</font></td><td width=40 valign=top align=center></td></tr></table><table width=250 height=44 border=0 bgcolor="23221e"><tr><td width=20><img src=L2UI_CT1.Gauge_DF_Attribute_Earth width=16 height=8></td><td width=20 align=right><img src=L2UI_CT1.MiniGame_DF_Text_Score_1 width=16 height=32></td><td width=20><img src=L2UI_CT1.MiniGame_DF_Text_Score_0 width=16 height=32></td><td width=90 align=center>%tNombre10%<br1><font color=9f906a>%tCantidad10%</font></td><td width=40 valign=top align=center></td></tr></table></td></tr></table></body></head></html>
\ No newline at end of file

CitarSQL:

-- Table for clan stats

CREATE TABLE IF NOT EXISTS `clan_stats` (
  `clanId` INT UNSIGNED NOT NULL DEFAULT 0,
  `variable` VARCHAR(255) NOT NULL,
  `value` BIGINT UNSIGNED NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- Table for monthly character and clan stats

CREATE TABLE IF NOT EXISTS `monthly_character_stats` (
  `charId` INT UNSIGNED NOT NULL DEFAULT 0,
  `variable` VARCHAR(255) NOT NULL,
  `value` BIGINT UNSIGNED NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- Table for character stats

CREATE TABLE IF NOT EXISTS `character_stats` (
  `charId` INT UNSIGNED NOT NULL DEFAULT 0,
  `variable` VARCHAR(255) NOT NULL,
  `value` BIGINT UNSIGNED NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8;