U3Games

Games | Desarrollo & Soporte => L2 | Implementaciones => L2 | Sección de Servidores => Lineage => L2 | Community Board => Mensaje iniciado por: Swarlog en Jul 29, 2025, 12:00 AM

Título: Community Board Rank Engine
Publicado por: Swarlog en Jul 29, 2025, 12:00 AM
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;