diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminPremium.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminPremium.java index e2457ea600..8e0358ffc7 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminPremium.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminPremium.java @@ -17,6 +17,7 @@ package handlers.admincommandhandlers; import java.text.SimpleDateFormat; +import java.util.concurrent.TimeUnit; import com.l2jmobius.Config; import com.l2jmobius.gameserver.cache.HtmCache; @@ -118,15 +119,21 @@ public class AdminPremium implements IAdminCommandHandler } // TODO: Add check if account exists XD - PremiumManager.getInstance().addPremiumMonths(months, accountName); - admin.sendMessage("Account " + accountName + " will now have premium status until " + new SimpleDateFormat("dd.MM.yyyy HH:mm").format(PremiumManager.getInstance().getPremiumEndDate(accountName)) + "."); + PremiumManager.getInstance().addPremiumTime(accountName, months * 30, TimeUnit.DAYS); + admin.sendMessage("Account " + accountName + " will now have premium status until " + new SimpleDateFormat("dd.MM.yyyy HH:mm").format(PremiumManager.getInstance().getPremiumExpiration(accountName)) + "."); } private void viewPremiumInfo(L2PcInstance admin, String accountName) { - if (PremiumManager.getInstance().getPremiumEndDate(accountName) > 0) + if (!Config.PREMIUM_SYSTEM_ENABLED) { - admin.sendMessage("Account " + accountName + " has premium status until " + new SimpleDateFormat("dd.MM.yyyy HH:mm").format(PremiumManager.getInstance().getPremiumEndDate(accountName)) + "."); + admin.sendMessage("Premium system is disabled."); + return; + } + + if (PremiumManager.getInstance().getPremiumExpiration(accountName) > 0) + { + admin.sendMessage("Account " + accountName + " has premium status until " + new SimpleDateFormat("dd.MM.yyyy HH:mm").format(PremiumManager.getInstance().getPremiumExpiration(accountName)) + "."); } else { @@ -136,7 +143,13 @@ public class AdminPremium implements IAdminCommandHandler private void removePremium(L2PcInstance admin, String accountName) { - if (PremiumManager.getInstance().getPremiumEndDate(accountName) > 0) + if (!Config.PREMIUM_SYSTEM_ENABLED) + { + admin.sendMessage("Premium system is disabled."); + return; + } + + if (PremiumManager.getInstance().getPremiumExpiration(accountName) > 0) { PremiumManager.getInstance().removePremiumStatus(accountName); admin.sendMessage("Account " + accountName + " has no longer premium status."); diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/communityboard/HomeBoard.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/communityboard/HomeBoard.java index 77fe452d4c..b5b294ab82 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/communityboard/HomeBoard.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/communityboard/HomeBoard.java @@ -20,6 +20,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.text.SimpleDateFormat; +import java.util.concurrent.TimeUnit; import com.l2jmobius.Config; import com.l2jmobius.commons.database.DatabaseFactory; @@ -242,8 +243,8 @@ public final class HomeBoard implements IParseBoardHandler else { activeChar.destroyItemByItemId("CB_Premium", Config.COMMUNITY_PREMIUM_COIN_ID, Config.COMMUNITY_PREMIUM_PRICE_PER_DAY * premiumDays, activeChar, true); - PremiumManager.getInstance().addPremiumDays(premiumDays, activeChar.getAccountName()); - activeChar.sendMessage("Your account will now have premium status until " + new SimpleDateFormat("dd.MM.yyyy HH:mm").format(PremiumManager.getInstance().getPremiumEndDate(activeChar.getAccountName())) + "."); + PremiumManager.getInstance().addPremiumTime(activeChar.getAccountName(), premiumDays, TimeUnit.DAYS); + activeChar.sendMessage("Your account will now have premium status until " + new SimpleDateFormat("dd.MM.yyyy HH:mm").format(PremiumManager.getInstance().getPremiumExpiration(activeChar.getAccountName())) + "."); CommunityBoardHandler.separateAndSend(HtmCache.getInstance().getHtm(activeChar.getHtmlPrefix(), "data/html/CommunityBoard/Custom/premium/thankyou.html"), activeChar); } } diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/voicedcommandhandlers/Premium.java b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/voicedcommandhandlers/Premium.java index 1089903af3..7b1bcbfc56 100644 --- a/L2J_Mobius_Underground/dist/game/data/scripts/handlers/voicedcommandhandlers/Premium.java +++ b/L2J_Mobius_Underground/dist/game/data/scripts/handlers/voicedcommandhandlers/Premium.java @@ -37,7 +37,7 @@ public class Premium implements IVoicedCommandHandler if (command.startsWith("premium") && Config.PREMIUM_SYSTEM_ENABLED) { final SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy HH:mm"); - final long endDate = PremiumManager.getInstance().getPremiumEndDate(activeChar.getAccountName()); + final long endDate = PremiumManager.getInstance().getPremiumExpiration(activeChar.getAccountName()); final NpcHtmlMessage msg = new NpcHtmlMessage(5); final StringBuilder html = new StringBuilder(); if (endDate == 0) diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/GameServer.java index 463e02f4a2..7b87fa47b2 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/GameServer.java @@ -264,11 +264,12 @@ public class GameServer { FactionManager.getInstance(); } + if (Config.PREMIUM_SYSTEM_ENABLED) { - LOGGER.info("PremiumManager: Premium system is enabled."); PremiumManager.getInstance(); } + printSection("Clans"); ClanTable.getInstance(); ResidenceFunctionsData.getInstance(); diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/instancemanager/PremiumManager.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/instancemanager/PremiumManager.java index 0ca1ac9582..ee36b8ead9 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/instancemanager/PremiumManager.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/instancemanager/PremiumManager.java @@ -20,142 +20,204 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.logging.Logger; -import com.l2jmobius.Config; import com.l2jmobius.commons.database.DatabaseFactory; +import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.events.Containers; +import com.l2jmobius.gameserver.model.events.EventType; +import com.l2jmobius.gameserver.model.events.ListenersContainer; +import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogin; +import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogout; +import com.l2jmobius.gameserver.model.events.listeners.ConsumerEventListener; +import com.l2jmobius.gameserver.network.serverpackets.ExBrPremiumState; /** * @author Mobius */ public class PremiumManager { - public long getPremiumEndDate(String accountName) + private final static Logger LOGGER = Logger.getLogger(PremiumManager.class.getName()); + + // SQL Statement + private final static String LOAD_SQL = "SELECT account_name,enddate FROM account_premium"; + private final static String UPDATE_SQL = "UPDATE account_premium SET enddate = ? WHERE account_name = ?"; + private final static String ADD_SQL = "INSERT INTO account_premium (endate,account_name) VALUE (?,?)"; + + class PremiumExpireTask implements Runnable { - long endDate = 0; + final L2PcInstance player; - try (Connection con = DatabaseFactory.getInstance().getConnection()) + PremiumExpireTask(L2PcInstance player) + { + this.player = player; + } + + @Override + public void run() + { + player.setPremiumStatus(false); + player.sendPacket(new ExBrPremiumState(player)); + } + } + + // Data Cache + private final Map premiumData = new HashMap<>(); + + // expireTasks + private final Map> expiretasks = new HashMap<>(); + + // Listeners + private final ListenersContainer listenerContainer = Containers.Players(); + + private final Consumer playerLoginEvent = (event) -> + { + final L2PcInstance player = event.getActiveChar(); + final String accountName = player.getAccountName(); + final long now = System.currentTimeMillis(); + final long premiumExpiration = getPremiumExpiration(accountName); + player.setPremiumStatus(premiumExpiration > now); + player.sendPacket(new ExBrPremiumState(player)); + + if (player.hasPremiumStatus()) + { + startExpireTask(player, premiumExpiration - now); + } + }; + + private final Consumer playerLogoutEvent = (event) -> + { + L2PcInstance player = event.getActiveChar(); + stopExpireTask(player); + }; + + protected PremiumManager() + { + loadPremiumData(); + listenerContainer.addListener(new ConsumerEventListener(listenerContainer, EventType.ON_PLAYER_LOGIN, playerLoginEvent, this)); + listenerContainer.addListener(new ConsumerEventListener(listenerContainer, EventType.ON_PLAYER_LOGOUT, playerLogoutEvent, this)); + } + + /** + * @param player + * @param delay + */ + private void startExpireTask(L2PcInstance player, long delay) + { + ScheduledFuture task = ThreadPoolManager.getInstance().scheduleEvent(new PremiumExpireTask(player), delay); + expiretasks.put(player.getAccountName(), task); + } + + /** + * @param player + */ + private void stopExpireTask(L2PcInstance player) + { + ScheduledFuture task = expiretasks.remove(player.getAccountName()); + if (task != null) + { + task.cancel(false); + task = null; + } + } + + private void loadPremiumData() + { + try (Connection con = DatabaseFactory.getInstance().getConnection(); + PreparedStatement statement = con.prepareStatement(LOAD_SQL); + ResultSet rset = statement.executeQuery()) { - final PreparedStatement statement = con.prepareStatement("SELECT premium_service,enddate FROM account_premium WHERE account_name=?"); - statement.setString(1, accountName); - final ResultSet rset = statement.executeQuery(); while (rset.next()) { - if (Config.PREMIUM_SYSTEM_ENABLED) - { - endDate = rset.getLong("enddate"); - if (endDate <= System.currentTimeMillis()) - { - endDate = 0; - removePremiumStatus(accountName); - } - } + premiumData.put(rset.getString(1), rset.getLong(2)); } - statement.close(); - } - catch (Exception e) - { - } - - return endDate; - } - - public void addPremiumDays(int days, String accountName) - { - long remainingTime = getPremiumEndDate(accountName); - if (remainingTime > 0) - { - remainingTime -= System.currentTimeMillis(); - } - - try (Connection con = DatabaseFactory.getInstance().getConnection()) - { - final Calendar endDate = Calendar.getInstance(); - endDate.setTimeInMillis(System.currentTimeMillis() + remainingTime); - endDate.set(Calendar.SECOND, 0); - endDate.add(Calendar.HOUR, 24 * days); - - final PreparedStatement statement = con.prepareStatement("UPDATE account_premium SET premium_service=?,enddate=? WHERE account_name=?"); - statement.setInt(1, 1); - statement.setLong(2, endDate.getTimeInMillis()); - statement.setString(3, accountName); - statement.execute(); - statement.close(); } catch (SQLException e) { + e.printStackTrace(); } - for (L2PcInstance player : L2World.getInstance().getPlayers()) - { - if (player.getAccountNamePlayer().equalsIgnoreCase(accountName)) - { - player.setPremiumStatus(getPremiumEndDate(accountName) > 0); - } - } + long expiredData = premiumData.values().stream().filter(d -> d < System.currentTimeMillis()).count(); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + premiumData.size() + " premium data (" + expiredData + " have expired)"); } - public void addPremiumMonths(int months, String accountName) + public long getPremiumExpiration(String accountName) { - long remainingTime = getPremiumEndDate(accountName); - if (remainingTime > 0) - { - remainingTime -= System.currentTimeMillis(); - } + return premiumData.getOrDefault(accountName, 0L); + } + + public void addPremiumTime(String accountName, int timeValue, TimeUnit timeUnit) + { + long addTime = timeUnit.toMillis(timeValue); + long now = System.currentTimeMillis(); + // new premium task at least from now + long oldPremiumExpiration = Math.max(now, getPremiumExpiration(accountName)); + long newPremiumExpiration = oldPremiumExpiration + addTime; - try (Connection con = DatabaseFactory.getInstance().getConnection()) + String sqlCmd = premiumData.containsKey(accountName) ? UPDATE_SQL : ADD_SQL; + + // UPDATE DATABASE + try (Connection con = DatabaseFactory.getInstance().getConnection(); + PreparedStatement stmt = con.prepareStatement(sqlCmd)) { - final Calendar endDate = Calendar.getInstance(); - endDate.setTimeInMillis(System.currentTimeMillis() + remainingTime); - endDate.set(Calendar.SECOND, 0); - endDate.add(Calendar.MONTH, months); - - final PreparedStatement statement = con.prepareStatement("UPDATE account_premium SET premium_service=?,enddate=? WHERE account_name=?"); - statement.setInt(1, 1); - statement.setLong(2, endDate.getTimeInMillis()); - statement.setString(3, accountName); - statement.execute(); - statement.close(); + stmt.setLong(1, newPremiumExpiration); + stmt.setString(2, accountName); + stmt.execute(); } catch (SQLException e) { + e.printStackTrace(); } - for (L2PcInstance player : L2World.getInstance().getPlayers()) + // UPDATE CACHE + premiumData.put(accountName, newPremiumExpiration); + + // UPDATE PlAYER PREMIUMSTATUS + L2PcInstance playerOnline = L2World.getInstance().getPlayers().stream().filter(p -> accountName.equals(p.getAccountName())).findFirst().orElse(null); + if (playerOnline != null) { - if (player.getAccountNamePlayer().equalsIgnoreCase(accountName)) + stopExpireTask(playerOnline); + startExpireTask(playerOnline, newPremiumExpiration - now); + + if (!playerOnline.hasPremiumStatus()) { - player.setPremiumStatus(getPremiumEndDate(accountName) > 0); + playerOnline.setPremiumStatus(true); + playerOnline.sendPacket(new ExBrPremiumState(playerOnline)); } } } public void removePremiumStatus(String accountName) { - // TODO: Add check if account exists. XD - try (Connection con = DatabaseFactory.getInstance().getConnection()) + L2PcInstance playerOnline = L2World.getInstance().getPlayers().stream().filter(p -> accountName.equals(p.getAccountName())).findFirst().orElse(null); + if ((playerOnline != null) && playerOnline.hasPremiumStatus()) { - final PreparedStatement statement = con.prepareStatement("INSERT INTO account_premium (account_name,premium_service,enddate) values(?,?,?) ON DUPLICATE KEY UPDATE premium_service = ?, enddate = ?"); - statement.setString(1, accountName); - statement.setInt(2, 0); - statement.setLong(3, 0); - statement.setInt(4, 0); - statement.setLong(5, 0); - statement.execute(); - statement.close(); + playerOnline.setPremiumStatus(false); + playerOnline.sendPacket(new ExBrPremiumState(playerOnline)); + stopExpireTask(playerOnline); + } + + // UPDATE CACHE + premiumData.remove(accountName); + + // UPDATE DATABASE + try (Connection con = DatabaseFactory.getInstance().getConnection(); + PreparedStatement stmt = con.prepareStatement(UPDATE_SQL)) + { + stmt.setLong(1, 0L); + stmt.setString(2, accountName); + stmt.execute(); } catch (SQLException e) { - } - - for (L2PcInstance player : L2World.getInstance().getPlayers()) - { - if (player.getAccountNamePlayer().equalsIgnoreCase(accountName)) - { - player.setPremiumStatus(false); - } + e.printStackTrace(); } } diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index 204bc89632..07a3a60646 100644 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -113,7 +113,6 @@ import com.l2jmobius.gameserver.instancemanager.HandysBlockCheckerManager; import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; import com.l2jmobius.gameserver.instancemanager.MatchingRoomManager; import com.l2jmobius.gameserver.instancemanager.MentorManager; -import com.l2jmobius.gameserver.instancemanager.PremiumManager; import com.l2jmobius.gameserver.instancemanager.PunishmentManager; import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.SiegeManager; @@ -369,9 +368,6 @@ public final class L2PcInstance extends L2Playable private static final String UPDATE_CHARACTER_ACCESS = "UPDATE characters SET accesslevel = ? WHERE charId = ?"; private static final String RESTORE_CHARACTER = "SELECT * FROM characters WHERE charId=?"; - // Character Premium System String Definitions: - private static final String RESTORE_PREMIUMSERVICE = "SELECT premium_service,enddate FROM account_premium WHERE account_name=?"; - // Character Teleport Bookmark: private static final String INSERT_TP_BOOKMARK = "INSERT INTO character_tpbookmark (charId,Id,x,y,z,icon,tag,name) values (?,?,?,?,?,?,?,?)"; private static final String UPDATE_TP_BOOKMARK = "UPDATE character_tpbookmark SET icon=?,tag=?,name=? where charId=? AND Id=?"; @@ -6490,7 +6486,6 @@ public final class L2PcInstance extends L2Playable player = new L2PcInstance(objectId, template, rset.getString("account_name"), app); player.setName(rset.getString("char_name")); - restorePremiumSystemData(player, rset.getString("account_name")); player.setLastAccess(rset.getLong("lastAccess")); player.getStat().setExp(rset.getLong("exp")); @@ -12876,48 +12871,6 @@ public final class L2PcInstance extends L2Playable return Config.PREMIUM_SYSTEM_ENABLED && _premiumStatus; } - private static void restorePremiumSystemData(L2PcInstance player, String account) - { - boolean success = false; - try (Connection con = DatabaseFactory.getInstance().getConnection()) - { - final PreparedStatement ps = con.prepareStatement(RESTORE_PREMIUMSERVICE); - ps.setString(1, account); - final ResultSet rs = ps.executeQuery(); - while (rs.next()) - { - success = true; - if (Config.PREMIUM_SYSTEM_ENABLED) - { - if (rs.getLong("enddate") <= System.currentTimeMillis()) - { - PremiumManager.getInstance().removePremiumStatus(account); - player.setPremiumStatus(false); - } - else - { - player.setPremiumStatus(rs.getBoolean("premium_service")); - } - } - else - { - player.setPremiumStatus(false); - } - } - ps.close(); - } - catch (Exception e) - { - _log.warning("Premium System: Could not restore premium system data for " + account + "." + e); - e.printStackTrace(); - } - if (!success) - { - PremiumManager.getInstance().removePremiumStatus(player.getAccountName()); - player.setPremiumStatus(false); - } - } - public void setLastPetitionGmName(String gmName) { _lastPetitionGmName = gmName; diff --git a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/network/serverpackets/PremiumState.java b/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/network/serverpackets/PremiumState.java deleted file mode 100644 index e359a10543..0000000000 --- a/L2J_Mobius_Underground/java/com/l2jmobius/gameserver/network/serverpackets/PremiumState.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of the L2J Mobius project. - * - * 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 . - */ -package com.l2jmobius.gameserver.network.serverpackets; - -import com.l2jmobius.commons.network.PacketWriter; -import com.l2jmobius.gameserver.network.client.OutgoingPackets; - -/** - * @author GodKratos - */ -public class PremiumState implements IClientOutgoingPacket -{ - private final int _objectId; - private final int _state; - - public PremiumState(int objectId, int state) - { - _objectId = objectId; - _state = state; - } - - @Override - public boolean write(PacketWriter packet) - { - OutgoingPackets.EX_NOTICE_POST_ARRIVED.writeId(packet); - - packet.writeD(_objectId); - packet.writeC(_state); - return true; - } -}