diff --git a/L2J_Mobius_1.0_Ertheia/build.xml b/L2J_Mobius_1.0_Ertheia/build.xml index 245dcde99c..929e117286 100644 --- a/L2J_Mobius_1.0_Ertheia/build.xml +++ b/L2J_Mobius_1.0_Ertheia/build.xml @@ -78,8 +78,8 @@ - - + + @@ -93,8 +93,8 @@ - - + + @@ -108,8 +108,8 @@ - - + + @@ -123,8 +123,8 @@ - - + + diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/GameServer.bat b/L2J_Mobius_1.0_Ertheia/dist/game/GameServer.bat deleted file mode 100644 index 2dbaac7089..0000000000 --- a/L2J_Mobius_1.0_Ertheia/dist/game/GameServer.bat +++ /dev/null @@ -1,30 +0,0 @@ -@set /p parameters=. + */ +package com.l2jmobius.commons.util; + +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; + +/* + * A class to control the maximum number of lines to be stored in a Document + * + * Excess lines can be removed from the start or end of the Document + * depending on your requirement. + * + * a) if you append text to the Document, then you would want to remove lines + * from the start. + * b) if you insert text at the beginning of the Document, then you would + * want to remove lines from the end. + */ +public class LimitLinesDocumentListener implements DocumentListener +{ + private int _maximumLines; + private final boolean _isRemoveFromStart; + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start of the Document. + */ + public LimitLinesDocumentListener(int maximumLines) + { + this(maximumLines, true); + } + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start or end of the Document, depending on the boolean value specified. + */ + public LimitLinesDocumentListener(int maximumLines, boolean isRemoveFromStart) + { + setLimitLines(maximumLines); + _isRemoveFromStart = isRemoveFromStart; + } + + /* + * Return the maximum number of lines to be stored in the Document. + */ + public int getLimitLines() + { + return _maximumLines; + } + + /* + * Set the maximum number of lines to be stored in the Document. + */ + public void setLimitLines(int maximumLines) + { + if (maximumLines < 1) + { + String message = "Maximum lines must be greater than 0"; + throw new IllegalArgumentException(message); + } + + _maximumLines = maximumLines; + } + + /* + * Handle insertion of new text into the Document. + */ + @Override + public void insertUpdate(final DocumentEvent e) + { + // Changes to the Document can not be done within the listener so we need to add the processing to the end of the EDT. + SwingUtilities.invokeLater(() -> removeLines(e)); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + } + + @Override + public void changedUpdate(DocumentEvent e) + { + } + + /* + * Remove lines from the Document when necessary. + */ + private void removeLines(DocumentEvent e) + { + // The root Element of the Document will tell us the total number of line in the Document. + Document document = e.getDocument(); + Element root = document.getDefaultRootElement(); + + while (root.getElementCount() > _maximumLines) + { + if (_isRemoveFromStart) + { + removeFromStart(document, root); + } + else + { + removeFromEnd(document, root); + } + } + } + + /* + * Remove lines from the start of the Document + */ + private void removeFromStart(Document document, Element root) + { + Element line = root.getElement(0); + int end = line.getEndOffset(); + + try + { + document.remove(0, end); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } + + /* + * Remove lines from the end of the Document + */ + private void removeFromEnd(Document document, Element root) + { + // We use start minus 1 to make sure we remove the newline character of the previous line. + + Element line = root.getElement(root.getElementCount() - 1); + int start = line.getStartOffset(); + int end = line.getEndOffset(); + + try + { + document.remove(start - 1, end - start); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/commons/util/SplashScreen.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/commons/util/SplashScreen.java index 80992f1b4d..5086e53e9c 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/commons/util/SplashScreen.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/commons/util/SplashScreen.java @@ -21,8 +21,8 @@ import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Timer; +import java.util.TimerTask; import javax.swing.ImageIcon; import javax.swing.JFrame; @@ -52,22 +52,24 @@ public class SplashScreen extends JWindow setAlwaysOnTop(true); setVisible(true); - // Schedule to close. - Executors.newScheduledThreadPool(1).schedule(this::close, imageIcon.getIconWidth() > 0 ? time : 100, TimeUnit.MILLISECONDS); - } - - public void close() - { - setVisible(false); - if (parentFrame != null) + new Timer().schedule(new TimerTask() { - // Make parent visible. - parentFrame.setVisible(true); - // Focus parent window. - parentFrame.toFront(); - parentFrame.setState(Frame.ICONIFIED); - parentFrame.setState(Frame.NORMAL); - } + @Override + public void run() + { + setVisible(false); + if (parentFrame != null) + { + // Make parent visible. + parentFrame.setVisible(true); + // Focus parent window. + parentFrame.toFront(); + parentFrame.setState(Frame.ICONIFIED); + parentFrame.setState(Frame.NORMAL); + } + dispose(); + } + }, imageIcon.getIconWidth() > 0 ? time : 100); } @Override diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java index 9545157efd..330ae1c73d 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.gameserver; +import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.io.File; import java.io.FileInputStream; @@ -145,6 +146,7 @@ import com.l2jmobius.gameserver.network.loginserver.LoginServerNetworkManager; import com.l2jmobius.gameserver.network.telnet.TelnetServer; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.taskmanager.TaskManager; +import com.l2jmobius.gameserver.ui.Gui; import com.l2jmobius.gameserver.util.Broadcast; public class GameServer @@ -168,6 +170,28 @@ public class GameServer public GameServer() throws Exception { final long serverLoadStart = System.currentTimeMillis(); + Server.serverMode = Server.MODE_GAMESERVER; + + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + + // Create log folder + final File logFolder = new File(Config.DATAPACK_ROOT, "log"); + logFolder.mkdir(); + + // Create input stream for log file -- or store file data into memory + try (InputStream is = new FileInputStream(new File("./log.cfg"))) + { + LogManager.getLogManager().readConfiguration(is); + } + + // Initialize config + Config.load(); + printSection("Database"); + DatabaseFactory.getInstance(); printSection("ThreadPool"); ThreadPool.init(); @@ -451,24 +475,6 @@ public class GameServer public static void main(String[] args) throws Exception { - Server.serverMode = Server.MODE_GAMESERVER; - - /*** Main ***/ - // Create log folder - final File logFolder = new File(Config.DATAPACK_ROOT, "log"); - logFolder.mkdir(); - - // Create input stream for log file -- or store file data into memory - try (InputStream is = new FileInputStream(new File("./log.cfg"))) - { - LogManager.getLogManager().readConfiguration(is); - } - - // Initialize config - Config.load(); - printSection("Database"); - DatabaseFactory.getInstance(); - INSTANCE = new GameServer(); } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java index 9a1a01c8a6..625915e123 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java @@ -28,6 +28,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.gameserver.LoginServerThread; import com.l2jmobius.gameserver.enums.PrivateStoreType; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.L2ManufactureItem; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.TradeItem; @@ -298,6 +299,7 @@ public class OfflineTradersTable player.setOnlineStatus(true, true); player.restoreEffects(); player.broadcastUserInfo(); + PlayerCountManager.getInstance().incOfflineTradeCount(); nTraders++; } catch (Exception e) @@ -451,6 +453,8 @@ public class OfflineTradersTable public static synchronized void removeTrader(int traderObjId) { + PlayerCountManager.getInstance().decOfflineTradeCount(); + try (Connection con = DatabaseFactory.getInstance().getConnection(); PreparedStatement stm1 = con.prepareStatement(CLEAR_OFFLINE_TABLE_ITEMS_PLAYER); PreparedStatement stm2 = con.prepareStatement(CLEAR_OFFLINE_TABLE_PLAYER)) diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java new file mode 100644 index 0000000000..cb2fab84ed --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java @@ -0,0 +1,77 @@ +/* + * 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.instancemanager; + +/** + * @author Mobius + */ +public class PlayerCountManager +{ + private volatile static int connectedCount = 0; + private volatile static int maxConnectedCount = 0; + private volatile static int offlineTradeCount = 0; + + protected PlayerCountManager() + { + } + + public int getConnectedCount() + { + return connectedCount; + } + + public int getMaxConnectedCount() + { + return maxConnectedCount; + } + + public int getOfflineTradeCount() + { + return offlineTradeCount; + } + + public synchronized void incConnectedCount() + { + connectedCount++; + maxConnectedCount = Math.max(maxConnectedCount, connectedCount); + } + + public void decConnectedCount() + { + connectedCount--; + } + + public void incOfflineTradeCount() + { + offlineTradeCount++; + } + + public synchronized void decOfflineTradeCount() + { + offlineTradeCount = Math.max(0, offlineTradeCount - 1); + } + + public static PlayerCountManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final PlayerCountManager INSTANCE = new PlayerCountManager(); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2World.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2World.java index 9b02364b07..bea222354b 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2World.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2World.java @@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -135,6 +136,8 @@ public final class L2World if (object.isPlayer()) { + PlayerCountManager.getInstance().incConnectedCount(); + final L2PcInstance newPlayer = (L2PcInstance) object; if (newPlayer.isTeleporting()) // TODO: drop when we stop removing player from the world while teleporting. { @@ -170,6 +173,8 @@ public final class L2World _allObjects.remove(object.getObjectId()); if (object.isPlayer()) { + PlayerCountManager.getInstance().decConnectedCount(); + final L2PcInstance player = (L2PcInstance) object; if (player.isTeleporting()) // TODO: drop when we stop removing player from the world while teleportingq. { diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/Gui.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/Gui.java new file mode 100644 index 0000000000..9f8c2a41a6 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/Gui.java @@ -0,0 +1,370 @@ +/* + * 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.ui; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.gameserver.Shutdown; +import com.l2jmobius.gameserver.cache.HtmCache; +import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.BuyListData; +import com.l2jmobius.gameserver.data.xml.impl.MultisellData; +import com.l2jmobius.gameserver.data.xml.impl.PrimeShopData; +import com.l2jmobius.gameserver.util.Broadcast; +import com.l2jmobius.gameserver.util.Util; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmGameServer; + JTextArea txtrConsole; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + final static String[] abortOptions = + { + "Abort", + "Cancel" + }; + final static String[] confirmOptions = + { + "Confirm", + "Cancel" + }; + + public Gui() + { + frmGameServer = new JFrame(); + frmGameServer.setVisible(false); + frmGameServer.setTitle("Mobius - GameServer"); + frmGameServer.setResizable(false); + frmGameServer.setBounds(100, 100, 825, 618); + frmGameServer.getContentPane().setLayout(null); + frmGameServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmGameServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown server immediately?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + Shutdown.getInstance().startShutdown(null, 1, false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmGameServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmGameServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Shutdown delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, false); + } + } + } + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Restart delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, true); + } + } + } + } + }); + mnActions.add(mntmRestart); + + JMenuItem mntmAbort = new JMenuItem("Abort"); + mntmAbort.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbort.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Abort server shutdown?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, abortOptions, abortOptions[1]) == 0) + { + Shutdown.getInstance().abort(null); + } + }); + mnActions.add(mntmAbort); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmConfigs = new JMenuItem("Configs"); + mntmConfigs.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmConfigs.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload configs?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + Config.load(); + } + }); + mnReload.add(mntmConfigs); + + JMenuItem mntmAccess = new JMenuItem("Access"); + mntmAccess.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAccess.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload admin access levels?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + AdminData.getInstance().load(); + } + }); + mnReload.add(mntmAccess); + + JMenuItem mntmHtml = new JMenuItem("HTML"); + mntmHtml.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmHtml.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload HTML files?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + HtmCache.getInstance().reload(); + } + }); + mnReload.add(mntmHtml); + + JMenuItem mntmMultisells = new JMenuItem("Multisells"); + mntmMultisells.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmMultisells.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload multisells?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + MultisellData.getInstance().load(); + } + }); + mnReload.add(mntmMultisells); + + JMenuItem mntmBuylists = new JMenuItem("Buylists"); + mntmBuylists.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBuylists.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload buylists?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + BuyListData.getInstance().load(); + } + }); + mnReload.add(mntmBuylists); + + JMenuItem mntmPrimeShop = new JMenuItem("PrimeShop"); + mntmPrimeShop.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmPrimeShop.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload PrimeShop?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + PrimeShopData.getInstance().load(); + } + }); + mnReload.add(mntmPrimeShop); + + JMenu mnAnnounce = new JMenu("Announce"); + mnAnnounce.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnAnnounce); + + JMenuItem mntmNormal = new JMenuItem("Normal"); + mntmNormal.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmNormal.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, false); + } + } + }); + mnAnnounce.add(mntmNormal); + + JMenuItem mntmCritical = new JMenuItem("Critical"); + mntmCritical.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmCritical.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Critical announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, true); + } + } + }); + mnAnnounce.add(mntmCritical); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmGameServer.setIconImages(icons); + + // System Panel. + JPanel systemPanel = new SystemPanel(); + JLayeredPane layeredPanel = new JLayeredPane(); + frmGameServer.getContentPane().add(layeredPanel, BorderLayout.CENTER); + layeredPanel.setBounds(0, 0, 819, 566); + layeredPanel.add(scrollPanel, new Integer(0), 0); + layeredPanel.add(systemPanel, new Integer(1), 0); + + // Center frame to screen. + frmGameServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmGameServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/Locator.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/Locator.java new file mode 100644 index 0000000000..e891609b67 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/Locator.java @@ -0,0 +1,295 @@ +/* + * 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.ui; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Locale; + +final class Locator +{ + /** + * Constructor for Locator. + */ + private Locator() + { + } + + /** + * Method getClassSource. + * @param c Class + * @return File + */ + static File getClassSource(Class c) + { + String classResource = c.getName().replace('.', '/') + ".class"; + return getResourceSource(c.getClassLoader(), classResource); + } + + /** + * Method getResourceSource. + * @param c ClassLoader + * @param resource String + * @return File + */ + private static File getResourceSource(ClassLoader c, String resource) + { + if (c == null) + { + c = Locator.class.getClassLoader(); + } + + URL url = null; + + if (c == null) + { + url = ClassLoader.getSystemResource(resource); + } + else + { + url = c.getResource(resource); + } + + if (url != null) + { + String u = url.toString(); + + if (u.startsWith("jar:file:")) + { + int pling = u.indexOf("!"); + String jarName = u.substring(4, pling); + return new File(fromURI(jarName)); + } + else if (u.startsWith("file:")) + { + int tail = u.indexOf(resource); + String dirName = u.substring(0, tail); + return new File(fromURI(dirName)); + } + } + + return null; + } + + /** + * Method fromURI. + * @param uri String + * @return String + */ + private static String fromURI(String uri) + { + URL url = null; + + try + { + url = new URL(uri); + } + catch (MalformedURLException emYouEarlEx) + { + // empty catch clause + } + + if ((url == null) || !"file".equals(url.getProtocol())) + { + throw new IllegalArgumentException("Can only handle valid file: URIs"); + } + + StringBuilder buf = new StringBuilder(url.getHost()); + + if (buf.length() > 0) + { + buf.insert(0, File.separatorChar).insert(0, File.separatorChar); + } + + String file = url.getFile(); + int queryPos = file.indexOf('?'); + buf.append(queryPos < 0 ? file : file.substring(0, queryPos)); + uri = buf.toString().replace('/', File.separatorChar); + + if ((File.pathSeparatorChar == ';') && uri.startsWith("\\") && (uri.length() > 2) && Character.isLetter(uri.charAt(1)) && (uri.lastIndexOf(':') > -1)) + { + uri = uri.substring(1); + } + + String path = decodeUri(uri); + return path; + } + + /** + * Method decodeUri. + * @param uri String + * @return String + */ + private static String decodeUri(String uri) + { + if (uri.indexOf('%') == -1) + { + return uri; + } + + StringBuilder sb = new StringBuilder(); + CharacterIterator iter = new StringCharacterIterator(uri); + + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + { + if (c == '%') + { + char c1 = iter.next(); + + if (c1 != CharacterIterator.DONE) + { + int i1 = Character.digit(c1, 16); + char c2 = iter.next(); + + if (c2 != CharacterIterator.DONE) + { + int i2 = Character.digit(c2, 16); + sb.append((char) ((i1 << 4) + i2)); + } + } + } + else + { + sb.append(c); + } + } + + String path = sb.toString(); + return path; + } + + /** + * Method getToolsJar. + * @return File + */ + static File getToolsJar() + { + boolean toolsJarAvailable = false; + + try + { + Class.forName("com.sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e) + { + try + { + Class.forName("sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e2) + { + // empty catch clause + } + } + + if (toolsJarAvailable) + { + return null; + } + + String javaHome = System.getProperty("java.home"); + + if (javaHome.toLowerCase(Locale.US).endsWith("jre")) + { + javaHome = javaHome.substring(0, javaHome.length() - 4); + } + + File toolsJar = new File(javaHome + "/lib/tools.jar"); + + if (!toolsJar.exists()) + { + System.out.println("Unable to locate tools.jar. " + "Expected to find it in " + toolsJar.getPath()); + return null; + } + + return toolsJar; + } + + /** + * Method getLocationURLs. + * @param location File + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + static URL[] getLocationURLs(File location) throws MalformedURLException + { + return getLocationURLs(location, new String[] + { + ".jar" + }); + } + + /** + * Method getLocationURLs. + * @param location File + * @param extensions String[] + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + private static URL[] getLocationURLs(File location, final String[] extensions) throws MalformedURLException + { + URL[] urls = new URL[0]; + + if (!location.exists()) + { + return urls; + } + + if (!location.isDirectory()) + { + urls = new URL[1]; + String path = location.getPath(); + + for (String extension : extensions) + { + if (path.toLowerCase().endsWith(extension)) + { + urls[0] = location.toURI().toURL(); + break; + } + } + + return urls; + } + + File[] matches = location.listFiles((FilenameFilter) (dir, name) -> + { + for (String extension : extensions) + { + if (name.toLowerCase().endsWith(extension)) + { + return true; + } + } + return false; + }); + urls = new URL[matches.length]; + + for (int i = 0; i < matches.length; ++i) + { + urls[i] = matches[i].toURI().toURL(); + } + + return urls; + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/SystemPanel.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/SystemPanel.java new file mode 100644 index 0000000000..68cabb3c12 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/SystemPanel.java @@ -0,0 +1,142 @@ +/* + * 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.ui; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.LineBorder; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.GameServer; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; + +/** + * @author Mobius + */ +public class SystemPanel extends JPanel +{ + final static long startTime = System.currentTimeMillis(); + + public SystemPanel() + { + setBackground(Color.WHITE); + setBounds(500, 20, 284, 140); + setBorder(new LineBorder(new Color(0, 0, 0), 1, false)); + setOpaque(true); + setLayout(null); + + JLabel lblProtocol = new JLabel("Protocol"); + lblProtocol.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblProtocol.setBounds(10, 5, 264, 17); + add(lblProtocol); + + JLabel lblConnected = new JLabel("Connected"); + lblConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblConnected.setBounds(10, 23, 264, 17); + add(lblConnected); + + JLabel lblMaxConnected = new JLabel("Max connected"); + lblMaxConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblMaxConnected.setBounds(10, 41, 264, 17); + add(lblMaxConnected); + + JLabel lblOfflineShops = new JLabel("Offline trade"); + lblOfflineShops.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblOfflineShops.setBounds(10, 59, 264, 17); + add(lblOfflineShops); + + JLabel lblElapsedTime = new JLabel("Elapsed time"); + lblElapsedTime.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblElapsedTime.setBounds(10, 77, 264, 17); + add(lblElapsedTime); + + JLabel lblJavaVersion = new JLabel("Build JDK"); + lblJavaVersion.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblJavaVersion.setBounds(10, 95, 264, 17); + add(lblJavaVersion); + + JLabel lblBuildDate = new JLabel("Build date"); + lblBuildDate.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblBuildDate.setBounds(10, 113, 264, 17); + add(lblBuildDate); + + // Set initial values. + lblProtocol.setText("Protocol: 0"); + lblConnected.setText("Connected: 0"); + lblMaxConnected.setText("Max connected: 0"); + lblOfflineShops.setText("Offline trade: 0"); + lblElapsedTime.setText("Elapsed: 0 sec"); + lblJavaVersion.setText("Java version: " + System.getProperty("java.version")); + lblBuildDate.setText("Build date: Unavailable"); + try + { + File jarName = Locator.getClassSource(GameServer.class); + JarFile jarFile = new JarFile(jarName); + Attributes attrs = jarFile.getManifest().getMainAttributes(); + lblBuildDate.setText("Build date: " + attrs.getValue("Build-Date").split(" ")[0]); + jarFile.close(); + } + catch (Exception e) + { + } + + // Initial update task. + new Timer().schedule(new TimerTask() + { + @Override + public void run() + { + lblProtocol.setText((Config.PROTOCOL_LIST.size() > 1 ? "Protocols: " : "Protocol: ") + Config.PROTOCOL_LIST.toString()); + } + }, 4500); + + // Repeating elapsed time task. + new Timer().scheduleAtFixedRate(new TimerTask() + { + @Override + public void run() + { + lblConnected.setText("Connected: " + PlayerCountManager.getInstance().getConnectedCount()); + lblMaxConnected.setText("Max connected: " + PlayerCountManager.getInstance().getMaxConnectedCount()); + lblOfflineShops.setText("Offline trade: " + PlayerCountManager.getInstance().getOfflineTradeCount()); + lblElapsedTime.setText("Elapsed: " + getDurationBreakdown(System.currentTimeMillis() - startTime)); + } + }, 1000, 1000); + } + + static String getDurationBreakdown(long millis) + { + long days = TimeUnit.MILLISECONDS.toDays(millis); + millis -= TimeUnit.DAYS.toMillis(days); + long hours = TimeUnit.MILLISECONDS.toHours(millis); + millis -= TimeUnit.HOURS.toMillis(hours); + long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); + millis -= TimeUnit.MINUTES.toMillis(minutes); + long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); + + return (days + "d " + hours + "h " + minutes + "m " + seconds + "s"); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/frmAbout.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/frmAbout.java new file mode 100644 index 0000000000..e8a4f9a47c --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ui/frmAbout.java @@ -0,0 +1,143 @@ +/* + * 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.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblSupports = new JLabel("Server Protocol"); + lblSupports.setHorizontalAlignment(SwingConstants.CENTER); + lblSupports.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblSupports.setBounds(10, 78, 271, 23); + frmAbout.getContentPane().add(lblSupports); + + JLabel lblProtocols = new JLabel("Protocol Number"); + lblProtocols.setHorizontalAlignment(SwingConstants.CENTER); + lblProtocols.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblProtocols.setBounds(10, 92, 271, 23); + frmAbout.getContentPane().add(lblProtocols); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Generate protocols text. + String protocols = ""; + if (Config.PROTOCOL_LIST.size() > 1) + { + for (Integer number : Config.PROTOCOL_LIST) + { + if (!protocols.isEmpty()) + { + protocols += " - "; + } + protocols += number; + } + lblSupports.setText("Server Protocols"); + } + else + { + protocols += Config.PROTOCOL_LIST.get(0); + } + lblProtocols.setText(protocols); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java index ecc40e644b..056fa7ea38 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java @@ -20,6 +20,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Summon; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.olympiad.OlympiadManager; @@ -100,6 +101,8 @@ public final class OfflineTradeUtil return false; } + PlayerCountManager.getInstance().incOfflineTradeCount(); + final L2GameClient client = player.getClient(); client.setDetached(true); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/GameServerTable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/GameServerTable.java index 362aa93ad5..73110fb6dc 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/GameServerTable.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/GameServerTable.java @@ -409,7 +409,18 @@ public final class GameServerTable implements IGameXmlReader */ public void setStatus(int status) { - _status = status; + if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) + { + _status = ServerStatus.STATUS_DOWN; + } + else if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) + { + _status = ServerStatus.STATUS_GM_ONLY; + } + else + { + _status = status; + } } /** diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/LoginServer.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/LoginServer.java index 6c2062e622..39377afee3 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/LoginServer.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/LoginServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.loginserver; +import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -32,35 +33,43 @@ import com.l2jmobius.Config; import com.l2jmobius.Server; import com.l2jmobius.commons.database.DatabaseBackup; import com.l2jmobius.commons.database.DatabaseFactory; +import com.l2jmobius.gameserver.network.loginserverpackets.game.ServerStatus; import com.l2jmobius.loginserver.network.ClientNetworkManager; +import com.l2jmobius.loginserver.ui.Gui; /** * @author KenM */ public final class LoginServer { - private final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); + public final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); public static final int PROTOCOL_REV = 0x0106; - private static LoginServer _instance; + private static LoginServer INSTANCE; private GameServerListener _gameServerListener; private Thread _restartLoginServer; + private static int _loginStatus = ServerStatus.STATUS_NORMAL; public static void main(String[] args) throws Exception { - new LoginServer(); + INSTANCE = new LoginServer(); } public static LoginServer getInstance() { - return _instance; + return INSTANCE; } private LoginServer() throws Exception { - _instance = this; Server.serverMode = Server.MODE_LOGINSERVER; + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + // Create log folder final File logFolder = new File(".", "log"); logFolder.mkdir(); @@ -96,6 +105,14 @@ public final class LoginServer loadBanFile(); + if (Config.LOGIN_SERVER_SCHEDULE_RESTART) + { + LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); + _restartLoginServer = new LoginServerRestart(); + _restartLoginServer.setDaemon(true); + _restartLoginServer.start(); + } + try { _gameServerListener = new GameServerListener(); @@ -116,7 +133,7 @@ public final class LoginServer return _gameServerListener; } - private void loadBanFile() + public void loadBanFile() { final File bannedFile = new File("./banned_ip.cfg"); if (bannedFile.exists() && bannedFile.isFile()) @@ -170,14 +187,6 @@ public final class LoginServer { LOGGER.warning("IP Bans file (" + bannedFile.getName() + ") is missing or is a directory, skipped."); } - - if (Config.LOGIN_SERVER_SCHEDULE_RESTART) - { - LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); - _restartLoginServer = new LoginServerRestart(); - _restartLoginServer.setDaemon(true); - _restartLoginServer.start(); - } } class LoginServerRestart extends Thread @@ -213,4 +222,14 @@ public final class LoginServer } Runtime.getRuntime().exit(restart ? 2 : 0); } + + public int getStatus() + { + return _loginStatus; + } + + public void setStatus(int status) + { + _loginStatus = status; + } } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java index 670365b761..fa5c1e0a3a 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java @@ -20,8 +20,10 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.IIncomingPacket; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.network.L2LoginClient; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayOk; @@ -61,7 +63,11 @@ public class RequestServerLogin implements IIncomingPacket // if we didnt showed the license we cant check these values if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2)) { - if (LoginController.getInstance().isLoginPossible(client, _serverId)) + if ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) || ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) && (client.getAccessLevel() < 1))) + { + client.close(LoginFailReason.REASON_ACCESS_FAILED); + } + else if (LoginController.getInstance().isLoginPossible(client, _serverId)) { client.setJoinedGS(true); client.sendPacket(new PlayOk(sk)); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/ui/Gui.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/ui/Gui.java new file mode 100644 index 0000000000..7dfddb4985 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/ui/Gui.java @@ -0,0 +1,275 @@ +/* + * 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.loginserver.ui; + +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.loginserver.GameServerTable; +import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; +import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmLoginServer; + JTextArea txtrConsole; + + JCheckBoxMenuItem chckbxmntmEnabled; + JCheckBoxMenuItem chckbxmntmDisabled; + JCheckBoxMenuItem chckbxmntmGmOnly; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + + public Gui() + { + frmLoginServer = new JFrame(); + frmLoginServer.setVisible(false); + frmLoginServer.setTitle("Mobius - LoginServer"); + frmLoginServer.setResizable(false); + frmLoginServer.setBounds(100, 100, 825, 618); + frmLoginServer.getContentPane().setLayout(null); + frmLoginServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmLoginServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmLoginServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmLoginServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(true); + } + }); + mnActions.add(mntmRestart); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmBannedIps = new JMenuItem("Banned IPs"); + mntmBannedIps.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBannedIps.addActionListener(arg0 -> + { + LoginController.getInstance().getBannedIps().clear(); + LoginServer.getInstance().loadBanFile(); + }); + mnReload.add(mntmBannedIps); + + JMenu mnStatus = new JMenu("Status"); + mnStatus.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnStatus); + + chckbxmntmEnabled = new JCheckBoxMenuItem("Enabled"); + chckbxmntmEnabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmEnabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(true); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_NORMAL); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_NORMAL); + } + LoginServer.getInstance().LOGGER.info("Status changed to enabled."); + }); + chckbxmntmEnabled.setSelected(true); + mnStatus.add(chckbxmntmEnabled); + + chckbxmntmDisabled = new JCheckBoxMenuItem("Disabled"); + chckbxmntmDisabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmDisabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(true); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_DOWN); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_DOWN); + } + LoginServer.getInstance().LOGGER.info("Status changed to disabled."); + }); + mnStatus.add(chckbxmntmDisabled); + + chckbxmntmGmOnly = new JCheckBoxMenuItem("GM only"); + chckbxmntmGmOnly.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmGmOnly.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(true); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_GM_ONLY); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_GM_ONLY); + } + LoginServer.getInstance().LOGGER.info("Status changed to GM only."); + }); + mnStatus.add(chckbxmntmGmOnly); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmLoginServer.setIconImages(icons); + + // Center frame to screen. + frmLoginServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmLoginServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/ui/frmAbout.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/ui/frmAbout.java new file mode 100644 index 0000000000..b535d860b6 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/loginserver/ui/frmAbout.java @@ -0,0 +1,115 @@ +/* + * 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.loginserver.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblLoginServer = new JLabel("Login Server"); + lblLoginServer.setHorizontalAlignment(SwingConstants.CENTER); + lblLoginServer.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblLoginServer.setBounds(10, 86, 271, 23); + frmAbout.getContentPane().add(lblLoginServer); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_2.5_Underground/build.xml b/L2J_Mobius_2.5_Underground/build.xml index 061d49f631..bae3275a09 100644 --- a/L2J_Mobius_2.5_Underground/build.xml +++ b/L2J_Mobius_2.5_Underground/build.xml @@ -78,8 +78,8 @@ - - + + @@ -93,8 +93,8 @@ - - + + @@ -108,8 +108,8 @@ - - + + @@ -123,8 +123,8 @@ - - + + diff --git a/L2J_Mobius_2.5_Underground/dist/game/GameServer.bat b/L2J_Mobius_2.5_Underground/dist/game/GameServer.bat deleted file mode 100644 index 2dbaac7089..0000000000 --- a/L2J_Mobius_2.5_Underground/dist/game/GameServer.bat +++ /dev/null @@ -1,30 +0,0 @@ -@set /p parameters=. + */ +package com.l2jmobius.commons.util; + +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; + +/* + * A class to control the maximum number of lines to be stored in a Document + * + * Excess lines can be removed from the start or end of the Document + * depending on your requirement. + * + * a) if you append text to the Document, then you would want to remove lines + * from the start. + * b) if you insert text at the beginning of the Document, then you would + * want to remove lines from the end. + */ +public class LimitLinesDocumentListener implements DocumentListener +{ + private int _maximumLines; + private final boolean _isRemoveFromStart; + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start of the Document. + */ + public LimitLinesDocumentListener(int maximumLines) + { + this(maximumLines, true); + } + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start or end of the Document, depending on the boolean value specified. + */ + public LimitLinesDocumentListener(int maximumLines, boolean isRemoveFromStart) + { + setLimitLines(maximumLines); + _isRemoveFromStart = isRemoveFromStart; + } + + /* + * Return the maximum number of lines to be stored in the Document. + */ + public int getLimitLines() + { + return _maximumLines; + } + + /* + * Set the maximum number of lines to be stored in the Document. + */ + public void setLimitLines(int maximumLines) + { + if (maximumLines < 1) + { + String message = "Maximum lines must be greater than 0"; + throw new IllegalArgumentException(message); + } + + _maximumLines = maximumLines; + } + + /* + * Handle insertion of new text into the Document. + */ + @Override + public void insertUpdate(final DocumentEvent e) + { + // Changes to the Document can not be done within the listener so we need to add the processing to the end of the EDT. + SwingUtilities.invokeLater(() -> removeLines(e)); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + } + + @Override + public void changedUpdate(DocumentEvent e) + { + } + + /* + * Remove lines from the Document when necessary. + */ + private void removeLines(DocumentEvent e) + { + // The root Element of the Document will tell us the total number of line in the Document. + Document document = e.getDocument(); + Element root = document.getDefaultRootElement(); + + while (root.getElementCount() > _maximumLines) + { + if (_isRemoveFromStart) + { + removeFromStart(document, root); + } + else + { + removeFromEnd(document, root); + } + } + } + + /* + * Remove lines from the start of the Document + */ + private void removeFromStart(Document document, Element root) + { + Element line = root.getElement(0); + int end = line.getEndOffset(); + + try + { + document.remove(0, end); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } + + /* + * Remove lines from the end of the Document + */ + private void removeFromEnd(Document document, Element root) + { + // We use start minus 1 to make sure we remove the newline character of the previous line. + + Element line = root.getElement(root.getElementCount() - 1); + int start = line.getStartOffset(); + int end = line.getEndOffset(); + + try + { + document.remove(start - 1, end - start); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/commons/util/SplashScreen.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/commons/util/SplashScreen.java index 80992f1b4d..5086e53e9c 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/commons/util/SplashScreen.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/commons/util/SplashScreen.java @@ -21,8 +21,8 @@ import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Timer; +import java.util.TimerTask; import javax.swing.ImageIcon; import javax.swing.JFrame; @@ -52,22 +52,24 @@ public class SplashScreen extends JWindow setAlwaysOnTop(true); setVisible(true); - // Schedule to close. - Executors.newScheduledThreadPool(1).schedule(this::close, imageIcon.getIconWidth() > 0 ? time : 100, TimeUnit.MILLISECONDS); - } - - public void close() - { - setVisible(false); - if (parentFrame != null) + new Timer().schedule(new TimerTask() { - // Make parent visible. - parentFrame.setVisible(true); - // Focus parent window. - parentFrame.toFront(); - parentFrame.setState(Frame.ICONIFIED); - parentFrame.setState(Frame.NORMAL); - } + @Override + public void run() + { + setVisible(false); + if (parentFrame != null) + { + // Make parent visible. + parentFrame.setVisible(true); + // Focus parent window. + parentFrame.toFront(); + parentFrame.setState(Frame.ICONIFIED); + parentFrame.setState(Frame.NORMAL); + } + dispose(); + } + }, imageIcon.getIconWidth() > 0 ? time : 100); } @Override diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java index 7df21deee2..298b937c28 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.gameserver; +import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.io.File; import java.io.FileInputStream; @@ -149,6 +150,7 @@ import com.l2jmobius.gameserver.network.loginserver.LoginServerNetworkManager; import com.l2jmobius.gameserver.network.telnet.TelnetServer; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.taskmanager.TaskManager; +import com.l2jmobius.gameserver.ui.Gui; import com.l2jmobius.gameserver.util.Broadcast; public class GameServer @@ -172,6 +174,28 @@ public class GameServer public GameServer() throws Exception { final long serverLoadStart = System.currentTimeMillis(); + Server.serverMode = Server.MODE_GAMESERVER; + + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + + // Create log folder + final File logFolder = new File(Config.DATAPACK_ROOT, "log"); + logFolder.mkdir(); + + // Create input stream for log file -- or store file data into memory + try (InputStream is = new FileInputStream(new File("./log.cfg"))) + { + LogManager.getLogManager().readConfiguration(is); + } + + // Initialize config + Config.load(); + printSection("Database"); + DatabaseFactory.getInstance(); printSection("ThreadPool"); ThreadPool.init(); @@ -459,23 +483,6 @@ public class GameServer public static void main(String[] args) throws Exception { - Server.serverMode = Server.MODE_GAMESERVER; - - /*** Main ***/ - // Create log folder - final File logFolder = new File(Config.DATAPACK_ROOT, "log"); - logFolder.mkdir(); - - // Create input stream for log file -- or store file data into memory - try (InputStream is = new FileInputStream(new File("./log.cfg"))) - { - LogManager.getLogManager().readConfiguration(is); - } - - // Initialize config - Config.load(); - DatabaseFactory.getInstance(); - INSTANCE = new GameServer(); } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java index 9a1a01c8a6..625915e123 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java @@ -28,6 +28,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.gameserver.LoginServerThread; import com.l2jmobius.gameserver.enums.PrivateStoreType; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.L2ManufactureItem; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.TradeItem; @@ -298,6 +299,7 @@ public class OfflineTradersTable player.setOnlineStatus(true, true); player.restoreEffects(); player.broadcastUserInfo(); + PlayerCountManager.getInstance().incOfflineTradeCount(); nTraders++; } catch (Exception e) @@ -451,6 +453,8 @@ public class OfflineTradersTable public static synchronized void removeTrader(int traderObjId) { + PlayerCountManager.getInstance().decOfflineTradeCount(); + try (Connection con = DatabaseFactory.getInstance().getConnection(); PreparedStatement stm1 = con.prepareStatement(CLEAR_OFFLINE_TABLE_ITEMS_PLAYER); PreparedStatement stm2 = con.prepareStatement(CLEAR_OFFLINE_TABLE_PLAYER)) diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java new file mode 100644 index 0000000000..cb2fab84ed --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java @@ -0,0 +1,77 @@ +/* + * 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.instancemanager; + +/** + * @author Mobius + */ +public class PlayerCountManager +{ + private volatile static int connectedCount = 0; + private volatile static int maxConnectedCount = 0; + private volatile static int offlineTradeCount = 0; + + protected PlayerCountManager() + { + } + + public int getConnectedCount() + { + return connectedCount; + } + + public int getMaxConnectedCount() + { + return maxConnectedCount; + } + + public int getOfflineTradeCount() + { + return offlineTradeCount; + } + + public synchronized void incConnectedCount() + { + connectedCount++; + maxConnectedCount = Math.max(maxConnectedCount, connectedCount); + } + + public void decConnectedCount() + { + connectedCount--; + } + + public void incOfflineTradeCount() + { + offlineTradeCount++; + } + + public synchronized void decOfflineTradeCount() + { + offlineTradeCount = Math.max(0, offlineTradeCount - 1); + } + + public static PlayerCountManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final PlayerCountManager INSTANCE = new PlayerCountManager(); + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2World.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2World.java index 9b02364b07..bea222354b 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2World.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2World.java @@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -135,6 +136,8 @@ public final class L2World if (object.isPlayer()) { + PlayerCountManager.getInstance().incConnectedCount(); + final L2PcInstance newPlayer = (L2PcInstance) object; if (newPlayer.isTeleporting()) // TODO: drop when we stop removing player from the world while teleporting. { @@ -170,6 +173,8 @@ public final class L2World _allObjects.remove(object.getObjectId()); if (object.isPlayer()) { + PlayerCountManager.getInstance().decConnectedCount(); + final L2PcInstance player = (L2PcInstance) object; if (player.isTeleporting()) // TODO: drop when we stop removing player from the world while teleportingq. { diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/Gui.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/Gui.java new file mode 100644 index 0000000000..9f8c2a41a6 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/Gui.java @@ -0,0 +1,370 @@ +/* + * 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.ui; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.gameserver.Shutdown; +import com.l2jmobius.gameserver.cache.HtmCache; +import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.BuyListData; +import com.l2jmobius.gameserver.data.xml.impl.MultisellData; +import com.l2jmobius.gameserver.data.xml.impl.PrimeShopData; +import com.l2jmobius.gameserver.util.Broadcast; +import com.l2jmobius.gameserver.util.Util; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmGameServer; + JTextArea txtrConsole; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + final static String[] abortOptions = + { + "Abort", + "Cancel" + }; + final static String[] confirmOptions = + { + "Confirm", + "Cancel" + }; + + public Gui() + { + frmGameServer = new JFrame(); + frmGameServer.setVisible(false); + frmGameServer.setTitle("Mobius - GameServer"); + frmGameServer.setResizable(false); + frmGameServer.setBounds(100, 100, 825, 618); + frmGameServer.getContentPane().setLayout(null); + frmGameServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmGameServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown server immediately?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + Shutdown.getInstance().startShutdown(null, 1, false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmGameServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmGameServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Shutdown delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, false); + } + } + } + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Restart delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, true); + } + } + } + } + }); + mnActions.add(mntmRestart); + + JMenuItem mntmAbort = new JMenuItem("Abort"); + mntmAbort.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbort.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Abort server shutdown?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, abortOptions, abortOptions[1]) == 0) + { + Shutdown.getInstance().abort(null); + } + }); + mnActions.add(mntmAbort); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmConfigs = new JMenuItem("Configs"); + mntmConfigs.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmConfigs.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload configs?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + Config.load(); + } + }); + mnReload.add(mntmConfigs); + + JMenuItem mntmAccess = new JMenuItem("Access"); + mntmAccess.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAccess.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload admin access levels?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + AdminData.getInstance().load(); + } + }); + mnReload.add(mntmAccess); + + JMenuItem mntmHtml = new JMenuItem("HTML"); + mntmHtml.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmHtml.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload HTML files?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + HtmCache.getInstance().reload(); + } + }); + mnReload.add(mntmHtml); + + JMenuItem mntmMultisells = new JMenuItem("Multisells"); + mntmMultisells.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmMultisells.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload multisells?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + MultisellData.getInstance().load(); + } + }); + mnReload.add(mntmMultisells); + + JMenuItem mntmBuylists = new JMenuItem("Buylists"); + mntmBuylists.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBuylists.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload buylists?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + BuyListData.getInstance().load(); + } + }); + mnReload.add(mntmBuylists); + + JMenuItem mntmPrimeShop = new JMenuItem("PrimeShop"); + mntmPrimeShop.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmPrimeShop.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload PrimeShop?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + PrimeShopData.getInstance().load(); + } + }); + mnReload.add(mntmPrimeShop); + + JMenu mnAnnounce = new JMenu("Announce"); + mnAnnounce.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnAnnounce); + + JMenuItem mntmNormal = new JMenuItem("Normal"); + mntmNormal.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmNormal.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, false); + } + } + }); + mnAnnounce.add(mntmNormal); + + JMenuItem mntmCritical = new JMenuItem("Critical"); + mntmCritical.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmCritical.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Critical announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, true); + } + } + }); + mnAnnounce.add(mntmCritical); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmGameServer.setIconImages(icons); + + // System Panel. + JPanel systemPanel = new SystemPanel(); + JLayeredPane layeredPanel = new JLayeredPane(); + frmGameServer.getContentPane().add(layeredPanel, BorderLayout.CENTER); + layeredPanel.setBounds(0, 0, 819, 566); + layeredPanel.add(scrollPanel, new Integer(0), 0); + layeredPanel.add(systemPanel, new Integer(1), 0); + + // Center frame to screen. + frmGameServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmGameServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/Locator.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/Locator.java new file mode 100644 index 0000000000..e891609b67 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/Locator.java @@ -0,0 +1,295 @@ +/* + * 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.ui; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Locale; + +final class Locator +{ + /** + * Constructor for Locator. + */ + private Locator() + { + } + + /** + * Method getClassSource. + * @param c Class + * @return File + */ + static File getClassSource(Class c) + { + String classResource = c.getName().replace('.', '/') + ".class"; + return getResourceSource(c.getClassLoader(), classResource); + } + + /** + * Method getResourceSource. + * @param c ClassLoader + * @param resource String + * @return File + */ + private static File getResourceSource(ClassLoader c, String resource) + { + if (c == null) + { + c = Locator.class.getClassLoader(); + } + + URL url = null; + + if (c == null) + { + url = ClassLoader.getSystemResource(resource); + } + else + { + url = c.getResource(resource); + } + + if (url != null) + { + String u = url.toString(); + + if (u.startsWith("jar:file:")) + { + int pling = u.indexOf("!"); + String jarName = u.substring(4, pling); + return new File(fromURI(jarName)); + } + else if (u.startsWith("file:")) + { + int tail = u.indexOf(resource); + String dirName = u.substring(0, tail); + return new File(fromURI(dirName)); + } + } + + return null; + } + + /** + * Method fromURI. + * @param uri String + * @return String + */ + private static String fromURI(String uri) + { + URL url = null; + + try + { + url = new URL(uri); + } + catch (MalformedURLException emYouEarlEx) + { + // empty catch clause + } + + if ((url == null) || !"file".equals(url.getProtocol())) + { + throw new IllegalArgumentException("Can only handle valid file: URIs"); + } + + StringBuilder buf = new StringBuilder(url.getHost()); + + if (buf.length() > 0) + { + buf.insert(0, File.separatorChar).insert(0, File.separatorChar); + } + + String file = url.getFile(); + int queryPos = file.indexOf('?'); + buf.append(queryPos < 0 ? file : file.substring(0, queryPos)); + uri = buf.toString().replace('/', File.separatorChar); + + if ((File.pathSeparatorChar == ';') && uri.startsWith("\\") && (uri.length() > 2) && Character.isLetter(uri.charAt(1)) && (uri.lastIndexOf(':') > -1)) + { + uri = uri.substring(1); + } + + String path = decodeUri(uri); + return path; + } + + /** + * Method decodeUri. + * @param uri String + * @return String + */ + private static String decodeUri(String uri) + { + if (uri.indexOf('%') == -1) + { + return uri; + } + + StringBuilder sb = new StringBuilder(); + CharacterIterator iter = new StringCharacterIterator(uri); + + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + { + if (c == '%') + { + char c1 = iter.next(); + + if (c1 != CharacterIterator.DONE) + { + int i1 = Character.digit(c1, 16); + char c2 = iter.next(); + + if (c2 != CharacterIterator.DONE) + { + int i2 = Character.digit(c2, 16); + sb.append((char) ((i1 << 4) + i2)); + } + } + } + else + { + sb.append(c); + } + } + + String path = sb.toString(); + return path; + } + + /** + * Method getToolsJar. + * @return File + */ + static File getToolsJar() + { + boolean toolsJarAvailable = false; + + try + { + Class.forName("com.sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e) + { + try + { + Class.forName("sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e2) + { + // empty catch clause + } + } + + if (toolsJarAvailable) + { + return null; + } + + String javaHome = System.getProperty("java.home"); + + if (javaHome.toLowerCase(Locale.US).endsWith("jre")) + { + javaHome = javaHome.substring(0, javaHome.length() - 4); + } + + File toolsJar = new File(javaHome + "/lib/tools.jar"); + + if (!toolsJar.exists()) + { + System.out.println("Unable to locate tools.jar. " + "Expected to find it in " + toolsJar.getPath()); + return null; + } + + return toolsJar; + } + + /** + * Method getLocationURLs. + * @param location File + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + static URL[] getLocationURLs(File location) throws MalformedURLException + { + return getLocationURLs(location, new String[] + { + ".jar" + }); + } + + /** + * Method getLocationURLs. + * @param location File + * @param extensions String[] + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + private static URL[] getLocationURLs(File location, final String[] extensions) throws MalformedURLException + { + URL[] urls = new URL[0]; + + if (!location.exists()) + { + return urls; + } + + if (!location.isDirectory()) + { + urls = new URL[1]; + String path = location.getPath(); + + for (String extension : extensions) + { + if (path.toLowerCase().endsWith(extension)) + { + urls[0] = location.toURI().toURL(); + break; + } + } + + return urls; + } + + File[] matches = location.listFiles((FilenameFilter) (dir, name) -> + { + for (String extension : extensions) + { + if (name.toLowerCase().endsWith(extension)) + { + return true; + } + } + return false; + }); + urls = new URL[matches.length]; + + for (int i = 0; i < matches.length; ++i) + { + urls[i] = matches[i].toURI().toURL(); + } + + return urls; + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/SystemPanel.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/SystemPanel.java new file mode 100644 index 0000000000..68cabb3c12 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/SystemPanel.java @@ -0,0 +1,142 @@ +/* + * 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.ui; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.LineBorder; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.GameServer; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; + +/** + * @author Mobius + */ +public class SystemPanel extends JPanel +{ + final static long startTime = System.currentTimeMillis(); + + public SystemPanel() + { + setBackground(Color.WHITE); + setBounds(500, 20, 284, 140); + setBorder(new LineBorder(new Color(0, 0, 0), 1, false)); + setOpaque(true); + setLayout(null); + + JLabel lblProtocol = new JLabel("Protocol"); + lblProtocol.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblProtocol.setBounds(10, 5, 264, 17); + add(lblProtocol); + + JLabel lblConnected = new JLabel("Connected"); + lblConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblConnected.setBounds(10, 23, 264, 17); + add(lblConnected); + + JLabel lblMaxConnected = new JLabel("Max connected"); + lblMaxConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblMaxConnected.setBounds(10, 41, 264, 17); + add(lblMaxConnected); + + JLabel lblOfflineShops = new JLabel("Offline trade"); + lblOfflineShops.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblOfflineShops.setBounds(10, 59, 264, 17); + add(lblOfflineShops); + + JLabel lblElapsedTime = new JLabel("Elapsed time"); + lblElapsedTime.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblElapsedTime.setBounds(10, 77, 264, 17); + add(lblElapsedTime); + + JLabel lblJavaVersion = new JLabel("Build JDK"); + lblJavaVersion.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblJavaVersion.setBounds(10, 95, 264, 17); + add(lblJavaVersion); + + JLabel lblBuildDate = new JLabel("Build date"); + lblBuildDate.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblBuildDate.setBounds(10, 113, 264, 17); + add(lblBuildDate); + + // Set initial values. + lblProtocol.setText("Protocol: 0"); + lblConnected.setText("Connected: 0"); + lblMaxConnected.setText("Max connected: 0"); + lblOfflineShops.setText("Offline trade: 0"); + lblElapsedTime.setText("Elapsed: 0 sec"); + lblJavaVersion.setText("Java version: " + System.getProperty("java.version")); + lblBuildDate.setText("Build date: Unavailable"); + try + { + File jarName = Locator.getClassSource(GameServer.class); + JarFile jarFile = new JarFile(jarName); + Attributes attrs = jarFile.getManifest().getMainAttributes(); + lblBuildDate.setText("Build date: " + attrs.getValue("Build-Date").split(" ")[0]); + jarFile.close(); + } + catch (Exception e) + { + } + + // Initial update task. + new Timer().schedule(new TimerTask() + { + @Override + public void run() + { + lblProtocol.setText((Config.PROTOCOL_LIST.size() > 1 ? "Protocols: " : "Protocol: ") + Config.PROTOCOL_LIST.toString()); + } + }, 4500); + + // Repeating elapsed time task. + new Timer().scheduleAtFixedRate(new TimerTask() + { + @Override + public void run() + { + lblConnected.setText("Connected: " + PlayerCountManager.getInstance().getConnectedCount()); + lblMaxConnected.setText("Max connected: " + PlayerCountManager.getInstance().getMaxConnectedCount()); + lblOfflineShops.setText("Offline trade: " + PlayerCountManager.getInstance().getOfflineTradeCount()); + lblElapsedTime.setText("Elapsed: " + getDurationBreakdown(System.currentTimeMillis() - startTime)); + } + }, 1000, 1000); + } + + static String getDurationBreakdown(long millis) + { + long days = TimeUnit.MILLISECONDS.toDays(millis); + millis -= TimeUnit.DAYS.toMillis(days); + long hours = TimeUnit.MILLISECONDS.toHours(millis); + millis -= TimeUnit.HOURS.toMillis(hours); + long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); + millis -= TimeUnit.MINUTES.toMillis(minutes); + long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); + + return (days + "d " + hours + "h " + minutes + "m " + seconds + "s"); + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/frmAbout.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/frmAbout.java new file mode 100644 index 0000000000..e8a4f9a47c --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ui/frmAbout.java @@ -0,0 +1,143 @@ +/* + * 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.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblSupports = new JLabel("Server Protocol"); + lblSupports.setHorizontalAlignment(SwingConstants.CENTER); + lblSupports.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblSupports.setBounds(10, 78, 271, 23); + frmAbout.getContentPane().add(lblSupports); + + JLabel lblProtocols = new JLabel("Protocol Number"); + lblProtocols.setHorizontalAlignment(SwingConstants.CENTER); + lblProtocols.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblProtocols.setBounds(10, 92, 271, 23); + frmAbout.getContentPane().add(lblProtocols); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Generate protocols text. + String protocols = ""; + if (Config.PROTOCOL_LIST.size() > 1) + { + for (Integer number : Config.PROTOCOL_LIST) + { + if (!protocols.isEmpty()) + { + protocols += " - "; + } + protocols += number; + } + lblSupports.setText("Server Protocols"); + } + else + { + protocols += Config.PROTOCOL_LIST.get(0); + } + lblProtocols.setText(protocols); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java index ecc40e644b..056fa7ea38 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java @@ -20,6 +20,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Summon; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.olympiad.OlympiadManager; @@ -100,6 +101,8 @@ public final class OfflineTradeUtil return false; } + PlayerCountManager.getInstance().incOfflineTradeCount(); + final L2GameClient client = player.getClient(); client.setDetached(true); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/GameServerTable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/GameServerTable.java index 362aa93ad5..73110fb6dc 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/GameServerTable.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/GameServerTable.java @@ -409,7 +409,18 @@ public final class GameServerTable implements IGameXmlReader */ public void setStatus(int status) { - _status = status; + if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) + { + _status = ServerStatus.STATUS_DOWN; + } + else if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) + { + _status = ServerStatus.STATUS_GM_ONLY; + } + else + { + _status = status; + } } /** diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/LoginServer.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/LoginServer.java index 6c2062e622..39377afee3 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/LoginServer.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/LoginServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.loginserver; +import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -32,35 +33,43 @@ import com.l2jmobius.Config; import com.l2jmobius.Server; import com.l2jmobius.commons.database.DatabaseBackup; import com.l2jmobius.commons.database.DatabaseFactory; +import com.l2jmobius.gameserver.network.loginserverpackets.game.ServerStatus; import com.l2jmobius.loginserver.network.ClientNetworkManager; +import com.l2jmobius.loginserver.ui.Gui; /** * @author KenM */ public final class LoginServer { - private final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); + public final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); public static final int PROTOCOL_REV = 0x0106; - private static LoginServer _instance; + private static LoginServer INSTANCE; private GameServerListener _gameServerListener; private Thread _restartLoginServer; + private static int _loginStatus = ServerStatus.STATUS_NORMAL; public static void main(String[] args) throws Exception { - new LoginServer(); + INSTANCE = new LoginServer(); } public static LoginServer getInstance() { - return _instance; + return INSTANCE; } private LoginServer() throws Exception { - _instance = this; Server.serverMode = Server.MODE_LOGINSERVER; + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + // Create log folder final File logFolder = new File(".", "log"); logFolder.mkdir(); @@ -96,6 +105,14 @@ public final class LoginServer loadBanFile(); + if (Config.LOGIN_SERVER_SCHEDULE_RESTART) + { + LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); + _restartLoginServer = new LoginServerRestart(); + _restartLoginServer.setDaemon(true); + _restartLoginServer.start(); + } + try { _gameServerListener = new GameServerListener(); @@ -116,7 +133,7 @@ public final class LoginServer return _gameServerListener; } - private void loadBanFile() + public void loadBanFile() { final File bannedFile = new File("./banned_ip.cfg"); if (bannedFile.exists() && bannedFile.isFile()) @@ -170,14 +187,6 @@ public final class LoginServer { LOGGER.warning("IP Bans file (" + bannedFile.getName() + ") is missing or is a directory, skipped."); } - - if (Config.LOGIN_SERVER_SCHEDULE_RESTART) - { - LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); - _restartLoginServer = new LoginServerRestart(); - _restartLoginServer.setDaemon(true); - _restartLoginServer.start(); - } } class LoginServerRestart extends Thread @@ -213,4 +222,14 @@ public final class LoginServer } Runtime.getRuntime().exit(restart ? 2 : 0); } + + public int getStatus() + { + return _loginStatus; + } + + public void setStatus(int status) + { + _loginStatus = status; + } } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java index 670365b761..fa5c1e0a3a 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java @@ -20,8 +20,10 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.IIncomingPacket; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.network.L2LoginClient; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayOk; @@ -61,7 +63,11 @@ public class RequestServerLogin implements IIncomingPacket // if we didnt showed the license we cant check these values if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2)) { - if (LoginController.getInstance().isLoginPossible(client, _serverId)) + if ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) || ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) && (client.getAccessLevel() < 1))) + { + client.close(LoginFailReason.REASON_ACCESS_FAILED); + } + else if (LoginController.getInstance().isLoginPossible(client, _serverId)) { client.setJoinedGS(true); client.sendPacket(new PlayOk(sk)); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/ui/Gui.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/ui/Gui.java new file mode 100644 index 0000000000..7dfddb4985 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/ui/Gui.java @@ -0,0 +1,275 @@ +/* + * 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.loginserver.ui; + +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.loginserver.GameServerTable; +import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; +import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmLoginServer; + JTextArea txtrConsole; + + JCheckBoxMenuItem chckbxmntmEnabled; + JCheckBoxMenuItem chckbxmntmDisabled; + JCheckBoxMenuItem chckbxmntmGmOnly; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + + public Gui() + { + frmLoginServer = new JFrame(); + frmLoginServer.setVisible(false); + frmLoginServer.setTitle("Mobius - LoginServer"); + frmLoginServer.setResizable(false); + frmLoginServer.setBounds(100, 100, 825, 618); + frmLoginServer.getContentPane().setLayout(null); + frmLoginServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmLoginServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmLoginServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmLoginServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(true); + } + }); + mnActions.add(mntmRestart); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmBannedIps = new JMenuItem("Banned IPs"); + mntmBannedIps.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBannedIps.addActionListener(arg0 -> + { + LoginController.getInstance().getBannedIps().clear(); + LoginServer.getInstance().loadBanFile(); + }); + mnReload.add(mntmBannedIps); + + JMenu mnStatus = new JMenu("Status"); + mnStatus.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnStatus); + + chckbxmntmEnabled = new JCheckBoxMenuItem("Enabled"); + chckbxmntmEnabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmEnabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(true); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_NORMAL); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_NORMAL); + } + LoginServer.getInstance().LOGGER.info("Status changed to enabled."); + }); + chckbxmntmEnabled.setSelected(true); + mnStatus.add(chckbxmntmEnabled); + + chckbxmntmDisabled = new JCheckBoxMenuItem("Disabled"); + chckbxmntmDisabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmDisabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(true); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_DOWN); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_DOWN); + } + LoginServer.getInstance().LOGGER.info("Status changed to disabled."); + }); + mnStatus.add(chckbxmntmDisabled); + + chckbxmntmGmOnly = new JCheckBoxMenuItem("GM only"); + chckbxmntmGmOnly.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmGmOnly.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(true); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_GM_ONLY); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_GM_ONLY); + } + LoginServer.getInstance().LOGGER.info("Status changed to GM only."); + }); + mnStatus.add(chckbxmntmGmOnly); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmLoginServer.setIconImages(icons); + + // Center frame to screen. + frmLoginServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmLoginServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/ui/frmAbout.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/ui/frmAbout.java new file mode 100644 index 0000000000..b535d860b6 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/loginserver/ui/frmAbout.java @@ -0,0 +1,115 @@ +/* + * 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.loginserver.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblLoginServer = new JLabel("Login Server"); + lblLoginServer.setHorizontalAlignment(SwingConstants.CENTER); + lblLoginServer.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblLoginServer.setBounds(10, 86, 271, 23); + frmAbout.getContentPane().add(lblLoginServer); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_3.0_Helios/build.xml b/L2J_Mobius_3.0_Helios/build.xml index fa64c28576..c2a71bb17c 100644 --- a/L2J_Mobius_3.0_Helios/build.xml +++ b/L2J_Mobius_3.0_Helios/build.xml @@ -78,8 +78,8 @@ - - + + @@ -93,8 +93,8 @@ - - + + @@ -108,8 +108,8 @@ - - + + @@ -123,8 +123,8 @@ - - + + diff --git a/L2J_Mobius_3.0_Helios/dist/game/GameServer.bat b/L2J_Mobius_3.0_Helios/dist/game/GameServer.bat deleted file mode 100644 index 2dbaac7089..0000000000 --- a/L2J_Mobius_3.0_Helios/dist/game/GameServer.bat +++ /dev/null @@ -1,30 +0,0 @@ -@set /p parameters=. + */ +package com.l2jmobius.commons.util; + +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; + +/* + * A class to control the maximum number of lines to be stored in a Document + * + * Excess lines can be removed from the start or end of the Document + * depending on your requirement. + * + * a) if you append text to the Document, then you would want to remove lines + * from the start. + * b) if you insert text at the beginning of the Document, then you would + * want to remove lines from the end. + */ +public class LimitLinesDocumentListener implements DocumentListener +{ + private int _maximumLines; + private final boolean _isRemoveFromStart; + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start of the Document. + */ + public LimitLinesDocumentListener(int maximumLines) + { + this(maximumLines, true); + } + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start or end of the Document, depending on the boolean value specified. + */ + public LimitLinesDocumentListener(int maximumLines, boolean isRemoveFromStart) + { + setLimitLines(maximumLines); + _isRemoveFromStart = isRemoveFromStart; + } + + /* + * Return the maximum number of lines to be stored in the Document. + */ + public int getLimitLines() + { + return _maximumLines; + } + + /* + * Set the maximum number of lines to be stored in the Document. + */ + public void setLimitLines(int maximumLines) + { + if (maximumLines < 1) + { + String message = "Maximum lines must be greater than 0"; + throw new IllegalArgumentException(message); + } + + _maximumLines = maximumLines; + } + + /* + * Handle insertion of new text into the Document. + */ + @Override + public void insertUpdate(final DocumentEvent e) + { + // Changes to the Document can not be done within the listener so we need to add the processing to the end of the EDT. + SwingUtilities.invokeLater(() -> removeLines(e)); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + } + + @Override + public void changedUpdate(DocumentEvent e) + { + } + + /* + * Remove lines from the Document when necessary. + */ + private void removeLines(DocumentEvent e) + { + // The root Element of the Document will tell us the total number of line in the Document. + Document document = e.getDocument(); + Element root = document.getDefaultRootElement(); + + while (root.getElementCount() > _maximumLines) + { + if (_isRemoveFromStart) + { + removeFromStart(document, root); + } + else + { + removeFromEnd(document, root); + } + } + } + + /* + * Remove lines from the start of the Document + */ + private void removeFromStart(Document document, Element root) + { + Element line = root.getElement(0); + int end = line.getEndOffset(); + + try + { + document.remove(0, end); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } + + /* + * Remove lines from the end of the Document + */ + private void removeFromEnd(Document document, Element root) + { + // We use start minus 1 to make sure we remove the newline character of the previous line. + + Element line = root.getElement(root.getElementCount() - 1); + int start = line.getStartOffset(); + int end = line.getEndOffset(); + + try + { + document.remove(start - 1, end - start); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/commons/util/SplashScreen.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/commons/util/SplashScreen.java index 80992f1b4d..5086e53e9c 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/commons/util/SplashScreen.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/commons/util/SplashScreen.java @@ -21,8 +21,8 @@ import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Timer; +import java.util.TimerTask; import javax.swing.ImageIcon; import javax.swing.JFrame; @@ -52,22 +52,24 @@ public class SplashScreen extends JWindow setAlwaysOnTop(true); setVisible(true); - // Schedule to close. - Executors.newScheduledThreadPool(1).schedule(this::close, imageIcon.getIconWidth() > 0 ? time : 100, TimeUnit.MILLISECONDS); - } - - public void close() - { - setVisible(false); - if (parentFrame != null) + new Timer().schedule(new TimerTask() { - // Make parent visible. - parentFrame.setVisible(true); - // Focus parent window. - parentFrame.toFront(); - parentFrame.setState(Frame.ICONIFIED); - parentFrame.setState(Frame.NORMAL); - } + @Override + public void run() + { + setVisible(false); + if (parentFrame != null) + { + // Make parent visible. + parentFrame.setVisible(true); + // Focus parent window. + parentFrame.toFront(); + parentFrame.setState(Frame.ICONIFIED); + parentFrame.setState(Frame.NORMAL); + } + dispose(); + } + }, imageIcon.getIconWidth() > 0 ? time : 100); } @Override diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java index dafad09f2e..298b937c28 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.gameserver; +import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.io.File; import java.io.FileInputStream; @@ -149,6 +150,7 @@ import com.l2jmobius.gameserver.network.loginserver.LoginServerNetworkManager; import com.l2jmobius.gameserver.network.telnet.TelnetServer; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.taskmanager.TaskManager; +import com.l2jmobius.gameserver.ui.Gui; import com.l2jmobius.gameserver.util.Broadcast; public class GameServer @@ -172,6 +174,28 @@ public class GameServer public GameServer() throws Exception { final long serverLoadStart = System.currentTimeMillis(); + Server.serverMode = Server.MODE_GAMESERVER; + + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + + // Create log folder + final File logFolder = new File(Config.DATAPACK_ROOT, "log"); + logFolder.mkdir(); + + // Create input stream for log file -- or store file data into memory + try (InputStream is = new FileInputStream(new File("./log.cfg"))) + { + LogManager.getLogManager().readConfiguration(is); + } + + // Initialize config + Config.load(); + printSection("Database"); + DatabaseFactory.getInstance(); printSection("ThreadPool"); ThreadPool.init(); @@ -459,24 +483,6 @@ public class GameServer public static void main(String[] args) throws Exception { - Server.serverMode = Server.MODE_GAMESERVER; - - /*** Main ***/ - // Create log folder - final File logFolder = new File(Config.DATAPACK_ROOT, "log"); - logFolder.mkdir(); - - // Create input stream for log file -- or store file data into memory - try (InputStream is = new FileInputStream(new File("./log.cfg"))) - { - LogManager.getLogManager().readConfiguration(is); - } - - // Initialize config - Config.load(); - printSection("Database"); - DatabaseFactory.getInstance(); - INSTANCE = new GameServer(); } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java index 9a1a01c8a6..625915e123 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java @@ -28,6 +28,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.gameserver.LoginServerThread; import com.l2jmobius.gameserver.enums.PrivateStoreType; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.L2ManufactureItem; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.TradeItem; @@ -298,6 +299,7 @@ public class OfflineTradersTable player.setOnlineStatus(true, true); player.restoreEffects(); player.broadcastUserInfo(); + PlayerCountManager.getInstance().incOfflineTradeCount(); nTraders++; } catch (Exception e) @@ -451,6 +453,8 @@ public class OfflineTradersTable public static synchronized void removeTrader(int traderObjId) { + PlayerCountManager.getInstance().decOfflineTradeCount(); + try (Connection con = DatabaseFactory.getInstance().getConnection(); PreparedStatement stm1 = con.prepareStatement(CLEAR_OFFLINE_TABLE_ITEMS_PLAYER); PreparedStatement stm2 = con.prepareStatement(CLEAR_OFFLINE_TABLE_PLAYER)) diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java new file mode 100644 index 0000000000..cb2fab84ed --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java @@ -0,0 +1,77 @@ +/* + * 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.instancemanager; + +/** + * @author Mobius + */ +public class PlayerCountManager +{ + private volatile static int connectedCount = 0; + private volatile static int maxConnectedCount = 0; + private volatile static int offlineTradeCount = 0; + + protected PlayerCountManager() + { + } + + public int getConnectedCount() + { + return connectedCount; + } + + public int getMaxConnectedCount() + { + return maxConnectedCount; + } + + public int getOfflineTradeCount() + { + return offlineTradeCount; + } + + public synchronized void incConnectedCount() + { + connectedCount++; + maxConnectedCount = Math.max(maxConnectedCount, connectedCount); + } + + public void decConnectedCount() + { + connectedCount--; + } + + public void incOfflineTradeCount() + { + offlineTradeCount++; + } + + public synchronized void decOfflineTradeCount() + { + offlineTradeCount = Math.max(0, offlineTradeCount - 1); + } + + public static PlayerCountManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final PlayerCountManager INSTANCE = new PlayerCountManager(); + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2World.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2World.java index 9b02364b07..bea222354b 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2World.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2World.java @@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -135,6 +136,8 @@ public final class L2World if (object.isPlayer()) { + PlayerCountManager.getInstance().incConnectedCount(); + final L2PcInstance newPlayer = (L2PcInstance) object; if (newPlayer.isTeleporting()) // TODO: drop when we stop removing player from the world while teleporting. { @@ -170,6 +173,8 @@ public final class L2World _allObjects.remove(object.getObjectId()); if (object.isPlayer()) { + PlayerCountManager.getInstance().decConnectedCount(); + final L2PcInstance player = (L2PcInstance) object; if (player.isTeleporting()) // TODO: drop when we stop removing player from the world while teleportingq. { diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/Gui.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/Gui.java new file mode 100644 index 0000000000..9f8c2a41a6 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/Gui.java @@ -0,0 +1,370 @@ +/* + * 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.ui; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.gameserver.Shutdown; +import com.l2jmobius.gameserver.cache.HtmCache; +import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.BuyListData; +import com.l2jmobius.gameserver.data.xml.impl.MultisellData; +import com.l2jmobius.gameserver.data.xml.impl.PrimeShopData; +import com.l2jmobius.gameserver.util.Broadcast; +import com.l2jmobius.gameserver.util.Util; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmGameServer; + JTextArea txtrConsole; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + final static String[] abortOptions = + { + "Abort", + "Cancel" + }; + final static String[] confirmOptions = + { + "Confirm", + "Cancel" + }; + + public Gui() + { + frmGameServer = new JFrame(); + frmGameServer.setVisible(false); + frmGameServer.setTitle("Mobius - GameServer"); + frmGameServer.setResizable(false); + frmGameServer.setBounds(100, 100, 825, 618); + frmGameServer.getContentPane().setLayout(null); + frmGameServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmGameServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown server immediately?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + Shutdown.getInstance().startShutdown(null, 1, false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmGameServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmGameServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Shutdown delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, false); + } + } + } + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Restart delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, true); + } + } + } + } + }); + mnActions.add(mntmRestart); + + JMenuItem mntmAbort = new JMenuItem("Abort"); + mntmAbort.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbort.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Abort server shutdown?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, abortOptions, abortOptions[1]) == 0) + { + Shutdown.getInstance().abort(null); + } + }); + mnActions.add(mntmAbort); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmConfigs = new JMenuItem("Configs"); + mntmConfigs.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmConfigs.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload configs?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + Config.load(); + } + }); + mnReload.add(mntmConfigs); + + JMenuItem mntmAccess = new JMenuItem("Access"); + mntmAccess.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAccess.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload admin access levels?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + AdminData.getInstance().load(); + } + }); + mnReload.add(mntmAccess); + + JMenuItem mntmHtml = new JMenuItem("HTML"); + mntmHtml.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmHtml.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload HTML files?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + HtmCache.getInstance().reload(); + } + }); + mnReload.add(mntmHtml); + + JMenuItem mntmMultisells = new JMenuItem("Multisells"); + mntmMultisells.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmMultisells.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload multisells?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + MultisellData.getInstance().load(); + } + }); + mnReload.add(mntmMultisells); + + JMenuItem mntmBuylists = new JMenuItem("Buylists"); + mntmBuylists.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBuylists.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload buylists?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + BuyListData.getInstance().load(); + } + }); + mnReload.add(mntmBuylists); + + JMenuItem mntmPrimeShop = new JMenuItem("PrimeShop"); + mntmPrimeShop.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmPrimeShop.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload PrimeShop?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + PrimeShopData.getInstance().load(); + } + }); + mnReload.add(mntmPrimeShop); + + JMenu mnAnnounce = new JMenu("Announce"); + mnAnnounce.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnAnnounce); + + JMenuItem mntmNormal = new JMenuItem("Normal"); + mntmNormal.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmNormal.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, false); + } + } + }); + mnAnnounce.add(mntmNormal); + + JMenuItem mntmCritical = new JMenuItem("Critical"); + mntmCritical.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmCritical.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Critical announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, true); + } + } + }); + mnAnnounce.add(mntmCritical); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmGameServer.setIconImages(icons); + + // System Panel. + JPanel systemPanel = new SystemPanel(); + JLayeredPane layeredPanel = new JLayeredPane(); + frmGameServer.getContentPane().add(layeredPanel, BorderLayout.CENTER); + layeredPanel.setBounds(0, 0, 819, 566); + layeredPanel.add(scrollPanel, new Integer(0), 0); + layeredPanel.add(systemPanel, new Integer(1), 0); + + // Center frame to screen. + frmGameServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmGameServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/Locator.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/Locator.java new file mode 100644 index 0000000000..e891609b67 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/Locator.java @@ -0,0 +1,295 @@ +/* + * 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.ui; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Locale; + +final class Locator +{ + /** + * Constructor for Locator. + */ + private Locator() + { + } + + /** + * Method getClassSource. + * @param c Class + * @return File + */ + static File getClassSource(Class c) + { + String classResource = c.getName().replace('.', '/') + ".class"; + return getResourceSource(c.getClassLoader(), classResource); + } + + /** + * Method getResourceSource. + * @param c ClassLoader + * @param resource String + * @return File + */ + private static File getResourceSource(ClassLoader c, String resource) + { + if (c == null) + { + c = Locator.class.getClassLoader(); + } + + URL url = null; + + if (c == null) + { + url = ClassLoader.getSystemResource(resource); + } + else + { + url = c.getResource(resource); + } + + if (url != null) + { + String u = url.toString(); + + if (u.startsWith("jar:file:")) + { + int pling = u.indexOf("!"); + String jarName = u.substring(4, pling); + return new File(fromURI(jarName)); + } + else if (u.startsWith("file:")) + { + int tail = u.indexOf(resource); + String dirName = u.substring(0, tail); + return new File(fromURI(dirName)); + } + } + + return null; + } + + /** + * Method fromURI. + * @param uri String + * @return String + */ + private static String fromURI(String uri) + { + URL url = null; + + try + { + url = new URL(uri); + } + catch (MalformedURLException emYouEarlEx) + { + // empty catch clause + } + + if ((url == null) || !"file".equals(url.getProtocol())) + { + throw new IllegalArgumentException("Can only handle valid file: URIs"); + } + + StringBuilder buf = new StringBuilder(url.getHost()); + + if (buf.length() > 0) + { + buf.insert(0, File.separatorChar).insert(0, File.separatorChar); + } + + String file = url.getFile(); + int queryPos = file.indexOf('?'); + buf.append(queryPos < 0 ? file : file.substring(0, queryPos)); + uri = buf.toString().replace('/', File.separatorChar); + + if ((File.pathSeparatorChar == ';') && uri.startsWith("\\") && (uri.length() > 2) && Character.isLetter(uri.charAt(1)) && (uri.lastIndexOf(':') > -1)) + { + uri = uri.substring(1); + } + + String path = decodeUri(uri); + return path; + } + + /** + * Method decodeUri. + * @param uri String + * @return String + */ + private static String decodeUri(String uri) + { + if (uri.indexOf('%') == -1) + { + return uri; + } + + StringBuilder sb = new StringBuilder(); + CharacterIterator iter = new StringCharacterIterator(uri); + + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + { + if (c == '%') + { + char c1 = iter.next(); + + if (c1 != CharacterIterator.DONE) + { + int i1 = Character.digit(c1, 16); + char c2 = iter.next(); + + if (c2 != CharacterIterator.DONE) + { + int i2 = Character.digit(c2, 16); + sb.append((char) ((i1 << 4) + i2)); + } + } + } + else + { + sb.append(c); + } + } + + String path = sb.toString(); + return path; + } + + /** + * Method getToolsJar. + * @return File + */ + static File getToolsJar() + { + boolean toolsJarAvailable = false; + + try + { + Class.forName("com.sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e) + { + try + { + Class.forName("sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e2) + { + // empty catch clause + } + } + + if (toolsJarAvailable) + { + return null; + } + + String javaHome = System.getProperty("java.home"); + + if (javaHome.toLowerCase(Locale.US).endsWith("jre")) + { + javaHome = javaHome.substring(0, javaHome.length() - 4); + } + + File toolsJar = new File(javaHome + "/lib/tools.jar"); + + if (!toolsJar.exists()) + { + System.out.println("Unable to locate tools.jar. " + "Expected to find it in " + toolsJar.getPath()); + return null; + } + + return toolsJar; + } + + /** + * Method getLocationURLs. + * @param location File + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + static URL[] getLocationURLs(File location) throws MalformedURLException + { + return getLocationURLs(location, new String[] + { + ".jar" + }); + } + + /** + * Method getLocationURLs. + * @param location File + * @param extensions String[] + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + private static URL[] getLocationURLs(File location, final String[] extensions) throws MalformedURLException + { + URL[] urls = new URL[0]; + + if (!location.exists()) + { + return urls; + } + + if (!location.isDirectory()) + { + urls = new URL[1]; + String path = location.getPath(); + + for (String extension : extensions) + { + if (path.toLowerCase().endsWith(extension)) + { + urls[0] = location.toURI().toURL(); + break; + } + } + + return urls; + } + + File[] matches = location.listFiles((FilenameFilter) (dir, name) -> + { + for (String extension : extensions) + { + if (name.toLowerCase().endsWith(extension)) + { + return true; + } + } + return false; + }); + urls = new URL[matches.length]; + + for (int i = 0; i < matches.length; ++i) + { + urls[i] = matches[i].toURI().toURL(); + } + + return urls; + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/SystemPanel.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/SystemPanel.java new file mode 100644 index 0000000000..68cabb3c12 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/SystemPanel.java @@ -0,0 +1,142 @@ +/* + * 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.ui; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.LineBorder; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.GameServer; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; + +/** + * @author Mobius + */ +public class SystemPanel extends JPanel +{ + final static long startTime = System.currentTimeMillis(); + + public SystemPanel() + { + setBackground(Color.WHITE); + setBounds(500, 20, 284, 140); + setBorder(new LineBorder(new Color(0, 0, 0), 1, false)); + setOpaque(true); + setLayout(null); + + JLabel lblProtocol = new JLabel("Protocol"); + lblProtocol.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblProtocol.setBounds(10, 5, 264, 17); + add(lblProtocol); + + JLabel lblConnected = new JLabel("Connected"); + lblConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblConnected.setBounds(10, 23, 264, 17); + add(lblConnected); + + JLabel lblMaxConnected = new JLabel("Max connected"); + lblMaxConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblMaxConnected.setBounds(10, 41, 264, 17); + add(lblMaxConnected); + + JLabel lblOfflineShops = new JLabel("Offline trade"); + lblOfflineShops.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblOfflineShops.setBounds(10, 59, 264, 17); + add(lblOfflineShops); + + JLabel lblElapsedTime = new JLabel("Elapsed time"); + lblElapsedTime.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblElapsedTime.setBounds(10, 77, 264, 17); + add(lblElapsedTime); + + JLabel lblJavaVersion = new JLabel("Build JDK"); + lblJavaVersion.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblJavaVersion.setBounds(10, 95, 264, 17); + add(lblJavaVersion); + + JLabel lblBuildDate = new JLabel("Build date"); + lblBuildDate.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblBuildDate.setBounds(10, 113, 264, 17); + add(lblBuildDate); + + // Set initial values. + lblProtocol.setText("Protocol: 0"); + lblConnected.setText("Connected: 0"); + lblMaxConnected.setText("Max connected: 0"); + lblOfflineShops.setText("Offline trade: 0"); + lblElapsedTime.setText("Elapsed: 0 sec"); + lblJavaVersion.setText("Java version: " + System.getProperty("java.version")); + lblBuildDate.setText("Build date: Unavailable"); + try + { + File jarName = Locator.getClassSource(GameServer.class); + JarFile jarFile = new JarFile(jarName); + Attributes attrs = jarFile.getManifest().getMainAttributes(); + lblBuildDate.setText("Build date: " + attrs.getValue("Build-Date").split(" ")[0]); + jarFile.close(); + } + catch (Exception e) + { + } + + // Initial update task. + new Timer().schedule(new TimerTask() + { + @Override + public void run() + { + lblProtocol.setText((Config.PROTOCOL_LIST.size() > 1 ? "Protocols: " : "Protocol: ") + Config.PROTOCOL_LIST.toString()); + } + }, 4500); + + // Repeating elapsed time task. + new Timer().scheduleAtFixedRate(new TimerTask() + { + @Override + public void run() + { + lblConnected.setText("Connected: " + PlayerCountManager.getInstance().getConnectedCount()); + lblMaxConnected.setText("Max connected: " + PlayerCountManager.getInstance().getMaxConnectedCount()); + lblOfflineShops.setText("Offline trade: " + PlayerCountManager.getInstance().getOfflineTradeCount()); + lblElapsedTime.setText("Elapsed: " + getDurationBreakdown(System.currentTimeMillis() - startTime)); + } + }, 1000, 1000); + } + + static String getDurationBreakdown(long millis) + { + long days = TimeUnit.MILLISECONDS.toDays(millis); + millis -= TimeUnit.DAYS.toMillis(days); + long hours = TimeUnit.MILLISECONDS.toHours(millis); + millis -= TimeUnit.HOURS.toMillis(hours); + long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); + millis -= TimeUnit.MINUTES.toMillis(minutes); + long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); + + return (days + "d " + hours + "h " + minutes + "m " + seconds + "s"); + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/frmAbout.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/frmAbout.java new file mode 100644 index 0000000000..e8a4f9a47c --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ui/frmAbout.java @@ -0,0 +1,143 @@ +/* + * 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.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblSupports = new JLabel("Server Protocol"); + lblSupports.setHorizontalAlignment(SwingConstants.CENTER); + lblSupports.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblSupports.setBounds(10, 78, 271, 23); + frmAbout.getContentPane().add(lblSupports); + + JLabel lblProtocols = new JLabel("Protocol Number"); + lblProtocols.setHorizontalAlignment(SwingConstants.CENTER); + lblProtocols.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblProtocols.setBounds(10, 92, 271, 23); + frmAbout.getContentPane().add(lblProtocols); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Generate protocols text. + String protocols = ""; + if (Config.PROTOCOL_LIST.size() > 1) + { + for (Integer number : Config.PROTOCOL_LIST) + { + if (!protocols.isEmpty()) + { + protocols += " - "; + } + protocols += number; + } + lblSupports.setText("Server Protocols"); + } + else + { + protocols += Config.PROTOCOL_LIST.get(0); + } + lblProtocols.setText(protocols); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java index ecc40e644b..056fa7ea38 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java @@ -20,6 +20,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Summon; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.olympiad.OlympiadManager; @@ -100,6 +101,8 @@ public final class OfflineTradeUtil return false; } + PlayerCountManager.getInstance().incOfflineTradeCount(); + final L2GameClient client = player.getClient(); client.setDetached(true); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/GameServerTable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/GameServerTable.java index 362aa93ad5..73110fb6dc 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/GameServerTable.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/GameServerTable.java @@ -409,7 +409,18 @@ public final class GameServerTable implements IGameXmlReader */ public void setStatus(int status) { - _status = status; + if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) + { + _status = ServerStatus.STATUS_DOWN; + } + else if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) + { + _status = ServerStatus.STATUS_GM_ONLY; + } + else + { + _status = status; + } } /** diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/LoginServer.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/LoginServer.java index 6c2062e622..39377afee3 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/LoginServer.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/LoginServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.loginserver; +import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -32,35 +33,43 @@ import com.l2jmobius.Config; import com.l2jmobius.Server; import com.l2jmobius.commons.database.DatabaseBackup; import com.l2jmobius.commons.database.DatabaseFactory; +import com.l2jmobius.gameserver.network.loginserverpackets.game.ServerStatus; import com.l2jmobius.loginserver.network.ClientNetworkManager; +import com.l2jmobius.loginserver.ui.Gui; /** * @author KenM */ public final class LoginServer { - private final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); + public final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); public static final int PROTOCOL_REV = 0x0106; - private static LoginServer _instance; + private static LoginServer INSTANCE; private GameServerListener _gameServerListener; private Thread _restartLoginServer; + private static int _loginStatus = ServerStatus.STATUS_NORMAL; public static void main(String[] args) throws Exception { - new LoginServer(); + INSTANCE = new LoginServer(); } public static LoginServer getInstance() { - return _instance; + return INSTANCE; } private LoginServer() throws Exception { - _instance = this; Server.serverMode = Server.MODE_LOGINSERVER; + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + // Create log folder final File logFolder = new File(".", "log"); logFolder.mkdir(); @@ -96,6 +105,14 @@ public final class LoginServer loadBanFile(); + if (Config.LOGIN_SERVER_SCHEDULE_RESTART) + { + LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); + _restartLoginServer = new LoginServerRestart(); + _restartLoginServer.setDaemon(true); + _restartLoginServer.start(); + } + try { _gameServerListener = new GameServerListener(); @@ -116,7 +133,7 @@ public final class LoginServer return _gameServerListener; } - private void loadBanFile() + public void loadBanFile() { final File bannedFile = new File("./banned_ip.cfg"); if (bannedFile.exists() && bannedFile.isFile()) @@ -170,14 +187,6 @@ public final class LoginServer { LOGGER.warning("IP Bans file (" + bannedFile.getName() + ") is missing or is a directory, skipped."); } - - if (Config.LOGIN_SERVER_SCHEDULE_RESTART) - { - LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); - _restartLoginServer = new LoginServerRestart(); - _restartLoginServer.setDaemon(true); - _restartLoginServer.start(); - } } class LoginServerRestart extends Thread @@ -213,4 +222,14 @@ public final class LoginServer } Runtime.getRuntime().exit(restart ? 2 : 0); } + + public int getStatus() + { + return _loginStatus; + } + + public void setStatus(int status) + { + _loginStatus = status; + } } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java index 670365b761..fa5c1e0a3a 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java @@ -20,8 +20,10 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.IIncomingPacket; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.network.L2LoginClient; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayOk; @@ -61,7 +63,11 @@ public class RequestServerLogin implements IIncomingPacket // if we didnt showed the license we cant check these values if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2)) { - if (LoginController.getInstance().isLoginPossible(client, _serverId)) + if ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) || ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) && (client.getAccessLevel() < 1))) + { + client.close(LoginFailReason.REASON_ACCESS_FAILED); + } + else if (LoginController.getInstance().isLoginPossible(client, _serverId)) { client.setJoinedGS(true); client.sendPacket(new PlayOk(sk)); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/ui/Gui.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/ui/Gui.java new file mode 100644 index 0000000000..7dfddb4985 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/ui/Gui.java @@ -0,0 +1,275 @@ +/* + * 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.loginserver.ui; + +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.loginserver.GameServerTable; +import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; +import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmLoginServer; + JTextArea txtrConsole; + + JCheckBoxMenuItem chckbxmntmEnabled; + JCheckBoxMenuItem chckbxmntmDisabled; + JCheckBoxMenuItem chckbxmntmGmOnly; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + + public Gui() + { + frmLoginServer = new JFrame(); + frmLoginServer.setVisible(false); + frmLoginServer.setTitle("Mobius - LoginServer"); + frmLoginServer.setResizable(false); + frmLoginServer.setBounds(100, 100, 825, 618); + frmLoginServer.getContentPane().setLayout(null); + frmLoginServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmLoginServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmLoginServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmLoginServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(true); + } + }); + mnActions.add(mntmRestart); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmBannedIps = new JMenuItem("Banned IPs"); + mntmBannedIps.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBannedIps.addActionListener(arg0 -> + { + LoginController.getInstance().getBannedIps().clear(); + LoginServer.getInstance().loadBanFile(); + }); + mnReload.add(mntmBannedIps); + + JMenu mnStatus = new JMenu("Status"); + mnStatus.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnStatus); + + chckbxmntmEnabled = new JCheckBoxMenuItem("Enabled"); + chckbxmntmEnabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmEnabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(true); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_NORMAL); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_NORMAL); + } + LoginServer.getInstance().LOGGER.info("Status changed to enabled."); + }); + chckbxmntmEnabled.setSelected(true); + mnStatus.add(chckbxmntmEnabled); + + chckbxmntmDisabled = new JCheckBoxMenuItem("Disabled"); + chckbxmntmDisabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmDisabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(true); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_DOWN); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_DOWN); + } + LoginServer.getInstance().LOGGER.info("Status changed to disabled."); + }); + mnStatus.add(chckbxmntmDisabled); + + chckbxmntmGmOnly = new JCheckBoxMenuItem("GM only"); + chckbxmntmGmOnly.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmGmOnly.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(true); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_GM_ONLY); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_GM_ONLY); + } + LoginServer.getInstance().LOGGER.info("Status changed to GM only."); + }); + mnStatus.add(chckbxmntmGmOnly); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmLoginServer.setIconImages(icons); + + // Center frame to screen. + frmLoginServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmLoginServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/ui/frmAbout.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/ui/frmAbout.java new file mode 100644 index 0000000000..b535d860b6 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/loginserver/ui/frmAbout.java @@ -0,0 +1,115 @@ +/* + * 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.loginserver.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblLoginServer = new JLabel("Login Server"); + lblLoginServer.setHorizontalAlignment(SwingConstants.CENTER); + lblLoginServer.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblLoginServer.setBounds(10, 86, 271, 23); + frmAbout.getContentPane().add(lblLoginServer); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/build.xml b/L2J_Mobius_4.0_GrandCrusade/build.xml index 5207ce69f8..4335650c76 100644 --- a/L2J_Mobius_4.0_GrandCrusade/build.xml +++ b/L2J_Mobius_4.0_GrandCrusade/build.xml @@ -78,8 +78,8 @@ - - + + @@ -93,8 +93,8 @@ - - + + @@ -108,8 +108,8 @@ - - + + @@ -123,8 +123,8 @@ - - + + diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/GameServer.bat b/L2J_Mobius_4.0_GrandCrusade/dist/game/GameServer.bat deleted file mode 100644 index 2dbaac7089..0000000000 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/GameServer.bat +++ /dev/null @@ -1,30 +0,0 @@ -@set /p parameters=. + */ +package com.l2jmobius.commons.util; + +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; + +/* + * A class to control the maximum number of lines to be stored in a Document + * + * Excess lines can be removed from the start or end of the Document + * depending on your requirement. + * + * a) if you append text to the Document, then you would want to remove lines + * from the start. + * b) if you insert text at the beginning of the Document, then you would + * want to remove lines from the end. + */ +public class LimitLinesDocumentListener implements DocumentListener +{ + private int _maximumLines; + private final boolean _isRemoveFromStart; + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start of the Document. + */ + public LimitLinesDocumentListener(int maximumLines) + { + this(maximumLines, true); + } + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start or end of the Document, depending on the boolean value specified. + */ + public LimitLinesDocumentListener(int maximumLines, boolean isRemoveFromStart) + { + setLimitLines(maximumLines); + _isRemoveFromStart = isRemoveFromStart; + } + + /* + * Return the maximum number of lines to be stored in the Document. + */ + public int getLimitLines() + { + return _maximumLines; + } + + /* + * Set the maximum number of lines to be stored in the Document. + */ + public void setLimitLines(int maximumLines) + { + if (maximumLines < 1) + { + String message = "Maximum lines must be greater than 0"; + throw new IllegalArgumentException(message); + } + + _maximumLines = maximumLines; + } + + /* + * Handle insertion of new text into the Document. + */ + @Override + public void insertUpdate(final DocumentEvent e) + { + // Changes to the Document can not be done within the listener so we need to add the processing to the end of the EDT. + SwingUtilities.invokeLater(() -> removeLines(e)); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + } + + @Override + public void changedUpdate(DocumentEvent e) + { + } + + /* + * Remove lines from the Document when necessary. + */ + private void removeLines(DocumentEvent e) + { + // The root Element of the Document will tell us the total number of line in the Document. + Document document = e.getDocument(); + Element root = document.getDefaultRootElement(); + + while (root.getElementCount() > _maximumLines) + { + if (_isRemoveFromStart) + { + removeFromStart(document, root); + } + else + { + removeFromEnd(document, root); + } + } + } + + /* + * Remove lines from the start of the Document + */ + private void removeFromStart(Document document, Element root) + { + Element line = root.getElement(0); + int end = line.getEndOffset(); + + try + { + document.remove(0, end); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } + + /* + * Remove lines from the end of the Document + */ + private void removeFromEnd(Document document, Element root) + { + // We use start minus 1 to make sure we remove the newline character of the previous line. + + Element line = root.getElement(root.getElementCount() - 1); + int start = line.getStartOffset(); + int end = line.getEndOffset(); + + try + { + document.remove(start - 1, end - start); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/commons/util/SplashScreen.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/commons/util/SplashScreen.java index 80992f1b4d..5086e53e9c 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/commons/util/SplashScreen.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/commons/util/SplashScreen.java @@ -21,8 +21,8 @@ import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Timer; +import java.util.TimerTask; import javax.swing.ImageIcon; import javax.swing.JFrame; @@ -52,22 +52,24 @@ public class SplashScreen extends JWindow setAlwaysOnTop(true); setVisible(true); - // Schedule to close. - Executors.newScheduledThreadPool(1).schedule(this::close, imageIcon.getIconWidth() > 0 ? time : 100, TimeUnit.MILLISECONDS); - } - - public void close() - { - setVisible(false); - if (parentFrame != null) + new Timer().schedule(new TimerTask() { - // Make parent visible. - parentFrame.setVisible(true); - // Focus parent window. - parentFrame.toFront(); - parentFrame.setState(Frame.ICONIFIED); - parentFrame.setState(Frame.NORMAL); - } + @Override + public void run() + { + setVisible(false); + if (parentFrame != null) + { + // Make parent visible. + parentFrame.setVisible(true); + // Focus parent window. + parentFrame.toFront(); + parentFrame.setState(Frame.ICONIFIED); + parentFrame.setState(Frame.NORMAL); + } + dispose(); + } + }, imageIcon.getIconWidth() > 0 ? time : 100); } @Override diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java index bf94971882..bd228cb89d 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.gameserver; +import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.io.File; import java.io.FileInputStream; @@ -149,6 +150,7 @@ import com.l2jmobius.gameserver.network.loginserver.LoginServerNetworkManager; import com.l2jmobius.gameserver.network.telnet.TelnetServer; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.taskmanager.TaskManager; +import com.l2jmobius.gameserver.ui.Gui; import com.l2jmobius.gameserver.util.Broadcast; public class GameServer @@ -172,6 +174,28 @@ public class GameServer public GameServer() throws Exception { final long serverLoadStart = System.currentTimeMillis(); + Server.serverMode = Server.MODE_GAMESERVER; + + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + + // Create log folder + final File logFolder = new File(Config.DATAPACK_ROOT, "log"); + logFolder.mkdir(); + + // Create input stream for log file -- or store file data into memory + try (InputStream is = new FileInputStream(new File("./log.cfg"))) + { + LogManager.getLogManager().readConfiguration(is); + } + + // Initialize config + Config.load(); + printSection("Database"); + DatabaseFactory.getInstance(); printSection("ThreadPool"); ThreadPool.init(); @@ -459,24 +483,6 @@ public class GameServer public static void main(String[] args) throws Exception { - Server.serverMode = Server.MODE_GAMESERVER; - - /*** Main ***/ - // Create log folder - final File logFolder = new File(Config.DATAPACK_ROOT, "log"); - logFolder.mkdir(); - - // Create input stream for log file -- or store file data into memory - try (InputStream is = new FileInputStream(new File("./log.cfg"))) - { - LogManager.getLogManager().readConfiguration(is); - } - - // Initialize config - Config.load(); - printSection("Database"); - DatabaseFactory.getInstance(); - INSTANCE = new GameServer(); } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java index bd32b469ac..7c4319c196 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java @@ -31,6 +31,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.gameserver.LoginServerThread; import com.l2jmobius.gameserver.enums.PrivateStoreType; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.TradeItem; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -302,6 +303,7 @@ public class OfflineTradersTable player.setOnlineStatus(true, true); player.restoreEffects(); player.broadcastUserInfo(); + PlayerCountManager.getInstance().incOfflineTradeCount(); nTraders++; } catch (Exception e) @@ -455,6 +457,8 @@ public class OfflineTradersTable public static synchronized void removeTrader(int traderObjId) { + PlayerCountManager.getInstance().decOfflineTradeCount(); + try (Connection con = DatabaseFactory.getInstance().getConnection(); PreparedStatement stm1 = con.prepareStatement(CLEAR_OFFLINE_TABLE_ITEMS_PLAYER); PreparedStatement stm2 = con.prepareStatement(CLEAR_OFFLINE_TABLE_PLAYER)) diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java new file mode 100644 index 0000000000..cb2fab84ed --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java @@ -0,0 +1,77 @@ +/* + * 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.instancemanager; + +/** + * @author Mobius + */ +public class PlayerCountManager +{ + private volatile static int connectedCount = 0; + private volatile static int maxConnectedCount = 0; + private volatile static int offlineTradeCount = 0; + + protected PlayerCountManager() + { + } + + public int getConnectedCount() + { + return connectedCount; + } + + public int getMaxConnectedCount() + { + return maxConnectedCount; + } + + public int getOfflineTradeCount() + { + return offlineTradeCount; + } + + public synchronized void incConnectedCount() + { + connectedCount++; + maxConnectedCount = Math.max(maxConnectedCount, connectedCount); + } + + public void decConnectedCount() + { + connectedCount--; + } + + public void incOfflineTradeCount() + { + offlineTradeCount++; + } + + public synchronized void decOfflineTradeCount() + { + offlineTradeCount = Math.max(0, offlineTradeCount - 1); + } + + public static PlayerCountManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final PlayerCountManager INSTANCE = new PlayerCountManager(); + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2World.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2World.java index 9b02364b07..bea222354b 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2World.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2World.java @@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -135,6 +136,8 @@ public final class L2World if (object.isPlayer()) { + PlayerCountManager.getInstance().incConnectedCount(); + final L2PcInstance newPlayer = (L2PcInstance) object; if (newPlayer.isTeleporting()) // TODO: drop when we stop removing player from the world while teleporting. { @@ -170,6 +173,8 @@ public final class L2World _allObjects.remove(object.getObjectId()); if (object.isPlayer()) { + PlayerCountManager.getInstance().decConnectedCount(); + final L2PcInstance player = (L2PcInstance) object; if (player.isTeleporting()) // TODO: drop when we stop removing player from the world while teleportingq. { diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/Gui.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/Gui.java new file mode 100644 index 0000000000..9f8c2a41a6 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/Gui.java @@ -0,0 +1,370 @@ +/* + * 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.ui; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.gameserver.Shutdown; +import com.l2jmobius.gameserver.cache.HtmCache; +import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.BuyListData; +import com.l2jmobius.gameserver.data.xml.impl.MultisellData; +import com.l2jmobius.gameserver.data.xml.impl.PrimeShopData; +import com.l2jmobius.gameserver.util.Broadcast; +import com.l2jmobius.gameserver.util.Util; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmGameServer; + JTextArea txtrConsole; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + final static String[] abortOptions = + { + "Abort", + "Cancel" + }; + final static String[] confirmOptions = + { + "Confirm", + "Cancel" + }; + + public Gui() + { + frmGameServer = new JFrame(); + frmGameServer.setVisible(false); + frmGameServer.setTitle("Mobius - GameServer"); + frmGameServer.setResizable(false); + frmGameServer.setBounds(100, 100, 825, 618); + frmGameServer.getContentPane().setLayout(null); + frmGameServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmGameServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown server immediately?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + Shutdown.getInstance().startShutdown(null, 1, false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmGameServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmGameServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Shutdown delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, false); + } + } + } + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Restart delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, true); + } + } + } + } + }); + mnActions.add(mntmRestart); + + JMenuItem mntmAbort = new JMenuItem("Abort"); + mntmAbort.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbort.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Abort server shutdown?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, abortOptions, abortOptions[1]) == 0) + { + Shutdown.getInstance().abort(null); + } + }); + mnActions.add(mntmAbort); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmConfigs = new JMenuItem("Configs"); + mntmConfigs.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmConfigs.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload configs?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + Config.load(); + } + }); + mnReload.add(mntmConfigs); + + JMenuItem mntmAccess = new JMenuItem("Access"); + mntmAccess.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAccess.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload admin access levels?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + AdminData.getInstance().load(); + } + }); + mnReload.add(mntmAccess); + + JMenuItem mntmHtml = new JMenuItem("HTML"); + mntmHtml.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmHtml.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload HTML files?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + HtmCache.getInstance().reload(); + } + }); + mnReload.add(mntmHtml); + + JMenuItem mntmMultisells = new JMenuItem("Multisells"); + mntmMultisells.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmMultisells.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload multisells?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + MultisellData.getInstance().load(); + } + }); + mnReload.add(mntmMultisells); + + JMenuItem mntmBuylists = new JMenuItem("Buylists"); + mntmBuylists.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBuylists.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload buylists?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + BuyListData.getInstance().load(); + } + }); + mnReload.add(mntmBuylists); + + JMenuItem mntmPrimeShop = new JMenuItem("PrimeShop"); + mntmPrimeShop.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmPrimeShop.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload PrimeShop?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + PrimeShopData.getInstance().load(); + } + }); + mnReload.add(mntmPrimeShop); + + JMenu mnAnnounce = new JMenu("Announce"); + mnAnnounce.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnAnnounce); + + JMenuItem mntmNormal = new JMenuItem("Normal"); + mntmNormal.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmNormal.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, false); + } + } + }); + mnAnnounce.add(mntmNormal); + + JMenuItem mntmCritical = new JMenuItem("Critical"); + mntmCritical.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmCritical.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Critical announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, true); + } + } + }); + mnAnnounce.add(mntmCritical); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmGameServer.setIconImages(icons); + + // System Panel. + JPanel systemPanel = new SystemPanel(); + JLayeredPane layeredPanel = new JLayeredPane(); + frmGameServer.getContentPane().add(layeredPanel, BorderLayout.CENTER); + layeredPanel.setBounds(0, 0, 819, 566); + layeredPanel.add(scrollPanel, new Integer(0), 0); + layeredPanel.add(systemPanel, new Integer(1), 0); + + // Center frame to screen. + frmGameServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmGameServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/Locator.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/Locator.java new file mode 100644 index 0000000000..e891609b67 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/Locator.java @@ -0,0 +1,295 @@ +/* + * 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.ui; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Locale; + +final class Locator +{ + /** + * Constructor for Locator. + */ + private Locator() + { + } + + /** + * Method getClassSource. + * @param c Class + * @return File + */ + static File getClassSource(Class c) + { + String classResource = c.getName().replace('.', '/') + ".class"; + return getResourceSource(c.getClassLoader(), classResource); + } + + /** + * Method getResourceSource. + * @param c ClassLoader + * @param resource String + * @return File + */ + private static File getResourceSource(ClassLoader c, String resource) + { + if (c == null) + { + c = Locator.class.getClassLoader(); + } + + URL url = null; + + if (c == null) + { + url = ClassLoader.getSystemResource(resource); + } + else + { + url = c.getResource(resource); + } + + if (url != null) + { + String u = url.toString(); + + if (u.startsWith("jar:file:")) + { + int pling = u.indexOf("!"); + String jarName = u.substring(4, pling); + return new File(fromURI(jarName)); + } + else if (u.startsWith("file:")) + { + int tail = u.indexOf(resource); + String dirName = u.substring(0, tail); + return new File(fromURI(dirName)); + } + } + + return null; + } + + /** + * Method fromURI. + * @param uri String + * @return String + */ + private static String fromURI(String uri) + { + URL url = null; + + try + { + url = new URL(uri); + } + catch (MalformedURLException emYouEarlEx) + { + // empty catch clause + } + + if ((url == null) || !"file".equals(url.getProtocol())) + { + throw new IllegalArgumentException("Can only handle valid file: URIs"); + } + + StringBuilder buf = new StringBuilder(url.getHost()); + + if (buf.length() > 0) + { + buf.insert(0, File.separatorChar).insert(0, File.separatorChar); + } + + String file = url.getFile(); + int queryPos = file.indexOf('?'); + buf.append(queryPos < 0 ? file : file.substring(0, queryPos)); + uri = buf.toString().replace('/', File.separatorChar); + + if ((File.pathSeparatorChar == ';') && uri.startsWith("\\") && (uri.length() > 2) && Character.isLetter(uri.charAt(1)) && (uri.lastIndexOf(':') > -1)) + { + uri = uri.substring(1); + } + + String path = decodeUri(uri); + return path; + } + + /** + * Method decodeUri. + * @param uri String + * @return String + */ + private static String decodeUri(String uri) + { + if (uri.indexOf('%') == -1) + { + return uri; + } + + StringBuilder sb = new StringBuilder(); + CharacterIterator iter = new StringCharacterIterator(uri); + + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + { + if (c == '%') + { + char c1 = iter.next(); + + if (c1 != CharacterIterator.DONE) + { + int i1 = Character.digit(c1, 16); + char c2 = iter.next(); + + if (c2 != CharacterIterator.DONE) + { + int i2 = Character.digit(c2, 16); + sb.append((char) ((i1 << 4) + i2)); + } + } + } + else + { + sb.append(c); + } + } + + String path = sb.toString(); + return path; + } + + /** + * Method getToolsJar. + * @return File + */ + static File getToolsJar() + { + boolean toolsJarAvailable = false; + + try + { + Class.forName("com.sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e) + { + try + { + Class.forName("sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e2) + { + // empty catch clause + } + } + + if (toolsJarAvailable) + { + return null; + } + + String javaHome = System.getProperty("java.home"); + + if (javaHome.toLowerCase(Locale.US).endsWith("jre")) + { + javaHome = javaHome.substring(0, javaHome.length() - 4); + } + + File toolsJar = new File(javaHome + "/lib/tools.jar"); + + if (!toolsJar.exists()) + { + System.out.println("Unable to locate tools.jar. " + "Expected to find it in " + toolsJar.getPath()); + return null; + } + + return toolsJar; + } + + /** + * Method getLocationURLs. + * @param location File + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + static URL[] getLocationURLs(File location) throws MalformedURLException + { + return getLocationURLs(location, new String[] + { + ".jar" + }); + } + + /** + * Method getLocationURLs. + * @param location File + * @param extensions String[] + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + private static URL[] getLocationURLs(File location, final String[] extensions) throws MalformedURLException + { + URL[] urls = new URL[0]; + + if (!location.exists()) + { + return urls; + } + + if (!location.isDirectory()) + { + urls = new URL[1]; + String path = location.getPath(); + + for (String extension : extensions) + { + if (path.toLowerCase().endsWith(extension)) + { + urls[0] = location.toURI().toURL(); + break; + } + } + + return urls; + } + + File[] matches = location.listFiles((FilenameFilter) (dir, name) -> + { + for (String extension : extensions) + { + if (name.toLowerCase().endsWith(extension)) + { + return true; + } + } + return false; + }); + urls = new URL[matches.length]; + + for (int i = 0; i < matches.length; ++i) + { + urls[i] = matches[i].toURI().toURL(); + } + + return urls; + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/SystemPanel.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/SystemPanel.java new file mode 100644 index 0000000000..68cabb3c12 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/SystemPanel.java @@ -0,0 +1,142 @@ +/* + * 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.ui; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.LineBorder; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.GameServer; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; + +/** + * @author Mobius + */ +public class SystemPanel extends JPanel +{ + final static long startTime = System.currentTimeMillis(); + + public SystemPanel() + { + setBackground(Color.WHITE); + setBounds(500, 20, 284, 140); + setBorder(new LineBorder(new Color(0, 0, 0), 1, false)); + setOpaque(true); + setLayout(null); + + JLabel lblProtocol = new JLabel("Protocol"); + lblProtocol.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblProtocol.setBounds(10, 5, 264, 17); + add(lblProtocol); + + JLabel lblConnected = new JLabel("Connected"); + lblConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblConnected.setBounds(10, 23, 264, 17); + add(lblConnected); + + JLabel lblMaxConnected = new JLabel("Max connected"); + lblMaxConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblMaxConnected.setBounds(10, 41, 264, 17); + add(lblMaxConnected); + + JLabel lblOfflineShops = new JLabel("Offline trade"); + lblOfflineShops.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblOfflineShops.setBounds(10, 59, 264, 17); + add(lblOfflineShops); + + JLabel lblElapsedTime = new JLabel("Elapsed time"); + lblElapsedTime.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblElapsedTime.setBounds(10, 77, 264, 17); + add(lblElapsedTime); + + JLabel lblJavaVersion = new JLabel("Build JDK"); + lblJavaVersion.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblJavaVersion.setBounds(10, 95, 264, 17); + add(lblJavaVersion); + + JLabel lblBuildDate = new JLabel("Build date"); + lblBuildDate.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblBuildDate.setBounds(10, 113, 264, 17); + add(lblBuildDate); + + // Set initial values. + lblProtocol.setText("Protocol: 0"); + lblConnected.setText("Connected: 0"); + lblMaxConnected.setText("Max connected: 0"); + lblOfflineShops.setText("Offline trade: 0"); + lblElapsedTime.setText("Elapsed: 0 sec"); + lblJavaVersion.setText("Java version: " + System.getProperty("java.version")); + lblBuildDate.setText("Build date: Unavailable"); + try + { + File jarName = Locator.getClassSource(GameServer.class); + JarFile jarFile = new JarFile(jarName); + Attributes attrs = jarFile.getManifest().getMainAttributes(); + lblBuildDate.setText("Build date: " + attrs.getValue("Build-Date").split(" ")[0]); + jarFile.close(); + } + catch (Exception e) + { + } + + // Initial update task. + new Timer().schedule(new TimerTask() + { + @Override + public void run() + { + lblProtocol.setText((Config.PROTOCOL_LIST.size() > 1 ? "Protocols: " : "Protocol: ") + Config.PROTOCOL_LIST.toString()); + } + }, 4500); + + // Repeating elapsed time task. + new Timer().scheduleAtFixedRate(new TimerTask() + { + @Override + public void run() + { + lblConnected.setText("Connected: " + PlayerCountManager.getInstance().getConnectedCount()); + lblMaxConnected.setText("Max connected: " + PlayerCountManager.getInstance().getMaxConnectedCount()); + lblOfflineShops.setText("Offline trade: " + PlayerCountManager.getInstance().getOfflineTradeCount()); + lblElapsedTime.setText("Elapsed: " + getDurationBreakdown(System.currentTimeMillis() - startTime)); + } + }, 1000, 1000); + } + + static String getDurationBreakdown(long millis) + { + long days = TimeUnit.MILLISECONDS.toDays(millis); + millis -= TimeUnit.DAYS.toMillis(days); + long hours = TimeUnit.MILLISECONDS.toHours(millis); + millis -= TimeUnit.HOURS.toMillis(hours); + long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); + millis -= TimeUnit.MINUTES.toMillis(minutes); + long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); + + return (days + "d " + hours + "h " + minutes + "m " + seconds + "s"); + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/frmAbout.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/frmAbout.java new file mode 100644 index 0000000000..e8a4f9a47c --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ui/frmAbout.java @@ -0,0 +1,143 @@ +/* + * 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.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblSupports = new JLabel("Server Protocol"); + lblSupports.setHorizontalAlignment(SwingConstants.CENTER); + lblSupports.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblSupports.setBounds(10, 78, 271, 23); + frmAbout.getContentPane().add(lblSupports); + + JLabel lblProtocols = new JLabel("Protocol Number"); + lblProtocols.setHorizontalAlignment(SwingConstants.CENTER); + lblProtocols.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblProtocols.setBounds(10, 92, 271, 23); + frmAbout.getContentPane().add(lblProtocols); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Generate protocols text. + String protocols = ""; + if (Config.PROTOCOL_LIST.size() > 1) + { + for (Integer number : Config.PROTOCOL_LIST) + { + if (!protocols.isEmpty()) + { + protocols += " - "; + } + protocols += number; + } + lblSupports.setText("Server Protocols"); + } + else + { + protocols += Config.PROTOCOL_LIST.get(0); + } + lblProtocols.setText(protocols); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java index e5991a5546..d0dbf3b697 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java @@ -20,6 +20,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Summon; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.olympiad.OlympiadManager; @@ -100,6 +101,8 @@ public final class OfflineTradeUtil return false; } + PlayerCountManager.getInstance().incOfflineTradeCount(); + final L2GameClient client = player.getClient(); client.setDetached(true); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/GameServerTable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/GameServerTable.java index 362aa93ad5..73110fb6dc 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/GameServerTable.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/GameServerTable.java @@ -409,7 +409,18 @@ public final class GameServerTable implements IGameXmlReader */ public void setStatus(int status) { - _status = status; + if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) + { + _status = ServerStatus.STATUS_DOWN; + } + else if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) + { + _status = ServerStatus.STATUS_GM_ONLY; + } + else + { + _status = status; + } } /** diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/LoginServer.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/LoginServer.java index 6c2062e622..39377afee3 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/LoginServer.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/LoginServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.loginserver; +import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -32,35 +33,43 @@ import com.l2jmobius.Config; import com.l2jmobius.Server; import com.l2jmobius.commons.database.DatabaseBackup; import com.l2jmobius.commons.database.DatabaseFactory; +import com.l2jmobius.gameserver.network.loginserverpackets.game.ServerStatus; import com.l2jmobius.loginserver.network.ClientNetworkManager; +import com.l2jmobius.loginserver.ui.Gui; /** * @author KenM */ public final class LoginServer { - private final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); + public final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); public static final int PROTOCOL_REV = 0x0106; - private static LoginServer _instance; + private static LoginServer INSTANCE; private GameServerListener _gameServerListener; private Thread _restartLoginServer; + private static int _loginStatus = ServerStatus.STATUS_NORMAL; public static void main(String[] args) throws Exception { - new LoginServer(); + INSTANCE = new LoginServer(); } public static LoginServer getInstance() { - return _instance; + return INSTANCE; } private LoginServer() throws Exception { - _instance = this; Server.serverMode = Server.MODE_LOGINSERVER; + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + // Create log folder final File logFolder = new File(".", "log"); logFolder.mkdir(); @@ -96,6 +105,14 @@ public final class LoginServer loadBanFile(); + if (Config.LOGIN_SERVER_SCHEDULE_RESTART) + { + LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); + _restartLoginServer = new LoginServerRestart(); + _restartLoginServer.setDaemon(true); + _restartLoginServer.start(); + } + try { _gameServerListener = new GameServerListener(); @@ -116,7 +133,7 @@ public final class LoginServer return _gameServerListener; } - private void loadBanFile() + public void loadBanFile() { final File bannedFile = new File("./banned_ip.cfg"); if (bannedFile.exists() && bannedFile.isFile()) @@ -170,14 +187,6 @@ public final class LoginServer { LOGGER.warning("IP Bans file (" + bannedFile.getName() + ") is missing or is a directory, skipped."); } - - if (Config.LOGIN_SERVER_SCHEDULE_RESTART) - { - LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); - _restartLoginServer = new LoginServerRestart(); - _restartLoginServer.setDaemon(true); - _restartLoginServer.start(); - } } class LoginServerRestart extends Thread @@ -213,4 +222,14 @@ public final class LoginServer } Runtime.getRuntime().exit(restart ? 2 : 0); } + + public int getStatus() + { + return _loginStatus; + } + + public void setStatus(int status) + { + _loginStatus = status; + } } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java index 670365b761..fa5c1e0a3a 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java @@ -20,8 +20,10 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.IIncomingPacket; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.network.L2LoginClient; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayOk; @@ -61,7 +63,11 @@ public class RequestServerLogin implements IIncomingPacket // if we didnt showed the license we cant check these values if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2)) { - if (LoginController.getInstance().isLoginPossible(client, _serverId)) + if ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) || ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) && (client.getAccessLevel() < 1))) + { + client.close(LoginFailReason.REASON_ACCESS_FAILED); + } + else if (LoginController.getInstance().isLoginPossible(client, _serverId)) { client.setJoinedGS(true); client.sendPacket(new PlayOk(sk)); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/ui/Gui.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/ui/Gui.java new file mode 100644 index 0000000000..7dfddb4985 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/ui/Gui.java @@ -0,0 +1,275 @@ +/* + * 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.loginserver.ui; + +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.loginserver.GameServerTable; +import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; +import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmLoginServer; + JTextArea txtrConsole; + + JCheckBoxMenuItem chckbxmntmEnabled; + JCheckBoxMenuItem chckbxmntmDisabled; + JCheckBoxMenuItem chckbxmntmGmOnly; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + + public Gui() + { + frmLoginServer = new JFrame(); + frmLoginServer.setVisible(false); + frmLoginServer.setTitle("Mobius - LoginServer"); + frmLoginServer.setResizable(false); + frmLoginServer.setBounds(100, 100, 825, 618); + frmLoginServer.getContentPane().setLayout(null); + frmLoginServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmLoginServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmLoginServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmLoginServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(true); + } + }); + mnActions.add(mntmRestart); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmBannedIps = new JMenuItem("Banned IPs"); + mntmBannedIps.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBannedIps.addActionListener(arg0 -> + { + LoginController.getInstance().getBannedIps().clear(); + LoginServer.getInstance().loadBanFile(); + }); + mnReload.add(mntmBannedIps); + + JMenu mnStatus = new JMenu("Status"); + mnStatus.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnStatus); + + chckbxmntmEnabled = new JCheckBoxMenuItem("Enabled"); + chckbxmntmEnabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmEnabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(true); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_NORMAL); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_NORMAL); + } + LoginServer.getInstance().LOGGER.info("Status changed to enabled."); + }); + chckbxmntmEnabled.setSelected(true); + mnStatus.add(chckbxmntmEnabled); + + chckbxmntmDisabled = new JCheckBoxMenuItem("Disabled"); + chckbxmntmDisabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmDisabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(true); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_DOWN); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_DOWN); + } + LoginServer.getInstance().LOGGER.info("Status changed to disabled."); + }); + mnStatus.add(chckbxmntmDisabled); + + chckbxmntmGmOnly = new JCheckBoxMenuItem("GM only"); + chckbxmntmGmOnly.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmGmOnly.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(true); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_GM_ONLY); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_GM_ONLY); + } + LoginServer.getInstance().LOGGER.info("Status changed to GM only."); + }); + mnStatus.add(chckbxmntmGmOnly); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmLoginServer.setIconImages(icons); + + // Center frame to screen. + frmLoginServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmLoginServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/ui/frmAbout.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/ui/frmAbout.java new file mode 100644 index 0000000000..b535d860b6 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/loginserver/ui/frmAbout.java @@ -0,0 +1,115 @@ +/* + * 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.loginserver.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblLoginServer = new JLabel("Login Server"); + lblLoginServer.setHorizontalAlignment(SwingConstants.CENTER); + lblLoginServer.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblLoginServer.setBounds(10, 86, 271, 23); + frmAbout.getContentPane().add(lblLoginServer); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_C6_Interlude/build.xml b/L2J_Mobius_C6_Interlude/build.xml index 17f4446493..6af638e518 100644 --- a/L2J_Mobius_C6_Interlude/build.xml +++ b/L2J_Mobius_C6_Interlude/build.xml @@ -75,8 +75,8 @@ - - + + @@ -90,8 +90,8 @@ - - + + @@ -105,8 +105,8 @@ - - + + @@ -120,8 +120,8 @@ - - + + diff --git a/L2J_Mobius_C6_Interlude/dist/game/GameServer.bat b/L2J_Mobius_C6_Interlude/dist/game/GameServer.bat deleted file mode 100644 index 2dbaac7089..0000000000 --- a/L2J_Mobius_C6_Interlude/dist/game/GameServer.bat +++ /dev/null @@ -1,30 +0,0 @@ -@set /p parameters=. + */ +package com.l2jmobius.commons.util; + +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; + +/* + * A class to control the maximum number of lines to be stored in a Document + * + * Excess lines can be removed from the start or end of the Document + * depending on your requirement. + * + * a) if you append text to the Document, then you would want to remove lines + * from the start. + * b) if you insert text at the beginning of the Document, then you would + * want to remove lines from the end. + */ +public class LimitLinesDocumentListener implements DocumentListener +{ + private int _maximumLines; + private final boolean _isRemoveFromStart; + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start of the Document. + */ + public LimitLinesDocumentListener(int maximumLines) + { + this(maximumLines, true); + } + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start or end of the Document, depending on the boolean value specified. + */ + public LimitLinesDocumentListener(int maximumLines, boolean isRemoveFromStart) + { + setLimitLines(maximumLines); + _isRemoveFromStart = isRemoveFromStart; + } + + /* + * Return the maximum number of lines to be stored in the Document. + */ + public int getLimitLines() + { + return _maximumLines; + } + + /* + * Set the maximum number of lines to be stored in the Document. + */ + public void setLimitLines(int maximumLines) + { + if (maximumLines < 1) + { + String message = "Maximum lines must be greater than 0"; + throw new IllegalArgumentException(message); + } + + _maximumLines = maximumLines; + } + + /* + * Handle insertion of new text into the Document. + */ + @Override + public void insertUpdate(final DocumentEvent e) + { + // Changes to the Document can not be done within the listener so we need to add the processing to the end of the EDT. + SwingUtilities.invokeLater(() -> removeLines(e)); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + } + + @Override + public void changedUpdate(DocumentEvent e) + { + } + + /* + * Remove lines from the Document when necessary. + */ + private void removeLines(DocumentEvent e) + { + // The root Element of the Document will tell us the total number of line in the Document. + Document document = e.getDocument(); + Element root = document.getDefaultRootElement(); + + while (root.getElementCount() > _maximumLines) + { + if (_isRemoveFromStart) + { + removeFromStart(document, root); + } + else + { + removeFromEnd(document, root); + } + } + } + + /* + * Remove lines from the start of the Document + */ + private void removeFromStart(Document document, Element root) + { + Element line = root.getElement(0); + int end = line.getEndOffset(); + + try + { + document.remove(0, end); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } + + /* + * Remove lines from the end of the Document + */ + private void removeFromEnd(Document document, Element root) + { + // We use start minus 1 to make sure we remove the newline character of the previous line. + + Element line = root.getElement(root.getElementCount() - 1); + int start = line.getStartOffset(); + int end = line.getEndOffset(); + + try + { + document.remove(start - 1, end - start); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/commons/util/SplashScreen.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/commons/util/SplashScreen.java index 80992f1b4d..5086e53e9c 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/commons/util/SplashScreen.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/commons/util/SplashScreen.java @@ -21,8 +21,8 @@ import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Timer; +import java.util.TimerTask; import javax.swing.ImageIcon; import javax.swing.JFrame; @@ -52,22 +52,24 @@ public class SplashScreen extends JWindow setAlwaysOnTop(true); setVisible(true); - // Schedule to close. - Executors.newScheduledThreadPool(1).schedule(this::close, imageIcon.getIconWidth() > 0 ? time : 100, TimeUnit.MILLISECONDS); - } - - public void close() - { - setVisible(false); - if (parentFrame != null) + new Timer().schedule(new TimerTask() { - // Make parent visible. - parentFrame.setVisible(true); - // Focus parent window. - parentFrame.toFront(); - parentFrame.setState(Frame.ICONIFIED); - parentFrame.setState(Frame.NORMAL); - } + @Override + public void run() + { + setVisible(false); + if (parentFrame != null) + { + // Make parent visible. + parentFrame.setVisible(true); + // Focus parent window. + parentFrame.toFront(); + parentFrame.setState(Frame.ICONIFIED); + parentFrame.setState(Frame.NORMAL); + } + dispose(); + } + }, imageIcon.getIconWidth() > 0 ? time : 100); } @Override diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/commons/util/Util.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/commons/util/Util.java index 9acfa8d77e..430d9723cc 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/commons/util/Util.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/commons/util/Util.java @@ -115,7 +115,7 @@ public class Util public static void printSection(String s) { s = "=[ " + s + " ]"; - while (s.length() < 62) + while (s.length() < 61) { s = "-" + s; } diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/GameServer.java index c62c016915..5a236c5137 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/GameServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.gameserver; +import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -140,6 +141,7 @@ import com.l2jmobius.gameserver.thread.LoginServerThread; import com.l2jmobius.gameserver.thread.daemons.DeadlockDetector; import com.l2jmobius.gameserver.thread.daemons.ItemsAutoDestroy; import com.l2jmobius.gameserver.thread.daemons.PcPoint; +import com.l2jmobius.gameserver.ui.Gui; import com.l2jmobius.gameserver.util.DynamicExtension; import com.l2jmobius.status.Status; @@ -158,6 +160,12 @@ public class GameServer { Server.serverMode = Server.MODE_GAMESERVER; + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + // Create log folder final File logFolder = new File(Config.DATAPACK_ROOT, "log"); logFolder.mkdir(); diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/datatables/OfflineTradeTable.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/datatables/OfflineTradeTable.java index 50132e0c8a..903b34f894 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/datatables/OfflineTradeTable.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/datatables/OfflineTradeTable.java @@ -24,6 +24,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.commons.database.DatabaseFactory; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.L2ManufactureItem; import com.l2jmobius.gameserver.model.L2ManufactureList; import com.l2jmobius.gameserver.model.L2World; @@ -275,6 +276,7 @@ public class OfflineTradeTable player.setOnlineStatus(true); player.restoreEffects(); player.broadcastUserInfo(); + PlayerCountManager.getInstance().incOfflineTradeCount(); nTraders++; } catch (Exception e) diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java new file mode 100644 index 0000000000..cb2fab84ed --- /dev/null +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java @@ -0,0 +1,77 @@ +/* + * 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.instancemanager; + +/** + * @author Mobius + */ +public class PlayerCountManager +{ + private volatile static int connectedCount = 0; + private volatile static int maxConnectedCount = 0; + private volatile static int offlineTradeCount = 0; + + protected PlayerCountManager() + { + } + + public int getConnectedCount() + { + return connectedCount; + } + + public int getMaxConnectedCount() + { + return maxConnectedCount; + } + + public int getOfflineTradeCount() + { + return offlineTradeCount; + } + + public synchronized void incConnectedCount() + { + connectedCount++; + maxConnectedCount = Math.max(maxConnectedCount, connectedCount); + } + + public void decConnectedCount() + { + connectedCount--; + } + + public void incOfflineTradeCount() + { + offlineTradeCount++; + } + + public synchronized void decOfflineTradeCount() + { + offlineTradeCount = Math.max(0, offlineTradeCount - 1); + } + + public static PlayerCountManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final PlayerCountManager INSTANCE = new PlayerCountManager(); + } +} diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/L2World.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/L2World.java index 789b2d8584..33ffa86b80 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/L2World.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/L2World.java @@ -29,6 +29,7 @@ import com.l2jmobius.commons.util.Point3D; import com.l2jmobius.commons.util.object.L2ObjectMap; import com.l2jmobius.commons.util.object.L2ObjectSet; import com.l2jmobius.gameserver.datatables.GmListTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Playable; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -413,10 +414,10 @@ public final class L2World */ public void addVisibleObject(L2Object object, L2WorldRegion newRegion, L2Character dropper) { - // If selected L2Object is a L2PcIntance, add it in L2ObjectHashSet(L2PcInstance) _allPlayers of L2World - // if (object instanceof L2PcInstance) { + PlayerCountManager.getInstance().incConnectedCount(); + L2PcInstance player = (L2PcInstance) object; L2PcInstance tmp = _allPlayers.get(player.getName().toLowerCase()); if ((tmp != null) && (tmp != player)) // just kick the player previous instance @@ -610,6 +611,12 @@ public final class L2World // If selected L2Object is a L2PcIntance, remove it from L2ObjectHashSet(L2PcInstance) _allPlayers of L2World if (object instanceof L2PcInstance) { + PlayerCountManager.getInstance().decConnectedCount(); + if (object.getActingPlayer().isInOfflineMode()) + { + PlayerCountManager.getInstance().decOfflineTradeCount(); + } + if (!((L2PcInstance) object).isTeleporting()) { removeFromAllPlayers((L2PcInstance) object); diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index d666ae58e4..91c6ce0e94 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -84,6 +84,7 @@ import com.l2jmobius.gameserver.instancemanager.DimensionalRiftManager; import com.l2jmobius.gameserver.instancemanager.DuelManager; import com.l2jmobius.gameserver.instancemanager.FortSiegeManager; import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.SiegeManager; import com.l2jmobius.gameserver.instancemanager.TownManager; @@ -9050,12 +9051,10 @@ public final class L2PcInstance extends L2Playable if ((_privatestore == STORE_PRIVATE_NONE) && ((getClient() == null) || isInOfflineMode())) { - /* - * if(this._originalNameColorOffline!=0) getAppearance().setNameColor(this._originalNameColorOffline); else getAppearance().setNameColor(_accessLevel.getNameColor()); - */ store(); if (Config.OFFLINE_DISCONNECT_FINISHED) { + PlayerCountManager.getInstance().decOfflineTradeCount(); deleteMe(); if (getClient() != null) diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/Disconnection.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/Disconnection.java index 47326244e9..415e83f1b7 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/Disconnection.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/Disconnection.java @@ -35,5 +35,4 @@ public class Disconnection implements Runnable { _activeChar.closeNetConnection(); } - } diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/L2GameClient.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/L2GameClient.java index 0e79af29be..3b0c1a7ed8 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/L2GameClient.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/L2GameClient.java @@ -42,6 +42,7 @@ import com.l2jmobius.gameserver.datatables.OfflineTradeTable; import com.l2jmobius.gameserver.datatables.SkillTable; import com.l2jmobius.gameserver.datatables.sql.ClanTable; import com.l2jmobius.gameserver.instancemanager.AwayManager; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.CharSelectInfoPackage; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2World; @@ -560,7 +561,6 @@ public final class L2GameClient extends MMOClient> i { getConnection().close(gsp); } - } /** @@ -866,7 +866,7 @@ public final class L2GameClient extends MMOClient> i } OfflineTradeTable.storeOffliner(player); - + PlayerCountManager.getInstance().incOfflineTradeCount(); return; } } diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/Gui.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/Gui.java new file mode 100644 index 0000000000..6a68193981 --- /dev/null +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/Gui.java @@ -0,0 +1,338 @@ +/* + * 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.ui; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.gameserver.Shutdown; +import com.l2jmobius.gameserver.cache.HtmCache; +import com.l2jmobius.gameserver.model.multisell.L2Multisell; +import com.l2jmobius.gameserver.network.clientpackets.Say2; +import com.l2jmobius.gameserver.network.serverpackets.CreatureSay; +import com.l2jmobius.gameserver.util.Broadcast; +import com.l2jmobius.gameserver.util.Util; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmGameServer; + JTextArea txtrConsole; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + final static String[] abortOptions = + { + "Abort", + "Cancel" + }; + final static String[] confirmOptions = + { + "Confirm", + "Cancel" + }; + + public Gui() + { + frmGameServer = new JFrame(); + frmGameServer.setVisible(false); + frmGameServer.setTitle("Mobius - GameServer"); + frmGameServer.setResizable(false); + frmGameServer.setBounds(100, 100, 825, 618); + frmGameServer.getContentPane().setLayout(null); + frmGameServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmGameServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown server immediately?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + Shutdown.getInstance().startShutdown(null, 1, false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmGameServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmGameServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Shutdown delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, false); + } + } + } + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Restart delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, true); + } + } + } + } + }); + mnActions.add(mntmRestart); + + JMenuItem mntmAbort = new JMenuItem("Abort"); + mntmAbort.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbort.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Abort server shutdown?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, abortOptions, abortOptions[1]) == 0) + { + Shutdown.getInstance().abort(null); + } + }); + mnActions.add(mntmAbort); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmConfigs = new JMenuItem("Configs"); + mntmConfigs.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmConfigs.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload configs?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + Config.load(); + } + }); + mnReload.add(mntmConfigs); + + JMenuItem mntmHtml = new JMenuItem("HTML"); + mntmHtml.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmHtml.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload HTML files?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + HtmCache.getInstance().reload(); + } + }); + mnReload.add(mntmHtml); + + JMenuItem mntmMultisells = new JMenuItem("Multisells"); + mntmMultisells.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmMultisells.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload multisells?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + L2Multisell.getInstance().reload(); + } + }); + mnReload.add(mntmMultisells); + + JMenu mnAnnounce = new JMenu("Announce"); + mnAnnounce.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnAnnounce); + + JMenuItem mntmNormal = new JMenuItem("Normal"); + mntmNormal.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmNormal.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + final CreatureSay cs = new CreatureSay(-1, Say2.ANNOUNCEMENT, "", message); + Broadcast.toAllOnlinePlayers(cs); + } + } + }); + mnAnnounce.add(mntmNormal); + + JMenuItem mntmCritical = new JMenuItem("Critical"); + mntmCritical.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmCritical.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Critical announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + final CreatureSay cs = new CreatureSay(-1, Say2.CRITICAL_ANNOUNCE, "", message); + Broadcast.toAllOnlinePlayers(cs); + } + } + }); + mnAnnounce.add(mntmCritical); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmGameServer.setIconImages(icons); + + // System Panel. + JPanel systemPanel = new SystemPanel(); + JLayeredPane layeredPanel = new JLayeredPane(); + frmGameServer.getContentPane().add(layeredPanel, BorderLayout.CENTER); + layeredPanel.setBounds(0, 0, 819, 566); + layeredPanel.add(scrollPanel, new Integer(0), 0); + layeredPanel.add(systemPanel, new Integer(1), 0); + + // Center frame to screen. + frmGameServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmGameServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/Locator.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/Locator.java new file mode 100644 index 0000000000..e891609b67 --- /dev/null +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/Locator.java @@ -0,0 +1,295 @@ +/* + * 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.ui; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Locale; + +final class Locator +{ + /** + * Constructor for Locator. + */ + private Locator() + { + } + + /** + * Method getClassSource. + * @param c Class + * @return File + */ + static File getClassSource(Class c) + { + String classResource = c.getName().replace('.', '/') + ".class"; + return getResourceSource(c.getClassLoader(), classResource); + } + + /** + * Method getResourceSource. + * @param c ClassLoader + * @param resource String + * @return File + */ + private static File getResourceSource(ClassLoader c, String resource) + { + if (c == null) + { + c = Locator.class.getClassLoader(); + } + + URL url = null; + + if (c == null) + { + url = ClassLoader.getSystemResource(resource); + } + else + { + url = c.getResource(resource); + } + + if (url != null) + { + String u = url.toString(); + + if (u.startsWith("jar:file:")) + { + int pling = u.indexOf("!"); + String jarName = u.substring(4, pling); + return new File(fromURI(jarName)); + } + else if (u.startsWith("file:")) + { + int tail = u.indexOf(resource); + String dirName = u.substring(0, tail); + return new File(fromURI(dirName)); + } + } + + return null; + } + + /** + * Method fromURI. + * @param uri String + * @return String + */ + private static String fromURI(String uri) + { + URL url = null; + + try + { + url = new URL(uri); + } + catch (MalformedURLException emYouEarlEx) + { + // empty catch clause + } + + if ((url == null) || !"file".equals(url.getProtocol())) + { + throw new IllegalArgumentException("Can only handle valid file: URIs"); + } + + StringBuilder buf = new StringBuilder(url.getHost()); + + if (buf.length() > 0) + { + buf.insert(0, File.separatorChar).insert(0, File.separatorChar); + } + + String file = url.getFile(); + int queryPos = file.indexOf('?'); + buf.append(queryPos < 0 ? file : file.substring(0, queryPos)); + uri = buf.toString().replace('/', File.separatorChar); + + if ((File.pathSeparatorChar == ';') && uri.startsWith("\\") && (uri.length() > 2) && Character.isLetter(uri.charAt(1)) && (uri.lastIndexOf(':') > -1)) + { + uri = uri.substring(1); + } + + String path = decodeUri(uri); + return path; + } + + /** + * Method decodeUri. + * @param uri String + * @return String + */ + private static String decodeUri(String uri) + { + if (uri.indexOf('%') == -1) + { + return uri; + } + + StringBuilder sb = new StringBuilder(); + CharacterIterator iter = new StringCharacterIterator(uri); + + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + { + if (c == '%') + { + char c1 = iter.next(); + + if (c1 != CharacterIterator.DONE) + { + int i1 = Character.digit(c1, 16); + char c2 = iter.next(); + + if (c2 != CharacterIterator.DONE) + { + int i2 = Character.digit(c2, 16); + sb.append((char) ((i1 << 4) + i2)); + } + } + } + else + { + sb.append(c); + } + } + + String path = sb.toString(); + return path; + } + + /** + * Method getToolsJar. + * @return File + */ + static File getToolsJar() + { + boolean toolsJarAvailable = false; + + try + { + Class.forName("com.sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e) + { + try + { + Class.forName("sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e2) + { + // empty catch clause + } + } + + if (toolsJarAvailable) + { + return null; + } + + String javaHome = System.getProperty("java.home"); + + if (javaHome.toLowerCase(Locale.US).endsWith("jre")) + { + javaHome = javaHome.substring(0, javaHome.length() - 4); + } + + File toolsJar = new File(javaHome + "/lib/tools.jar"); + + if (!toolsJar.exists()) + { + System.out.println("Unable to locate tools.jar. " + "Expected to find it in " + toolsJar.getPath()); + return null; + } + + return toolsJar; + } + + /** + * Method getLocationURLs. + * @param location File + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + static URL[] getLocationURLs(File location) throws MalformedURLException + { + return getLocationURLs(location, new String[] + { + ".jar" + }); + } + + /** + * Method getLocationURLs. + * @param location File + * @param extensions String[] + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + private static URL[] getLocationURLs(File location, final String[] extensions) throws MalformedURLException + { + URL[] urls = new URL[0]; + + if (!location.exists()) + { + return urls; + } + + if (!location.isDirectory()) + { + urls = new URL[1]; + String path = location.getPath(); + + for (String extension : extensions) + { + if (path.toLowerCase().endsWith(extension)) + { + urls[0] = location.toURI().toURL(); + break; + } + } + + return urls; + } + + File[] matches = location.listFiles((FilenameFilter) (dir, name) -> + { + for (String extension : extensions) + { + if (name.toLowerCase().endsWith(extension)) + { + return true; + } + } + return false; + }); + urls = new URL[matches.length]; + + for (int i = 0; i < matches.length; ++i) + { + urls[i] = matches[i].toURI().toURL(); + } + + return urls; + } +} diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/SystemPanel.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/SystemPanel.java new file mode 100644 index 0000000000..6df4951749 --- /dev/null +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/SystemPanel.java @@ -0,0 +1,149 @@ +/* + * 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.ui; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.LineBorder; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.GameServer; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; + +/** + * @author Mobius + */ +public class SystemPanel extends JPanel +{ + final static long startTime = System.currentTimeMillis(); + + public SystemPanel() + { + setBackground(Color.WHITE); + setBounds(500, 20, 284, 140); + setBorder(new LineBorder(new Color(0, 0, 0), 1, false)); + setOpaque(true); + setLayout(null); + + JLabel lblProtocol = new JLabel("Protocol"); + lblProtocol.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblProtocol.setBounds(10, 5, 264, 17); + add(lblProtocol); + + JLabel lblConnected = new JLabel("Connected"); + lblConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblConnected.setBounds(10, 23, 264, 17); + add(lblConnected); + + JLabel lblMaxConnected = new JLabel("Max connected"); + lblMaxConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblMaxConnected.setBounds(10, 41, 264, 17); + add(lblMaxConnected); + + JLabel lblOfflineShops = new JLabel("Offline trade"); + lblOfflineShops.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblOfflineShops.setBounds(10, 59, 264, 17); + add(lblOfflineShops); + + JLabel lblElapsedTime = new JLabel("Elapsed time"); + lblElapsedTime.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblElapsedTime.setBounds(10, 77, 264, 17); + add(lblElapsedTime); + + JLabel lblJavaVersion = new JLabel("Build JDK"); + lblJavaVersion.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblJavaVersion.setBounds(10, 95, 264, 17); + add(lblJavaVersion); + + JLabel lblBuildDate = new JLabel("Build date"); + lblBuildDate.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblBuildDate.setBounds(10, 113, 264, 17); + add(lblBuildDate); + + // Set initial values. + lblProtocol.setText("Protocol: 0"); + lblConnected.setText("Connected: 0"); + lblMaxConnected.setText("Max connected: 0"); + lblOfflineShops.setText("Offline trade: 0"); + lblElapsedTime.setText("Elapsed: 0 sec"); + lblJavaVersion.setText("Java version: " + System.getProperty("java.version")); + lblBuildDate.setText("Build date: Unavailable"); + try + { + File jarName = Locator.getClassSource(GameServer.class); + JarFile jarFile = new JarFile(jarName); + Attributes attrs = jarFile.getManifest().getMainAttributes(); + lblBuildDate.setText("Build date: " + attrs.getValue("Build-Date").split(" ")[0]); + jarFile.close(); + } + catch (Exception e) + { + } + + // Initial update task. + new Timer().schedule(new TimerTask() + { + @Override + public void run() + { + if (Config.MIN_PROTOCOL_REVISION != Config.MAX_PROTOCOL_REVISION) + { + lblProtocol.setText("Protocols: " + Config.MIN_PROTOCOL_REVISION + "-" + Config.MAX_PROTOCOL_REVISION); + } + else + { + lblProtocol.setText("Protocol: " + Config.MIN_PROTOCOL_REVISION); + } + } + }, 4500); + + // Repeating elapsed time task. + new Timer().scheduleAtFixedRate(new TimerTask() + { + @Override + public void run() + { + lblConnected.setText("Connected: " + PlayerCountManager.getInstance().getConnectedCount()); + lblMaxConnected.setText("Max connected: " + PlayerCountManager.getInstance().getMaxConnectedCount()); + lblOfflineShops.setText("Offline trade: " + PlayerCountManager.getInstance().getOfflineTradeCount()); + lblElapsedTime.setText("Elapsed: " + getDurationBreakdown(System.currentTimeMillis() - startTime)); + } + }, 1000, 1000); + } + + static String getDurationBreakdown(long millis) + { + long days = TimeUnit.MILLISECONDS.toDays(millis); + millis -= TimeUnit.DAYS.toMillis(days); + long hours = TimeUnit.MILLISECONDS.toHours(millis); + millis -= TimeUnit.HOURS.toMillis(hours); + long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); + millis -= TimeUnit.MINUTES.toMillis(minutes); + long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); + + return (days + "d " + hours + "h " + minutes + "m " + seconds + "s"); + } +} diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/frmAbout.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/frmAbout.java new file mode 100644 index 0000000000..0ab78d6140 --- /dev/null +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/ui/frmAbout.java @@ -0,0 +1,136 @@ +/* + * 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.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblSupports = new JLabel("Server Protocol"); + lblSupports.setHorizontalAlignment(SwingConstants.CENTER); + lblSupports.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblSupports.setBounds(10, 78, 271, 23); + frmAbout.getContentPane().add(lblSupports); + + JLabel lblProtocols = new JLabel("Protocol Number"); + lblProtocols.setHorizontalAlignment(SwingConstants.CENTER); + lblProtocols.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblProtocols.setBounds(10, 92, 271, 23); + frmAbout.getContentPane().add(lblProtocols); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Generate protocols text. + String protocols = ""; + if (Config.MIN_PROTOCOL_REVISION != Config.MAX_PROTOCOL_REVISION) + { + protocols = Config.MIN_PROTOCOL_REVISION + "-" + Config.MAX_PROTOCOL_REVISION; + lblSupports.setText("Server Protocols"); + } + else + { + protocols += Config.MIN_PROTOCOL_REVISION; + } + lblProtocols.setText(protocols); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/GameServerTable.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/GameServerTable.java index 11409fcb5d..77211089f1 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/GameServerTable.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/GameServerTable.java @@ -337,7 +337,18 @@ public class GameServerTable public void setStatus(int status) { - _status = status; + if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) + { + _status = ServerStatus.STATUS_DOWN; + } + else if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) + { + _status = ServerStatus.STATUS_GM_ONLY; + } + else + { + _status = status; + } } public int getStatus() diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/LoginServer.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/LoginServer.java index af1bc1668f..9b4efaec2a 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/LoginServer.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/LoginServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.loginserver; +import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -34,35 +35,41 @@ import com.l2jmobius.commons.mmocore.NetcoreConfig; import com.l2jmobius.commons.mmocore.SelectorConfig; import com.l2jmobius.commons.mmocore.SelectorThread; import com.l2jmobius.commons.util.Util; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; +import com.l2jmobius.loginserver.ui.Gui; import com.l2jmobius.status.Status; public class LoginServer { - private final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); + public final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); public static final int PROTOCOL_REV = 0x0102; - - private static LoginServer _instance; - + private static LoginServer INSTANCE; private GameServerListener _gameServerListener; private SelectorThread _selectorThread; private Status _statusServer; + private static int _loginStatus = ServerStatus.STATUS_NORMAL; public static void main(String[] args) { - _instance = new LoginServer(); + INSTANCE = new LoginServer(); } public static LoginServer getInstance() { - return _instance; + return INSTANCE; } public LoginServer() { - _instance = this; Server.serverMode = Server.MODE_LOGINSERVER; + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + // Create log folder final File logFolder = new File(".", "log"); logFolder.mkdir(); @@ -200,4 +207,14 @@ public class LoginServer System.gc(); Runtime.getRuntime().exit(restart ? 2 : 0); } + + public int getStatus() + { + return _loginStatus; + } + + public void setStatus(int status) + { + _loginStatus = status; + } } diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java index a5eae4cac2..dbeb3f432d 100644 --- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java @@ -18,7 +18,9 @@ package com.l2jmobius.loginserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; import com.l2jmobius.loginserver.SessionKey; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayOk; @@ -77,7 +79,11 @@ public class RequestServerLogin extends L2LoginClientPacket // if we didnt showed the license we cant check these values if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2)) { - if (LoginController.getInstance().isLoginPossible(getClient(), _serverId)) + if ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) || ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) && (getClient().getAccessLevel() < 1))) + { + getClient().close(LoginFailReason.REASON_ACCESS_FAILED); + } + else if (LoginController.getInstance().isLoginPossible(getClient(), _serverId)) { getClient().setJoinedGS(true); getClient().sendPacket(new PlayOk(sk)); diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/ui/Gui.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/ui/Gui.java new file mode 100644 index 0000000000..28006d2eeb --- /dev/null +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/ui/Gui.java @@ -0,0 +1,276 @@ +/* + * 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.loginserver.ui; + +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.loginserver.GameServerTable; +import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; +import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmLoginServer; + JTextArea txtrConsole; + + JCheckBoxMenuItem chckbxmntmEnabled; + JCheckBoxMenuItem chckbxmntmDisabled; + JCheckBoxMenuItem chckbxmntmGmOnly; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + + public Gui() + { + frmLoginServer = new JFrame(); + frmLoginServer.setVisible(false); + frmLoginServer.setTitle("Mobius - LoginServer"); + frmLoginServer.setResizable(false); + frmLoginServer.setBounds(100, 100, 825, 618); + frmLoginServer.getContentPane().setLayout(null); + frmLoginServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmLoginServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmLoginServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmLoginServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(true); + } + }); + mnActions.add(mntmRestart); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmBannedIps = new JMenuItem("Banned IPs"); + mntmBannedIps.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBannedIps.addActionListener(arg0 -> + { + LoginController.getInstance().getBannedIps().clear(); + Config.loadBanFile(); + }); + mnReload.add(mntmBannedIps); + + JMenu mnStatus = new JMenu("Status"); + mnStatus.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnStatus); + + chckbxmntmEnabled = new JCheckBoxMenuItem("Enabled"); + chckbxmntmEnabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmEnabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(true); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_NORMAL); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_NORMAL); + } + LoginServer.getInstance().LOGGER.info("Status changed to enabled."); + }); + chckbxmntmEnabled.setSelected(true); + mnStatus.add(chckbxmntmEnabled); + + chckbxmntmDisabled = new JCheckBoxMenuItem("Disabled"); + chckbxmntmDisabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmDisabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(true); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_DOWN); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_DOWN); + } + LoginServer.getInstance().LOGGER.info("Status changed to disabled."); + }); + mnStatus.add(chckbxmntmDisabled); + + chckbxmntmGmOnly = new JCheckBoxMenuItem("GM only"); + chckbxmntmGmOnly.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmGmOnly.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(true); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_GM_ONLY); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_GM_ONLY); + } + LoginServer.getInstance().LOGGER.info("Status changed to GM only."); + }); + mnStatus.add(chckbxmntmGmOnly); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmLoginServer.setIconImages(icons); + + // Center frame to screen. + frmLoginServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmLoginServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/ui/frmAbout.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/ui/frmAbout.java new file mode 100644 index 0000000000..b535d860b6 --- /dev/null +++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/loginserver/ui/frmAbout.java @@ -0,0 +1,115 @@ +/* + * 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.loginserver.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblLoginServer = new JLabel("Login Server"); + lblLoginServer.setHorizontalAlignment(SwingConstants.CENTER); + lblLoginServer.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblLoginServer.setBounds(10, 86, 271, 23); + frmAbout.getContentPane().add(lblLoginServer); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_CT_2.6_HighFive/build.xml b/L2J_Mobius_CT_2.6_HighFive/build.xml index baec993f0d..36803f5e3e 100644 --- a/L2J_Mobius_CT_2.6_HighFive/build.xml +++ b/L2J_Mobius_CT_2.6_HighFive/build.xml @@ -78,8 +78,8 @@ - - + + @@ -93,8 +93,8 @@ - - + + @@ -108,8 +108,8 @@ - - + + @@ -123,8 +123,8 @@ - - + + diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/GameServer.bat b/L2J_Mobius_CT_2.6_HighFive/dist/game/GameServer.bat deleted file mode 100644 index 2dbaac7089..0000000000 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/GameServer.bat +++ /dev/null @@ -1,30 +0,0 @@ -@set /p parameters=. + */ +package com.l2jmobius.commons.util; + +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; + +/* + * A class to control the maximum number of lines to be stored in a Document + * + * Excess lines can be removed from the start or end of the Document + * depending on your requirement. + * + * a) if you append text to the Document, then you would want to remove lines + * from the start. + * b) if you insert text at the beginning of the Document, then you would + * want to remove lines from the end. + */ +public class LimitLinesDocumentListener implements DocumentListener +{ + private int _maximumLines; + private final boolean _isRemoveFromStart; + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start of the Document. + */ + public LimitLinesDocumentListener(int maximumLines) + { + this(maximumLines, true); + } + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start or end of the Document, depending on the boolean value specified. + */ + public LimitLinesDocumentListener(int maximumLines, boolean isRemoveFromStart) + { + setLimitLines(maximumLines); + _isRemoveFromStart = isRemoveFromStart; + } + + /* + * Return the maximum number of lines to be stored in the Document. + */ + public int getLimitLines() + { + return _maximumLines; + } + + /* + * Set the maximum number of lines to be stored in the Document. + */ + public void setLimitLines(int maximumLines) + { + if (maximumLines < 1) + { + String message = "Maximum lines must be greater than 0"; + throw new IllegalArgumentException(message); + } + + _maximumLines = maximumLines; + } + + /* + * Handle insertion of new text into the Document. + */ + @Override + public void insertUpdate(final DocumentEvent e) + { + // Changes to the Document can not be done within the listener so we need to add the processing to the end of the EDT. + SwingUtilities.invokeLater(() -> removeLines(e)); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + } + + @Override + public void changedUpdate(DocumentEvent e) + { + } + + /* + * Remove lines from the Document when necessary. + */ + private void removeLines(DocumentEvent e) + { + // The root Element of the Document will tell us the total number of line in the Document. + Document document = e.getDocument(); + Element root = document.getDefaultRootElement(); + + while (root.getElementCount() > _maximumLines) + { + if (_isRemoveFromStart) + { + removeFromStart(document, root); + } + else + { + removeFromEnd(document, root); + } + } + } + + /* + * Remove lines from the start of the Document + */ + private void removeFromStart(Document document, Element root) + { + Element line = root.getElement(0); + int end = line.getEndOffset(); + + try + { + document.remove(0, end); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } + + /* + * Remove lines from the end of the Document + */ + private void removeFromEnd(Document document, Element root) + { + // We use start minus 1 to make sure we remove the newline character of the previous line. + + Element line = root.getElement(root.getElementCount() - 1); + int start = line.getStartOffset(); + int end = line.getEndOffset(); + + try + { + document.remove(start - 1, end - start); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/commons/util/SplashScreen.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/commons/util/SplashScreen.java index 80992f1b4d..5086e53e9c 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/commons/util/SplashScreen.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/commons/util/SplashScreen.java @@ -21,8 +21,8 @@ import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Timer; +import java.util.TimerTask; import javax.swing.ImageIcon; import javax.swing.JFrame; @@ -52,22 +52,24 @@ public class SplashScreen extends JWindow setAlwaysOnTop(true); setVisible(true); - // Schedule to close. - Executors.newScheduledThreadPool(1).schedule(this::close, imageIcon.getIconWidth() > 0 ? time : 100, TimeUnit.MILLISECONDS); - } - - public void close() - { - setVisible(false); - if (parentFrame != null) + new Timer().schedule(new TimerTask() { - // Make parent visible. - parentFrame.setVisible(true); - // Focus parent window. - parentFrame.toFront(); - parentFrame.setState(Frame.ICONIFIED); - parentFrame.setState(Frame.NORMAL); - } + @Override + public void run() + { + setVisible(false); + if (parentFrame != null) + { + // Make parent visible. + parentFrame.setVisible(true); + // Focus parent window. + parentFrame.toFront(); + parentFrame.setState(Frame.ICONIFIED); + parentFrame.setState(Frame.NORMAL); + } + dispose(); + } + }, imageIcon.getIconWidth() > 0 ? time : 100); } @Override diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java index 2e024a6666..f5460b510d 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.gameserver; +import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.io.File; import java.io.FileInputStream; @@ -80,10 +81,10 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData; import com.l2jmobius.gameserver.data.xml.impl.UIData; import com.l2jmobius.gameserver.datatables.AugmentationData; import com.l2jmobius.gameserver.datatables.BotReportTable; -import com.l2jmobius.gameserver.datatables.SchemeBufferTable; import com.l2jmobius.gameserver.datatables.EventDroplist; import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.datatables.MerchantPriceConfigTable; +import com.l2jmobius.gameserver.datatables.SchemeBufferTable; import com.l2jmobius.gameserver.datatables.SpawnTable; import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.handler.EffectHandler; @@ -142,6 +143,7 @@ import com.l2jmobius.gameserver.network.loginserver.LoginServerNetworkManager; import com.l2jmobius.gameserver.network.telnet.TelnetServer; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.taskmanager.TaskManager; +import com.l2jmobius.gameserver.ui.Gui; import com.l2jmobius.gameserver.util.Broadcast; public class GameServer @@ -165,6 +167,30 @@ public class GameServer public GameServer() throws Exception { final long serverLoadStart = System.currentTimeMillis(); + Server.serverMode = Server.MODE_GAMESERVER; + + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + + // Create log folder + final File logFolder = new File(Config.DATAPACK_ROOT, "log"); + logFolder.mkdir(); + + // Create input stream for log file -- or store file data into memory + try (InputStream is = new FileInputStream(new File("./log.cfg"))) + { + LogManager.getLogManager().readConfiguration(is); + } + + new File("log/game").mkdirs(); + + // Initialize config + Config.load(); + printSection("Database"); + DatabaseFactory.getInstance(); printSection("ThreadPool"); ThreadPool.init(); @@ -456,25 +482,6 @@ public class GameServer public static void main(String[] args) throws Exception { - Server.serverMode = Server.MODE_GAMESERVER; - - // Create log folder - final File logFolder = new File(Config.DATAPACK_ROOT, "log"); - logFolder.mkdir(); - - // Create input stream for log file -- or store file data into memory - try (InputStream is = new FileInputStream(new File("./log.cfg"))) - { - LogManager.getLogManager().readConfiguration(is); - } - - new File("log/game").mkdirs(); - - // Initialize config - Config.load(); - printSection("Database"); - DatabaseFactory.getInstance(); - INSTANCE = new GameServer(); } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java index efe55bcf4e..70cc6c74b2 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java @@ -28,6 +28,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.gameserver.LoginServerThread; import com.l2jmobius.gameserver.enums.PrivateStoreType; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.L2ManufactureItem; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.TradeItem; @@ -298,6 +299,7 @@ public class OfflineTradersTable player.setOnlineStatus(true, true); player.restoreEffects(); player.broadcastUserInfo(); + PlayerCountManager.getInstance().incOfflineTradeCount(); nTraders++; } catch (Exception e) @@ -451,6 +453,8 @@ public class OfflineTradersTable public static synchronized void removeTrader(int traderObjId) { + PlayerCountManager.getInstance().decOfflineTradeCount(); + try (Connection con = DatabaseFactory.getInstance().getConnection(); PreparedStatement stm1 = con.prepareStatement(CLEAR_OFFLINE_TABLE_ITEMS_PLAYER); PreparedStatement stm2 = con.prepareStatement(CLEAR_OFFLINE_TABLE_PLAYER)) diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java new file mode 100644 index 0000000000..cb2fab84ed --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java @@ -0,0 +1,77 @@ +/* + * 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.instancemanager; + +/** + * @author Mobius + */ +public class PlayerCountManager +{ + private volatile static int connectedCount = 0; + private volatile static int maxConnectedCount = 0; + private volatile static int offlineTradeCount = 0; + + protected PlayerCountManager() + { + } + + public int getConnectedCount() + { + return connectedCount; + } + + public int getMaxConnectedCount() + { + return maxConnectedCount; + } + + public int getOfflineTradeCount() + { + return offlineTradeCount; + } + + public synchronized void incConnectedCount() + { + connectedCount++; + maxConnectedCount = Math.max(maxConnectedCount, connectedCount); + } + + public void decConnectedCount() + { + connectedCount--; + } + + public void incOfflineTradeCount() + { + offlineTradeCount++; + } + + public synchronized void decOfflineTradeCount() + { + offlineTradeCount = Math.max(0, offlineTradeCount - 1); + } + + public static PlayerCountManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final PlayerCountManager INSTANCE = new PlayerCountManager(); + } +} diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/L2World.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/L2World.java index 0cb5921bfc..0a9d4adbae 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/L2World.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/L2World.java @@ -31,6 +31,7 @@ import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -131,6 +132,8 @@ public final class L2World if (object.isPlayer()) { + PlayerCountManager.getInstance().incConnectedCount(); + final L2PcInstance newPlayer = (L2PcInstance) object; if (newPlayer.isTeleporting()) // TODO: drop when we stop removing player from the world while teleporting. { @@ -166,6 +169,8 @@ public final class L2World _allObjects.remove(object.getObjectId()); if (object.isPlayer()) { + PlayerCountManager.getInstance().decConnectedCount(); + final L2PcInstance player = (L2PcInstance) object; if (player.isTeleporting()) // TODO: drop when we stop removing player from the world while teleportingq. { diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/Gui.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/Gui.java new file mode 100644 index 0000000000..9f8c2a41a6 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/Gui.java @@ -0,0 +1,370 @@ +/* + * 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.ui; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.gameserver.Shutdown; +import com.l2jmobius.gameserver.cache.HtmCache; +import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.BuyListData; +import com.l2jmobius.gameserver.data.xml.impl.MultisellData; +import com.l2jmobius.gameserver.data.xml.impl.PrimeShopData; +import com.l2jmobius.gameserver.util.Broadcast; +import com.l2jmobius.gameserver.util.Util; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmGameServer; + JTextArea txtrConsole; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + final static String[] abortOptions = + { + "Abort", + "Cancel" + }; + final static String[] confirmOptions = + { + "Confirm", + "Cancel" + }; + + public Gui() + { + frmGameServer = new JFrame(); + frmGameServer.setVisible(false); + frmGameServer.setTitle("Mobius - GameServer"); + frmGameServer.setResizable(false); + frmGameServer.setBounds(100, 100, 825, 618); + frmGameServer.getContentPane().setLayout(null); + frmGameServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmGameServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown server immediately?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + Shutdown.getInstance().startShutdown(null, 1, false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmGameServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmGameServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Shutdown delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, false); + } + } + } + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Restart delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, true); + } + } + } + } + }); + mnActions.add(mntmRestart); + + JMenuItem mntmAbort = new JMenuItem("Abort"); + mntmAbort.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbort.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Abort server shutdown?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, abortOptions, abortOptions[1]) == 0) + { + Shutdown.getInstance().abort(null); + } + }); + mnActions.add(mntmAbort); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmConfigs = new JMenuItem("Configs"); + mntmConfigs.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmConfigs.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload configs?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + Config.load(); + } + }); + mnReload.add(mntmConfigs); + + JMenuItem mntmAccess = new JMenuItem("Access"); + mntmAccess.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAccess.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload admin access levels?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + AdminData.getInstance().load(); + } + }); + mnReload.add(mntmAccess); + + JMenuItem mntmHtml = new JMenuItem("HTML"); + mntmHtml.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmHtml.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload HTML files?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + HtmCache.getInstance().reload(); + } + }); + mnReload.add(mntmHtml); + + JMenuItem mntmMultisells = new JMenuItem("Multisells"); + mntmMultisells.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmMultisells.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload multisells?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + MultisellData.getInstance().load(); + } + }); + mnReload.add(mntmMultisells); + + JMenuItem mntmBuylists = new JMenuItem("Buylists"); + mntmBuylists.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBuylists.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload buylists?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + BuyListData.getInstance().load(); + } + }); + mnReload.add(mntmBuylists); + + JMenuItem mntmPrimeShop = new JMenuItem("PrimeShop"); + mntmPrimeShop.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmPrimeShop.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload PrimeShop?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + PrimeShopData.getInstance().load(); + } + }); + mnReload.add(mntmPrimeShop); + + JMenu mnAnnounce = new JMenu("Announce"); + mnAnnounce.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnAnnounce); + + JMenuItem mntmNormal = new JMenuItem("Normal"); + mntmNormal.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmNormal.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, false); + } + } + }); + mnAnnounce.add(mntmNormal); + + JMenuItem mntmCritical = new JMenuItem("Critical"); + mntmCritical.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmCritical.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Critical announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, true); + } + } + }); + mnAnnounce.add(mntmCritical); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmGameServer.setIconImages(icons); + + // System Panel. + JPanel systemPanel = new SystemPanel(); + JLayeredPane layeredPanel = new JLayeredPane(); + frmGameServer.getContentPane().add(layeredPanel, BorderLayout.CENTER); + layeredPanel.setBounds(0, 0, 819, 566); + layeredPanel.add(scrollPanel, new Integer(0), 0); + layeredPanel.add(systemPanel, new Integer(1), 0); + + // Center frame to screen. + frmGameServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmGameServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/Locator.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/Locator.java new file mode 100644 index 0000000000..e891609b67 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/Locator.java @@ -0,0 +1,295 @@ +/* + * 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.ui; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Locale; + +final class Locator +{ + /** + * Constructor for Locator. + */ + private Locator() + { + } + + /** + * Method getClassSource. + * @param c Class + * @return File + */ + static File getClassSource(Class c) + { + String classResource = c.getName().replace('.', '/') + ".class"; + return getResourceSource(c.getClassLoader(), classResource); + } + + /** + * Method getResourceSource. + * @param c ClassLoader + * @param resource String + * @return File + */ + private static File getResourceSource(ClassLoader c, String resource) + { + if (c == null) + { + c = Locator.class.getClassLoader(); + } + + URL url = null; + + if (c == null) + { + url = ClassLoader.getSystemResource(resource); + } + else + { + url = c.getResource(resource); + } + + if (url != null) + { + String u = url.toString(); + + if (u.startsWith("jar:file:")) + { + int pling = u.indexOf("!"); + String jarName = u.substring(4, pling); + return new File(fromURI(jarName)); + } + else if (u.startsWith("file:")) + { + int tail = u.indexOf(resource); + String dirName = u.substring(0, tail); + return new File(fromURI(dirName)); + } + } + + return null; + } + + /** + * Method fromURI. + * @param uri String + * @return String + */ + private static String fromURI(String uri) + { + URL url = null; + + try + { + url = new URL(uri); + } + catch (MalformedURLException emYouEarlEx) + { + // empty catch clause + } + + if ((url == null) || !"file".equals(url.getProtocol())) + { + throw new IllegalArgumentException("Can only handle valid file: URIs"); + } + + StringBuilder buf = new StringBuilder(url.getHost()); + + if (buf.length() > 0) + { + buf.insert(0, File.separatorChar).insert(0, File.separatorChar); + } + + String file = url.getFile(); + int queryPos = file.indexOf('?'); + buf.append(queryPos < 0 ? file : file.substring(0, queryPos)); + uri = buf.toString().replace('/', File.separatorChar); + + if ((File.pathSeparatorChar == ';') && uri.startsWith("\\") && (uri.length() > 2) && Character.isLetter(uri.charAt(1)) && (uri.lastIndexOf(':') > -1)) + { + uri = uri.substring(1); + } + + String path = decodeUri(uri); + return path; + } + + /** + * Method decodeUri. + * @param uri String + * @return String + */ + private static String decodeUri(String uri) + { + if (uri.indexOf('%') == -1) + { + return uri; + } + + StringBuilder sb = new StringBuilder(); + CharacterIterator iter = new StringCharacterIterator(uri); + + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + { + if (c == '%') + { + char c1 = iter.next(); + + if (c1 != CharacterIterator.DONE) + { + int i1 = Character.digit(c1, 16); + char c2 = iter.next(); + + if (c2 != CharacterIterator.DONE) + { + int i2 = Character.digit(c2, 16); + sb.append((char) ((i1 << 4) + i2)); + } + } + } + else + { + sb.append(c); + } + } + + String path = sb.toString(); + return path; + } + + /** + * Method getToolsJar. + * @return File + */ + static File getToolsJar() + { + boolean toolsJarAvailable = false; + + try + { + Class.forName("com.sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e) + { + try + { + Class.forName("sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e2) + { + // empty catch clause + } + } + + if (toolsJarAvailable) + { + return null; + } + + String javaHome = System.getProperty("java.home"); + + if (javaHome.toLowerCase(Locale.US).endsWith("jre")) + { + javaHome = javaHome.substring(0, javaHome.length() - 4); + } + + File toolsJar = new File(javaHome + "/lib/tools.jar"); + + if (!toolsJar.exists()) + { + System.out.println("Unable to locate tools.jar. " + "Expected to find it in " + toolsJar.getPath()); + return null; + } + + return toolsJar; + } + + /** + * Method getLocationURLs. + * @param location File + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + static URL[] getLocationURLs(File location) throws MalformedURLException + { + return getLocationURLs(location, new String[] + { + ".jar" + }); + } + + /** + * Method getLocationURLs. + * @param location File + * @param extensions String[] + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + private static URL[] getLocationURLs(File location, final String[] extensions) throws MalformedURLException + { + URL[] urls = new URL[0]; + + if (!location.exists()) + { + return urls; + } + + if (!location.isDirectory()) + { + urls = new URL[1]; + String path = location.getPath(); + + for (String extension : extensions) + { + if (path.toLowerCase().endsWith(extension)) + { + urls[0] = location.toURI().toURL(); + break; + } + } + + return urls; + } + + File[] matches = location.listFiles((FilenameFilter) (dir, name) -> + { + for (String extension : extensions) + { + if (name.toLowerCase().endsWith(extension)) + { + return true; + } + } + return false; + }); + urls = new URL[matches.length]; + + for (int i = 0; i < matches.length; ++i) + { + urls[i] = matches[i].toURI().toURL(); + } + + return urls; + } +} diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/SystemPanel.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/SystemPanel.java new file mode 100644 index 0000000000..68cabb3c12 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/SystemPanel.java @@ -0,0 +1,142 @@ +/* + * 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.ui; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.LineBorder; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.GameServer; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; + +/** + * @author Mobius + */ +public class SystemPanel extends JPanel +{ + final static long startTime = System.currentTimeMillis(); + + public SystemPanel() + { + setBackground(Color.WHITE); + setBounds(500, 20, 284, 140); + setBorder(new LineBorder(new Color(0, 0, 0), 1, false)); + setOpaque(true); + setLayout(null); + + JLabel lblProtocol = new JLabel("Protocol"); + lblProtocol.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblProtocol.setBounds(10, 5, 264, 17); + add(lblProtocol); + + JLabel lblConnected = new JLabel("Connected"); + lblConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblConnected.setBounds(10, 23, 264, 17); + add(lblConnected); + + JLabel lblMaxConnected = new JLabel("Max connected"); + lblMaxConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblMaxConnected.setBounds(10, 41, 264, 17); + add(lblMaxConnected); + + JLabel lblOfflineShops = new JLabel("Offline trade"); + lblOfflineShops.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblOfflineShops.setBounds(10, 59, 264, 17); + add(lblOfflineShops); + + JLabel lblElapsedTime = new JLabel("Elapsed time"); + lblElapsedTime.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblElapsedTime.setBounds(10, 77, 264, 17); + add(lblElapsedTime); + + JLabel lblJavaVersion = new JLabel("Build JDK"); + lblJavaVersion.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblJavaVersion.setBounds(10, 95, 264, 17); + add(lblJavaVersion); + + JLabel lblBuildDate = new JLabel("Build date"); + lblBuildDate.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblBuildDate.setBounds(10, 113, 264, 17); + add(lblBuildDate); + + // Set initial values. + lblProtocol.setText("Protocol: 0"); + lblConnected.setText("Connected: 0"); + lblMaxConnected.setText("Max connected: 0"); + lblOfflineShops.setText("Offline trade: 0"); + lblElapsedTime.setText("Elapsed: 0 sec"); + lblJavaVersion.setText("Java version: " + System.getProperty("java.version")); + lblBuildDate.setText("Build date: Unavailable"); + try + { + File jarName = Locator.getClassSource(GameServer.class); + JarFile jarFile = new JarFile(jarName); + Attributes attrs = jarFile.getManifest().getMainAttributes(); + lblBuildDate.setText("Build date: " + attrs.getValue("Build-Date").split(" ")[0]); + jarFile.close(); + } + catch (Exception e) + { + } + + // Initial update task. + new Timer().schedule(new TimerTask() + { + @Override + public void run() + { + lblProtocol.setText((Config.PROTOCOL_LIST.size() > 1 ? "Protocols: " : "Protocol: ") + Config.PROTOCOL_LIST.toString()); + } + }, 4500); + + // Repeating elapsed time task. + new Timer().scheduleAtFixedRate(new TimerTask() + { + @Override + public void run() + { + lblConnected.setText("Connected: " + PlayerCountManager.getInstance().getConnectedCount()); + lblMaxConnected.setText("Max connected: " + PlayerCountManager.getInstance().getMaxConnectedCount()); + lblOfflineShops.setText("Offline trade: " + PlayerCountManager.getInstance().getOfflineTradeCount()); + lblElapsedTime.setText("Elapsed: " + getDurationBreakdown(System.currentTimeMillis() - startTime)); + } + }, 1000, 1000); + } + + static String getDurationBreakdown(long millis) + { + long days = TimeUnit.MILLISECONDS.toDays(millis); + millis -= TimeUnit.DAYS.toMillis(days); + long hours = TimeUnit.MILLISECONDS.toHours(millis); + millis -= TimeUnit.HOURS.toMillis(hours); + long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); + millis -= TimeUnit.MINUTES.toMillis(minutes); + long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); + + return (days + "d " + hours + "h " + minutes + "m " + seconds + "s"); + } +} diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/frmAbout.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/frmAbout.java new file mode 100644 index 0000000000..e8a4f9a47c --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ui/frmAbout.java @@ -0,0 +1,143 @@ +/* + * 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.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblSupports = new JLabel("Server Protocol"); + lblSupports.setHorizontalAlignment(SwingConstants.CENTER); + lblSupports.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblSupports.setBounds(10, 78, 271, 23); + frmAbout.getContentPane().add(lblSupports); + + JLabel lblProtocols = new JLabel("Protocol Number"); + lblProtocols.setHorizontalAlignment(SwingConstants.CENTER); + lblProtocols.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblProtocols.setBounds(10, 92, 271, 23); + frmAbout.getContentPane().add(lblProtocols); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Generate protocols text. + String protocols = ""; + if (Config.PROTOCOL_LIST.size() > 1) + { + for (Integer number : Config.PROTOCOL_LIST) + { + if (!protocols.isEmpty()) + { + protocols += " - "; + } + protocols += number; + } + lblSupports.setText("Server Protocols"); + } + else + { + protocols += Config.PROTOCOL_LIST.get(0); + } + lblProtocols.setText(protocols); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java index 3cb8fafc7b..69c319219c 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java @@ -20,6 +20,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Summon; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.olympiad.OlympiadManager; @@ -100,6 +101,8 @@ public final class OfflineTradeUtil return false; } + PlayerCountManager.getInstance().incOfflineTradeCount(); + final L2GameClient client = player.getClient(); client.setDetached(true); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/GameServerTable.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/GameServerTable.java index 23ab31bac8..7d191232fe 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/GameServerTable.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/GameServerTable.java @@ -409,7 +409,18 @@ public final class GameServerTable implements IGameXmlReader */ public void setStatus(int status) { - _status = status; + if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) + { + _status = ServerStatus.STATUS_DOWN; + } + else if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) + { + _status = ServerStatus.STATUS_GM_ONLY; + } + else + { + _status = status; + } } /** diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/LoginServer.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/LoginServer.java index 642659a03d..d3e85d3abf 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/LoginServer.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/LoginServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.loginserver; +import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -32,35 +33,43 @@ import com.l2jmobius.Config; import com.l2jmobius.Server; import com.l2jmobius.commons.database.DatabaseBackup; import com.l2jmobius.commons.database.DatabaseFactory; +import com.l2jmobius.gameserver.network.loginserverpackets.game.ServerStatus; import com.l2jmobius.loginserver.network.ClientNetworkManager; +import com.l2jmobius.loginserver.ui.Gui; /** * @author KenM */ public final class LoginServer { - private final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); + public final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); public static final int PROTOCOL_REV = 0x0106; - private static LoginServer _instance; + private static LoginServer INSTANCE; private GameServerListener _gameServerListener; private Thread _restartLoginServer; + private static int _loginStatus = ServerStatus.STATUS_NORMAL; public static void main(String[] args) throws Exception { - new LoginServer(); + INSTANCE = new LoginServer(); } public static LoginServer getInstance() { - return _instance; + return INSTANCE; } private LoginServer() throws Exception { - _instance = this; Server.serverMode = Server.MODE_LOGINSERVER; + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + // Create log folder final File logFolder = new File(".", "log"); logFolder.mkdir(); @@ -96,6 +105,14 @@ public final class LoginServer loadBanFile(); + if (Config.LOGIN_SERVER_SCHEDULE_RESTART) + { + LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); + _restartLoginServer = new LoginServerRestart(); + _restartLoginServer.setDaemon(true); + _restartLoginServer.start(); + } + try { _gameServerListener = new GameServerListener(); @@ -116,7 +133,7 @@ public final class LoginServer return _gameServerListener; } - private void loadBanFile() + public void loadBanFile() { final File bannedFile = new File("./banned_ip.cfg"); if (bannedFile.exists() && bannedFile.isFile()) @@ -170,14 +187,6 @@ public final class LoginServer { LOGGER.warning("IP Bans file (" + bannedFile.getName() + ") is missing or is a directory, skipped."); } - - if (Config.LOGIN_SERVER_SCHEDULE_RESTART) - { - LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); - _restartLoginServer = new LoginServerRestart(); - _restartLoginServer.setDaemon(true); - _restartLoginServer.start(); - } } class LoginServerRestart extends Thread @@ -213,4 +222,14 @@ public final class LoginServer } Runtime.getRuntime().exit(restart ? 2 : 0); } + + public int getStatus() + { + return _loginStatus; + } + + public void setStatus(int status) + { + _loginStatus = status; + } } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java index 85bf1582c0..83223cd6d5 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java @@ -20,8 +20,10 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.IIncomingPacket; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.network.L2LoginClient; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayOk; @@ -61,7 +63,11 @@ public class RequestServerLogin implements IIncomingPacket // if we didnt showed the license we cant check these values if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2)) { - if (LoginController.getInstance().isLoginPossible(client, _serverId)) + if ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) || ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) && (client.getAccessLevel() < 1))) + { + client.close(LoginFailReason.REASON_ACCESS_FAILED); + } + else if (LoginController.getInstance().isLoginPossible(client, _serverId)) { client.setJoinedGS(true); client.sendPacket(new PlayOk(sk)); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/ui/Gui.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/ui/Gui.java new file mode 100644 index 0000000000..7dfddb4985 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/ui/Gui.java @@ -0,0 +1,275 @@ +/* + * 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.loginserver.ui; + +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.loginserver.GameServerTable; +import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; +import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmLoginServer; + JTextArea txtrConsole; + + JCheckBoxMenuItem chckbxmntmEnabled; + JCheckBoxMenuItem chckbxmntmDisabled; + JCheckBoxMenuItem chckbxmntmGmOnly; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + + public Gui() + { + frmLoginServer = new JFrame(); + frmLoginServer.setVisible(false); + frmLoginServer.setTitle("Mobius - LoginServer"); + frmLoginServer.setResizable(false); + frmLoginServer.setBounds(100, 100, 825, 618); + frmLoginServer.getContentPane().setLayout(null); + frmLoginServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmLoginServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmLoginServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmLoginServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(true); + } + }); + mnActions.add(mntmRestart); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmBannedIps = new JMenuItem("Banned IPs"); + mntmBannedIps.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBannedIps.addActionListener(arg0 -> + { + LoginController.getInstance().getBannedIps().clear(); + LoginServer.getInstance().loadBanFile(); + }); + mnReload.add(mntmBannedIps); + + JMenu mnStatus = new JMenu("Status"); + mnStatus.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnStatus); + + chckbxmntmEnabled = new JCheckBoxMenuItem("Enabled"); + chckbxmntmEnabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmEnabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(true); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_NORMAL); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_NORMAL); + } + LoginServer.getInstance().LOGGER.info("Status changed to enabled."); + }); + chckbxmntmEnabled.setSelected(true); + mnStatus.add(chckbxmntmEnabled); + + chckbxmntmDisabled = new JCheckBoxMenuItem("Disabled"); + chckbxmntmDisabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmDisabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(true); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_DOWN); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_DOWN); + } + LoginServer.getInstance().LOGGER.info("Status changed to disabled."); + }); + mnStatus.add(chckbxmntmDisabled); + + chckbxmntmGmOnly = new JCheckBoxMenuItem("GM only"); + chckbxmntmGmOnly.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmGmOnly.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(true); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_GM_ONLY); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_GM_ONLY); + } + LoginServer.getInstance().LOGGER.info("Status changed to GM only."); + }); + mnStatus.add(chckbxmntmGmOnly); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmLoginServer.setIconImages(icons); + + // Center frame to screen. + frmLoginServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmLoginServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/ui/frmAbout.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/ui/frmAbout.java new file mode 100644 index 0000000000..b535d860b6 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/loginserver/ui/frmAbout.java @@ -0,0 +1,115 @@ +/* + * 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.loginserver.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblLoginServer = new JLabel("Login Server"); + lblLoginServer.setHorizontalAlignment(SwingConstants.CENTER); + lblLoginServer.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblLoginServer.setBounds(10, 86, 271, 23); + frmAbout.getContentPane().add(lblLoginServer); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/build.xml b/L2J_Mobius_Classic_2.0_Saviors/build.xml index 2beb01c9c4..7f3abacdc5 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/build.xml +++ b/L2J_Mobius_Classic_2.0_Saviors/build.xml @@ -78,8 +78,8 @@ - - + + @@ -93,8 +93,8 @@ - - + + @@ -108,8 +108,8 @@ - - + + @@ -123,8 +123,8 @@ - - + + diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/GameServer.bat b/L2J_Mobius_Classic_2.0_Saviors/dist/game/GameServer.bat deleted file mode 100644 index 2dbaac7089..0000000000 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/GameServer.bat +++ /dev/null @@ -1,30 +0,0 @@ -@set /p parameters=. + */ +package com.l2jmobius.commons.util; + +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; + +/* + * A class to control the maximum number of lines to be stored in a Document + * + * Excess lines can be removed from the start or end of the Document + * depending on your requirement. + * + * a) if you append text to the Document, then you would want to remove lines + * from the start. + * b) if you insert text at the beginning of the Document, then you would + * want to remove lines from the end. + */ +public class LimitLinesDocumentListener implements DocumentListener +{ + private int _maximumLines; + private final boolean _isRemoveFromStart; + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start of the Document. + */ + public LimitLinesDocumentListener(int maximumLines) + { + this(maximumLines, true); + } + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start or end of the Document, depending on the boolean value specified. + */ + public LimitLinesDocumentListener(int maximumLines, boolean isRemoveFromStart) + { + setLimitLines(maximumLines); + _isRemoveFromStart = isRemoveFromStart; + } + + /* + * Return the maximum number of lines to be stored in the Document. + */ + public int getLimitLines() + { + return _maximumLines; + } + + /* + * Set the maximum number of lines to be stored in the Document. + */ + public void setLimitLines(int maximumLines) + { + if (maximumLines < 1) + { + String message = "Maximum lines must be greater than 0"; + throw new IllegalArgumentException(message); + } + + _maximumLines = maximumLines; + } + + /* + * Handle insertion of new text into the Document. + */ + @Override + public void insertUpdate(final DocumentEvent e) + { + // Changes to the Document can not be done within the listener so we need to add the processing to the end of the EDT. + SwingUtilities.invokeLater(() -> removeLines(e)); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + } + + @Override + public void changedUpdate(DocumentEvent e) + { + } + + /* + * Remove lines from the Document when necessary. + */ + private void removeLines(DocumentEvent e) + { + // The root Element of the Document will tell us the total number of line in the Document. + Document document = e.getDocument(); + Element root = document.getDefaultRootElement(); + + while (root.getElementCount() > _maximumLines) + { + if (_isRemoveFromStart) + { + removeFromStart(document, root); + } + else + { + removeFromEnd(document, root); + } + } + } + + /* + * Remove lines from the start of the Document + */ + private void removeFromStart(Document document, Element root) + { + Element line = root.getElement(0); + int end = line.getEndOffset(); + + try + { + document.remove(0, end); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } + + /* + * Remove lines from the end of the Document + */ + private void removeFromEnd(Document document, Element root) + { + // We use start minus 1 to make sure we remove the newline character of the previous line. + + Element line = root.getElement(root.getElementCount() - 1); + int start = line.getStartOffset(); + int end = line.getEndOffset(); + + try + { + document.remove(start - 1, end - start); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/commons/util/SplashScreen.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/commons/util/SplashScreen.java index 80992f1b4d..5086e53e9c 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/commons/util/SplashScreen.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/commons/util/SplashScreen.java @@ -21,8 +21,8 @@ import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Timer; +import java.util.TimerTask; import javax.swing.ImageIcon; import javax.swing.JFrame; @@ -52,22 +52,24 @@ public class SplashScreen extends JWindow setAlwaysOnTop(true); setVisible(true); - // Schedule to close. - Executors.newScheduledThreadPool(1).schedule(this::close, imageIcon.getIconWidth() > 0 ? time : 100, TimeUnit.MILLISECONDS); - } - - public void close() - { - setVisible(false); - if (parentFrame != null) + new Timer().schedule(new TimerTask() { - // Make parent visible. - parentFrame.setVisible(true); - // Focus parent window. - parentFrame.toFront(); - parentFrame.setState(Frame.ICONIFIED); - parentFrame.setState(Frame.NORMAL); - } + @Override + public void run() + { + setVisible(false); + if (parentFrame != null) + { + // Make parent visible. + parentFrame.setVisible(true); + // Focus parent window. + parentFrame.toFront(); + parentFrame.setState(Frame.ICONIFIED); + parentFrame.setState(Frame.NORMAL); + } + dispose(); + } + }, imageIcon.getIconWidth() > 0 ? time : 100); } @Override diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java index c9830de34b..7316defa0d 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.gameserver; +import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.io.File; import java.io.FileInputStream; @@ -145,6 +146,7 @@ import com.l2jmobius.gameserver.network.loginserver.LoginServerNetworkManager; import com.l2jmobius.gameserver.network.telnet.TelnetServer; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.taskmanager.TaskManager; +import com.l2jmobius.gameserver.ui.Gui; import com.l2jmobius.gameserver.util.Broadcast; public class GameServer @@ -168,6 +170,28 @@ public class GameServer public GameServer() throws Exception { final long serverLoadStart = System.currentTimeMillis(); + Server.serverMode = Server.MODE_GAMESERVER; + + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + + // Create log folder + final File logFolder = new File(Config.DATAPACK_ROOT, "log"); + logFolder.mkdir(); + + // Create input stream for log file -- or store file data into memory + try (InputStream is = new FileInputStream(new File("./log.cfg"))) + { + LogManager.getLogManager().readConfiguration(is); + } + + // Initialize config + Config.load(); + printSection("Database"); + DatabaseFactory.getInstance(); printSection("ThreadPool"); ThreadPool.init(); @@ -450,24 +474,6 @@ public class GameServer public static void main(String[] args) throws Exception { - Server.serverMode = Server.MODE_GAMESERVER; - - /*** Main ***/ - // Create log folder - final File logFolder = new File(Config.DATAPACK_ROOT, "log"); - logFolder.mkdir(); - - // Create input stream for log file -- or store file data into memory - try (InputStream is = new FileInputStream(new File("./log.cfg"))) - { - LogManager.getLogManager().readConfiguration(is); - } - - // Initialize config - Config.load(); - printSection("Database"); - DatabaseFactory.getInstance(); - INSTANCE = new GameServer(); } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java index 9a1a01c8a6..625915e123 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java @@ -28,6 +28,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.gameserver.LoginServerThread; import com.l2jmobius.gameserver.enums.PrivateStoreType; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.L2ManufactureItem; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.TradeItem; @@ -298,6 +299,7 @@ public class OfflineTradersTable player.setOnlineStatus(true, true); player.restoreEffects(); player.broadcastUserInfo(); + PlayerCountManager.getInstance().incOfflineTradeCount(); nTraders++; } catch (Exception e) @@ -451,6 +453,8 @@ public class OfflineTradersTable public static synchronized void removeTrader(int traderObjId) { + PlayerCountManager.getInstance().decOfflineTradeCount(); + try (Connection con = DatabaseFactory.getInstance().getConnection(); PreparedStatement stm1 = con.prepareStatement(CLEAR_OFFLINE_TABLE_ITEMS_PLAYER); PreparedStatement stm2 = con.prepareStatement(CLEAR_OFFLINE_TABLE_PLAYER)) diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java new file mode 100644 index 0000000000..cb2fab84ed --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java @@ -0,0 +1,77 @@ +/* + * 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.instancemanager; + +/** + * @author Mobius + */ +public class PlayerCountManager +{ + private volatile static int connectedCount = 0; + private volatile static int maxConnectedCount = 0; + private volatile static int offlineTradeCount = 0; + + protected PlayerCountManager() + { + } + + public int getConnectedCount() + { + return connectedCount; + } + + public int getMaxConnectedCount() + { + return maxConnectedCount; + } + + public int getOfflineTradeCount() + { + return offlineTradeCount; + } + + public synchronized void incConnectedCount() + { + connectedCount++; + maxConnectedCount = Math.max(maxConnectedCount, connectedCount); + } + + public void decConnectedCount() + { + connectedCount--; + } + + public void incOfflineTradeCount() + { + offlineTradeCount++; + } + + public synchronized void decOfflineTradeCount() + { + offlineTradeCount = Math.max(0, offlineTradeCount - 1); + } + + public static PlayerCountManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final PlayerCountManager INSTANCE = new PlayerCountManager(); + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2World.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2World.java index 9b02364b07..bea222354b 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2World.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2World.java @@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -135,6 +136,8 @@ public final class L2World if (object.isPlayer()) { + PlayerCountManager.getInstance().incConnectedCount(); + final L2PcInstance newPlayer = (L2PcInstance) object; if (newPlayer.isTeleporting()) // TODO: drop when we stop removing player from the world while teleporting. { @@ -170,6 +173,8 @@ public final class L2World _allObjects.remove(object.getObjectId()); if (object.isPlayer()) { + PlayerCountManager.getInstance().decConnectedCount(); + final L2PcInstance player = (L2PcInstance) object; if (player.isTeleporting()) // TODO: drop when we stop removing player from the world while teleportingq. { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/Gui.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/Gui.java new file mode 100644 index 0000000000..0ea9ac46e0 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/Gui.java @@ -0,0 +1,358 @@ +/* + * 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.ui; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.gameserver.Shutdown; +import com.l2jmobius.gameserver.cache.HtmCache; +import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.BuyListData; +import com.l2jmobius.gameserver.data.xml.impl.MultisellData; +import com.l2jmobius.gameserver.util.Broadcast; +import com.l2jmobius.gameserver.util.Util; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmGameServer; + JTextArea txtrConsole; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + final static String[] abortOptions = + { + "Abort", + "Cancel" + }; + final static String[] confirmOptions = + { + "Confirm", + "Cancel" + }; + + public Gui() + { + frmGameServer = new JFrame(); + frmGameServer.setVisible(false); + frmGameServer.setTitle("Mobius - GameServer"); + frmGameServer.setResizable(false); + frmGameServer.setBounds(100, 100, 825, 618); + frmGameServer.getContentPane().setLayout(null); + frmGameServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmGameServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown server immediately?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + Shutdown.getInstance().startShutdown(null, 1, false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmGameServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmGameServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Shutdown delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, false); + } + } + } + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Restart delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, true); + } + } + } + } + }); + mnActions.add(mntmRestart); + + JMenuItem mntmAbort = new JMenuItem("Abort"); + mntmAbort.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbort.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Abort server shutdown?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, abortOptions, abortOptions[1]) == 0) + { + Shutdown.getInstance().abort(null); + } + }); + mnActions.add(mntmAbort); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmConfigs = new JMenuItem("Configs"); + mntmConfigs.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmConfigs.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload configs?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + Config.load(); + } + }); + mnReload.add(mntmConfigs); + + JMenuItem mntmAccess = new JMenuItem("Access"); + mntmAccess.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAccess.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload admin access levels?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + AdminData.getInstance().load(); + } + }); + mnReload.add(mntmAccess); + + JMenuItem mntmHtml = new JMenuItem("HTML"); + mntmHtml.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmHtml.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload HTML files?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + HtmCache.getInstance().reload(); + } + }); + mnReload.add(mntmHtml); + + JMenuItem mntmMultisells = new JMenuItem("Multisells"); + mntmMultisells.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmMultisells.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload multisells?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + MultisellData.getInstance().load(); + } + }); + mnReload.add(mntmMultisells); + + JMenuItem mntmBuylists = new JMenuItem("Buylists"); + mntmBuylists.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBuylists.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload buylists?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + BuyListData.getInstance().load(); + } + }); + mnReload.add(mntmBuylists); + + JMenu mnAnnounce = new JMenu("Announce"); + mnAnnounce.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnAnnounce); + + JMenuItem mntmNormal = new JMenuItem("Normal"); + mntmNormal.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmNormal.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, false); + } + } + }); + mnAnnounce.add(mntmNormal); + + JMenuItem mntmCritical = new JMenuItem("Critical"); + mntmCritical.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmCritical.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Critical announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, true); + } + } + }); + mnAnnounce.add(mntmCritical); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmGameServer.setIconImages(icons); + + // System Panel. + JPanel systemPanel = new SystemPanel(); + JLayeredPane layeredPanel = new JLayeredPane(); + frmGameServer.getContentPane().add(layeredPanel, BorderLayout.CENTER); + layeredPanel.setBounds(0, 0, 819, 566); + layeredPanel.add(scrollPanel, new Integer(0), 0); + layeredPanel.add(systemPanel, new Integer(1), 0); + + // Center frame to screen. + frmGameServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmGameServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/Locator.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/Locator.java new file mode 100644 index 0000000000..e891609b67 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/Locator.java @@ -0,0 +1,295 @@ +/* + * 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.ui; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Locale; + +final class Locator +{ + /** + * Constructor for Locator. + */ + private Locator() + { + } + + /** + * Method getClassSource. + * @param c Class + * @return File + */ + static File getClassSource(Class c) + { + String classResource = c.getName().replace('.', '/') + ".class"; + return getResourceSource(c.getClassLoader(), classResource); + } + + /** + * Method getResourceSource. + * @param c ClassLoader + * @param resource String + * @return File + */ + private static File getResourceSource(ClassLoader c, String resource) + { + if (c == null) + { + c = Locator.class.getClassLoader(); + } + + URL url = null; + + if (c == null) + { + url = ClassLoader.getSystemResource(resource); + } + else + { + url = c.getResource(resource); + } + + if (url != null) + { + String u = url.toString(); + + if (u.startsWith("jar:file:")) + { + int pling = u.indexOf("!"); + String jarName = u.substring(4, pling); + return new File(fromURI(jarName)); + } + else if (u.startsWith("file:")) + { + int tail = u.indexOf(resource); + String dirName = u.substring(0, tail); + return new File(fromURI(dirName)); + } + } + + return null; + } + + /** + * Method fromURI. + * @param uri String + * @return String + */ + private static String fromURI(String uri) + { + URL url = null; + + try + { + url = new URL(uri); + } + catch (MalformedURLException emYouEarlEx) + { + // empty catch clause + } + + if ((url == null) || !"file".equals(url.getProtocol())) + { + throw new IllegalArgumentException("Can only handle valid file: URIs"); + } + + StringBuilder buf = new StringBuilder(url.getHost()); + + if (buf.length() > 0) + { + buf.insert(0, File.separatorChar).insert(0, File.separatorChar); + } + + String file = url.getFile(); + int queryPos = file.indexOf('?'); + buf.append(queryPos < 0 ? file : file.substring(0, queryPos)); + uri = buf.toString().replace('/', File.separatorChar); + + if ((File.pathSeparatorChar == ';') && uri.startsWith("\\") && (uri.length() > 2) && Character.isLetter(uri.charAt(1)) && (uri.lastIndexOf(':') > -1)) + { + uri = uri.substring(1); + } + + String path = decodeUri(uri); + return path; + } + + /** + * Method decodeUri. + * @param uri String + * @return String + */ + private static String decodeUri(String uri) + { + if (uri.indexOf('%') == -1) + { + return uri; + } + + StringBuilder sb = new StringBuilder(); + CharacterIterator iter = new StringCharacterIterator(uri); + + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + { + if (c == '%') + { + char c1 = iter.next(); + + if (c1 != CharacterIterator.DONE) + { + int i1 = Character.digit(c1, 16); + char c2 = iter.next(); + + if (c2 != CharacterIterator.DONE) + { + int i2 = Character.digit(c2, 16); + sb.append((char) ((i1 << 4) + i2)); + } + } + } + else + { + sb.append(c); + } + } + + String path = sb.toString(); + return path; + } + + /** + * Method getToolsJar. + * @return File + */ + static File getToolsJar() + { + boolean toolsJarAvailable = false; + + try + { + Class.forName("com.sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e) + { + try + { + Class.forName("sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e2) + { + // empty catch clause + } + } + + if (toolsJarAvailable) + { + return null; + } + + String javaHome = System.getProperty("java.home"); + + if (javaHome.toLowerCase(Locale.US).endsWith("jre")) + { + javaHome = javaHome.substring(0, javaHome.length() - 4); + } + + File toolsJar = new File(javaHome + "/lib/tools.jar"); + + if (!toolsJar.exists()) + { + System.out.println("Unable to locate tools.jar. " + "Expected to find it in " + toolsJar.getPath()); + return null; + } + + return toolsJar; + } + + /** + * Method getLocationURLs. + * @param location File + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + static URL[] getLocationURLs(File location) throws MalformedURLException + { + return getLocationURLs(location, new String[] + { + ".jar" + }); + } + + /** + * Method getLocationURLs. + * @param location File + * @param extensions String[] + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + private static URL[] getLocationURLs(File location, final String[] extensions) throws MalformedURLException + { + URL[] urls = new URL[0]; + + if (!location.exists()) + { + return urls; + } + + if (!location.isDirectory()) + { + urls = new URL[1]; + String path = location.getPath(); + + for (String extension : extensions) + { + if (path.toLowerCase().endsWith(extension)) + { + urls[0] = location.toURI().toURL(); + break; + } + } + + return urls; + } + + File[] matches = location.listFiles((FilenameFilter) (dir, name) -> + { + for (String extension : extensions) + { + if (name.toLowerCase().endsWith(extension)) + { + return true; + } + } + return false; + }); + urls = new URL[matches.length]; + + for (int i = 0; i < matches.length; ++i) + { + urls[i] = matches[i].toURI().toURL(); + } + + return urls; + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/SystemPanel.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/SystemPanel.java new file mode 100644 index 0000000000..68cabb3c12 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/SystemPanel.java @@ -0,0 +1,142 @@ +/* + * 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.ui; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.LineBorder; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.GameServer; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; + +/** + * @author Mobius + */ +public class SystemPanel extends JPanel +{ + final static long startTime = System.currentTimeMillis(); + + public SystemPanel() + { + setBackground(Color.WHITE); + setBounds(500, 20, 284, 140); + setBorder(new LineBorder(new Color(0, 0, 0), 1, false)); + setOpaque(true); + setLayout(null); + + JLabel lblProtocol = new JLabel("Protocol"); + lblProtocol.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblProtocol.setBounds(10, 5, 264, 17); + add(lblProtocol); + + JLabel lblConnected = new JLabel("Connected"); + lblConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblConnected.setBounds(10, 23, 264, 17); + add(lblConnected); + + JLabel lblMaxConnected = new JLabel("Max connected"); + lblMaxConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblMaxConnected.setBounds(10, 41, 264, 17); + add(lblMaxConnected); + + JLabel lblOfflineShops = new JLabel("Offline trade"); + lblOfflineShops.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblOfflineShops.setBounds(10, 59, 264, 17); + add(lblOfflineShops); + + JLabel lblElapsedTime = new JLabel("Elapsed time"); + lblElapsedTime.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblElapsedTime.setBounds(10, 77, 264, 17); + add(lblElapsedTime); + + JLabel lblJavaVersion = new JLabel("Build JDK"); + lblJavaVersion.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblJavaVersion.setBounds(10, 95, 264, 17); + add(lblJavaVersion); + + JLabel lblBuildDate = new JLabel("Build date"); + lblBuildDate.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblBuildDate.setBounds(10, 113, 264, 17); + add(lblBuildDate); + + // Set initial values. + lblProtocol.setText("Protocol: 0"); + lblConnected.setText("Connected: 0"); + lblMaxConnected.setText("Max connected: 0"); + lblOfflineShops.setText("Offline trade: 0"); + lblElapsedTime.setText("Elapsed: 0 sec"); + lblJavaVersion.setText("Java version: " + System.getProperty("java.version")); + lblBuildDate.setText("Build date: Unavailable"); + try + { + File jarName = Locator.getClassSource(GameServer.class); + JarFile jarFile = new JarFile(jarName); + Attributes attrs = jarFile.getManifest().getMainAttributes(); + lblBuildDate.setText("Build date: " + attrs.getValue("Build-Date").split(" ")[0]); + jarFile.close(); + } + catch (Exception e) + { + } + + // Initial update task. + new Timer().schedule(new TimerTask() + { + @Override + public void run() + { + lblProtocol.setText((Config.PROTOCOL_LIST.size() > 1 ? "Protocols: " : "Protocol: ") + Config.PROTOCOL_LIST.toString()); + } + }, 4500); + + // Repeating elapsed time task. + new Timer().scheduleAtFixedRate(new TimerTask() + { + @Override + public void run() + { + lblConnected.setText("Connected: " + PlayerCountManager.getInstance().getConnectedCount()); + lblMaxConnected.setText("Max connected: " + PlayerCountManager.getInstance().getMaxConnectedCount()); + lblOfflineShops.setText("Offline trade: " + PlayerCountManager.getInstance().getOfflineTradeCount()); + lblElapsedTime.setText("Elapsed: " + getDurationBreakdown(System.currentTimeMillis() - startTime)); + } + }, 1000, 1000); + } + + static String getDurationBreakdown(long millis) + { + long days = TimeUnit.MILLISECONDS.toDays(millis); + millis -= TimeUnit.DAYS.toMillis(days); + long hours = TimeUnit.MILLISECONDS.toHours(millis); + millis -= TimeUnit.HOURS.toMillis(hours); + long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); + millis -= TimeUnit.MINUTES.toMillis(minutes); + long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); + + return (days + "d " + hours + "h " + minutes + "m " + seconds + "s"); + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/frmAbout.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/frmAbout.java new file mode 100644 index 0000000000..e8a4f9a47c --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ui/frmAbout.java @@ -0,0 +1,143 @@ +/* + * 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.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblSupports = new JLabel("Server Protocol"); + lblSupports.setHorizontalAlignment(SwingConstants.CENTER); + lblSupports.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblSupports.setBounds(10, 78, 271, 23); + frmAbout.getContentPane().add(lblSupports); + + JLabel lblProtocols = new JLabel("Protocol Number"); + lblProtocols.setHorizontalAlignment(SwingConstants.CENTER); + lblProtocols.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblProtocols.setBounds(10, 92, 271, 23); + frmAbout.getContentPane().add(lblProtocols); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Generate protocols text. + String protocols = ""; + if (Config.PROTOCOL_LIST.size() > 1) + { + for (Integer number : Config.PROTOCOL_LIST) + { + if (!protocols.isEmpty()) + { + protocols += " - "; + } + protocols += number; + } + lblSupports.setText("Server Protocols"); + } + else + { + protocols += Config.PROTOCOL_LIST.get(0); + } + lblProtocols.setText(protocols); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java index ecc40e644b..056fa7ea38 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java @@ -20,6 +20,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Summon; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.olympiad.OlympiadManager; @@ -100,6 +101,8 @@ public final class OfflineTradeUtil return false; } + PlayerCountManager.getInstance().incOfflineTradeCount(); + final L2GameClient client = player.getClient(); client.setDetached(true); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/GameServerTable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/GameServerTable.java index 362aa93ad5..73110fb6dc 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/GameServerTable.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/GameServerTable.java @@ -409,7 +409,18 @@ public final class GameServerTable implements IGameXmlReader */ public void setStatus(int status) { - _status = status; + if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) + { + _status = ServerStatus.STATUS_DOWN; + } + else if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) + { + _status = ServerStatus.STATUS_GM_ONLY; + } + else + { + _status = status; + } } /** diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/LoginServer.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/LoginServer.java index 6c2062e622..39377afee3 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/LoginServer.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/LoginServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.loginserver; +import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -32,35 +33,43 @@ import com.l2jmobius.Config; import com.l2jmobius.Server; import com.l2jmobius.commons.database.DatabaseBackup; import com.l2jmobius.commons.database.DatabaseFactory; +import com.l2jmobius.gameserver.network.loginserverpackets.game.ServerStatus; import com.l2jmobius.loginserver.network.ClientNetworkManager; +import com.l2jmobius.loginserver.ui.Gui; /** * @author KenM */ public final class LoginServer { - private final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); + public final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); public static final int PROTOCOL_REV = 0x0106; - private static LoginServer _instance; + private static LoginServer INSTANCE; private GameServerListener _gameServerListener; private Thread _restartLoginServer; + private static int _loginStatus = ServerStatus.STATUS_NORMAL; public static void main(String[] args) throws Exception { - new LoginServer(); + INSTANCE = new LoginServer(); } public static LoginServer getInstance() { - return _instance; + return INSTANCE; } private LoginServer() throws Exception { - _instance = this; Server.serverMode = Server.MODE_LOGINSERVER; + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + // Create log folder final File logFolder = new File(".", "log"); logFolder.mkdir(); @@ -96,6 +105,14 @@ public final class LoginServer loadBanFile(); + if (Config.LOGIN_SERVER_SCHEDULE_RESTART) + { + LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); + _restartLoginServer = new LoginServerRestart(); + _restartLoginServer.setDaemon(true); + _restartLoginServer.start(); + } + try { _gameServerListener = new GameServerListener(); @@ -116,7 +133,7 @@ public final class LoginServer return _gameServerListener; } - private void loadBanFile() + public void loadBanFile() { final File bannedFile = new File("./banned_ip.cfg"); if (bannedFile.exists() && bannedFile.isFile()) @@ -170,14 +187,6 @@ public final class LoginServer { LOGGER.warning("IP Bans file (" + bannedFile.getName() + ") is missing or is a directory, skipped."); } - - if (Config.LOGIN_SERVER_SCHEDULE_RESTART) - { - LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); - _restartLoginServer = new LoginServerRestart(); - _restartLoginServer.setDaemon(true); - _restartLoginServer.start(); - } } class LoginServerRestart extends Thread @@ -213,4 +222,14 @@ public final class LoginServer } Runtime.getRuntime().exit(restart ? 2 : 0); } + + public int getStatus() + { + return _loginStatus; + } + + public void setStatus(int status) + { + _loginStatus = status; + } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java index 670365b761..fa5c1e0a3a 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java @@ -20,8 +20,10 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.IIncomingPacket; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.network.L2LoginClient; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayOk; @@ -61,7 +63,11 @@ public class RequestServerLogin implements IIncomingPacket // if we didnt showed the license we cant check these values if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2)) { - if (LoginController.getInstance().isLoginPossible(client, _serverId)) + if ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) || ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) && (client.getAccessLevel() < 1))) + { + client.close(LoginFailReason.REASON_ACCESS_FAILED); + } + else if (LoginController.getInstance().isLoginPossible(client, _serverId)) { client.setJoinedGS(true); client.sendPacket(new PlayOk(sk)); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/ui/Gui.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/ui/Gui.java new file mode 100644 index 0000000000..7dfddb4985 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/ui/Gui.java @@ -0,0 +1,275 @@ +/* + * 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.loginserver.ui; + +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.loginserver.GameServerTable; +import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; +import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmLoginServer; + JTextArea txtrConsole; + + JCheckBoxMenuItem chckbxmntmEnabled; + JCheckBoxMenuItem chckbxmntmDisabled; + JCheckBoxMenuItem chckbxmntmGmOnly; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + + public Gui() + { + frmLoginServer = new JFrame(); + frmLoginServer.setVisible(false); + frmLoginServer.setTitle("Mobius - LoginServer"); + frmLoginServer.setResizable(false); + frmLoginServer.setBounds(100, 100, 825, 618); + frmLoginServer.getContentPane().setLayout(null); + frmLoginServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmLoginServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmLoginServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmLoginServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(true); + } + }); + mnActions.add(mntmRestart); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmBannedIps = new JMenuItem("Banned IPs"); + mntmBannedIps.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBannedIps.addActionListener(arg0 -> + { + LoginController.getInstance().getBannedIps().clear(); + LoginServer.getInstance().loadBanFile(); + }); + mnReload.add(mntmBannedIps); + + JMenu mnStatus = new JMenu("Status"); + mnStatus.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnStatus); + + chckbxmntmEnabled = new JCheckBoxMenuItem("Enabled"); + chckbxmntmEnabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmEnabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(true); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_NORMAL); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_NORMAL); + } + LoginServer.getInstance().LOGGER.info("Status changed to enabled."); + }); + chckbxmntmEnabled.setSelected(true); + mnStatus.add(chckbxmntmEnabled); + + chckbxmntmDisabled = new JCheckBoxMenuItem("Disabled"); + chckbxmntmDisabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmDisabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(true); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_DOWN); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_DOWN); + } + LoginServer.getInstance().LOGGER.info("Status changed to disabled."); + }); + mnStatus.add(chckbxmntmDisabled); + + chckbxmntmGmOnly = new JCheckBoxMenuItem("GM only"); + chckbxmntmGmOnly.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmGmOnly.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(true); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_GM_ONLY); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_GM_ONLY); + } + LoginServer.getInstance().LOGGER.info("Status changed to GM only."); + }); + mnStatus.add(chckbxmntmGmOnly); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmLoginServer.setIconImages(icons); + + // Center frame to screen. + frmLoginServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmLoginServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/ui/frmAbout.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/ui/frmAbout.java new file mode 100644 index 0000000000..b535d860b6 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/loginserver/ui/frmAbout.java @@ -0,0 +1,115 @@ +/* + * 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.loginserver.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblLoginServer = new JLabel("Login Server"); + lblLoginServer.setHorizontalAlignment(SwingConstants.CENTER); + lblLoginServer.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblLoginServer.setBounds(10, 86, 271, 23); + frmAbout.getContentPane().add(lblLoginServer); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_Classic_2.0_Zaken/build.xml b/L2J_Mobius_Classic_2.0_Zaken/build.xml index d2f12ef70b..e92df95d5b 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/build.xml +++ b/L2J_Mobius_Classic_2.0_Zaken/build.xml @@ -78,8 +78,8 @@ - - + + @@ -93,8 +93,8 @@ - - + + @@ -108,8 +108,8 @@ - - + + @@ -123,8 +123,8 @@ - - + + diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/GameServer.bat b/L2J_Mobius_Classic_2.0_Zaken/dist/game/GameServer.bat deleted file mode 100644 index 2dbaac7089..0000000000 --- a/L2J_Mobius_Classic_2.0_Zaken/dist/game/GameServer.bat +++ /dev/null @@ -1,30 +0,0 @@ -@set /p parameters=. + */ +package com.l2jmobius.commons.util; + +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; + +/* + * A class to control the maximum number of lines to be stored in a Document + * + * Excess lines can be removed from the start or end of the Document + * depending on your requirement. + * + * a) if you append text to the Document, then you would want to remove lines + * from the start. + * b) if you insert text at the beginning of the Document, then you would + * want to remove lines from the end. + */ +public class LimitLinesDocumentListener implements DocumentListener +{ + private int _maximumLines; + private final boolean _isRemoveFromStart; + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start of the Document. + */ + public LimitLinesDocumentListener(int maximumLines) + { + this(maximumLines, true); + } + + /* + * Specify the number of lines to be stored in the Document. Extra lines will be removed from the start or end of the Document, depending on the boolean value specified. + */ + public LimitLinesDocumentListener(int maximumLines, boolean isRemoveFromStart) + { + setLimitLines(maximumLines); + _isRemoveFromStart = isRemoveFromStart; + } + + /* + * Return the maximum number of lines to be stored in the Document. + */ + public int getLimitLines() + { + return _maximumLines; + } + + /* + * Set the maximum number of lines to be stored in the Document. + */ + public void setLimitLines(int maximumLines) + { + if (maximumLines < 1) + { + String message = "Maximum lines must be greater than 0"; + throw new IllegalArgumentException(message); + } + + _maximumLines = maximumLines; + } + + /* + * Handle insertion of new text into the Document. + */ + @Override + public void insertUpdate(final DocumentEvent e) + { + // Changes to the Document can not be done within the listener so we need to add the processing to the end of the EDT. + SwingUtilities.invokeLater(() -> removeLines(e)); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + } + + @Override + public void changedUpdate(DocumentEvent e) + { + } + + /* + * Remove lines from the Document when necessary. + */ + private void removeLines(DocumentEvent e) + { + // The root Element of the Document will tell us the total number of line in the Document. + Document document = e.getDocument(); + Element root = document.getDefaultRootElement(); + + while (root.getElementCount() > _maximumLines) + { + if (_isRemoveFromStart) + { + removeFromStart(document, root); + } + else + { + removeFromEnd(document, root); + } + } + } + + /* + * Remove lines from the start of the Document + */ + private void removeFromStart(Document document, Element root) + { + Element line = root.getElement(0); + int end = line.getEndOffset(); + + try + { + document.remove(0, end); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } + + /* + * Remove lines from the end of the Document + */ + private void removeFromEnd(Document document, Element root) + { + // We use start minus 1 to make sure we remove the newline character of the previous line. + + Element line = root.getElement(root.getElementCount() - 1); + int start = line.getStartOffset(); + int end = line.getEndOffset(); + + try + { + document.remove(start - 1, end - start); + } + catch (BadLocationException ble) + { + System.out.println(ble); + } + } +} \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/commons/util/SplashScreen.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/commons/util/SplashScreen.java index 80992f1b4d..5086e53e9c 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/commons/util/SplashScreen.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/commons/util/SplashScreen.java @@ -21,8 +21,8 @@ import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Timer; +import java.util.TimerTask; import javax.swing.ImageIcon; import javax.swing.JFrame; @@ -52,22 +52,24 @@ public class SplashScreen extends JWindow setAlwaysOnTop(true); setVisible(true); - // Schedule to close. - Executors.newScheduledThreadPool(1).schedule(this::close, imageIcon.getIconWidth() > 0 ? time : 100, TimeUnit.MILLISECONDS); - } - - public void close() - { - setVisible(false); - if (parentFrame != null) + new Timer().schedule(new TimerTask() { - // Make parent visible. - parentFrame.setVisible(true); - // Focus parent window. - parentFrame.toFront(); - parentFrame.setState(Frame.ICONIFIED); - parentFrame.setState(Frame.NORMAL); - } + @Override + public void run() + { + setVisible(false); + if (parentFrame != null) + { + // Make parent visible. + parentFrame.setVisible(true); + // Focus parent window. + parentFrame.toFront(); + parentFrame.setState(Frame.ICONIFIED); + parentFrame.setState(Frame.NORMAL); + } + dispose(); + } + }, imageIcon.getIconWidth() > 0 ? time : 100); } @Override diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java index c9830de34b..7316defa0d 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.gameserver; +import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.io.File; import java.io.FileInputStream; @@ -145,6 +146,7 @@ import com.l2jmobius.gameserver.network.loginserver.LoginServerNetworkManager; import com.l2jmobius.gameserver.network.telnet.TelnetServer; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.taskmanager.TaskManager; +import com.l2jmobius.gameserver.ui.Gui; import com.l2jmobius.gameserver.util.Broadcast; public class GameServer @@ -168,6 +170,28 @@ public class GameServer public GameServer() throws Exception { final long serverLoadStart = System.currentTimeMillis(); + Server.serverMode = Server.MODE_GAMESERVER; + + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + + // Create log folder + final File logFolder = new File(Config.DATAPACK_ROOT, "log"); + logFolder.mkdir(); + + // Create input stream for log file -- or store file data into memory + try (InputStream is = new FileInputStream(new File("./log.cfg"))) + { + LogManager.getLogManager().readConfiguration(is); + } + + // Initialize config + Config.load(); + printSection("Database"); + DatabaseFactory.getInstance(); printSection("ThreadPool"); ThreadPool.init(); @@ -450,24 +474,6 @@ public class GameServer public static void main(String[] args) throws Exception { - Server.serverMode = Server.MODE_GAMESERVER; - - /*** Main ***/ - // Create log folder - final File logFolder = new File(Config.DATAPACK_ROOT, "log"); - logFolder.mkdir(); - - // Create input stream for log file -- or store file data into memory - try (InputStream is = new FileInputStream(new File("./log.cfg"))) - { - LogManager.getLogManager().readConfiguration(is); - } - - // Initialize config - Config.load(); - printSection("Database"); - DatabaseFactory.getInstance(); - INSTANCE = new GameServer(); } diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java index 9a1a01c8a6..625915e123 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java @@ -28,6 +28,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.database.DatabaseFactory; import com.l2jmobius.gameserver.LoginServerThread; import com.l2jmobius.gameserver.enums.PrivateStoreType; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.L2ManufactureItem; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.TradeItem; @@ -298,6 +299,7 @@ public class OfflineTradersTable player.setOnlineStatus(true, true); player.restoreEffects(); player.broadcastUserInfo(); + PlayerCountManager.getInstance().incOfflineTradeCount(); nTraders++; } catch (Exception e) @@ -451,6 +453,8 @@ public class OfflineTradersTable public static synchronized void removeTrader(int traderObjId) { + PlayerCountManager.getInstance().decOfflineTradeCount(); + try (Connection con = DatabaseFactory.getInstance().getConnection(); PreparedStatement stm1 = con.prepareStatement(CLEAR_OFFLINE_TABLE_ITEMS_PLAYER); PreparedStatement stm2 = con.prepareStatement(CLEAR_OFFLINE_TABLE_PLAYER)) diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java new file mode 100644 index 0000000000..cb2fab84ed --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/instancemanager/PlayerCountManager.java @@ -0,0 +1,77 @@ +/* + * 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.instancemanager; + +/** + * @author Mobius + */ +public class PlayerCountManager +{ + private volatile static int connectedCount = 0; + private volatile static int maxConnectedCount = 0; + private volatile static int offlineTradeCount = 0; + + protected PlayerCountManager() + { + } + + public int getConnectedCount() + { + return connectedCount; + } + + public int getMaxConnectedCount() + { + return maxConnectedCount; + } + + public int getOfflineTradeCount() + { + return offlineTradeCount; + } + + public synchronized void incConnectedCount() + { + connectedCount++; + maxConnectedCount = Math.max(maxConnectedCount, connectedCount); + } + + public void decConnectedCount() + { + connectedCount--; + } + + public void incOfflineTradeCount() + { + offlineTradeCount++; + } + + public synchronized void decOfflineTradeCount() + { + offlineTradeCount = Math.max(0, offlineTradeCount - 1); + } + + public static PlayerCountManager getInstance() + { + return SingletonHolder.INSTANCE; + } + + private static class SingletonHolder + { + protected static final PlayerCountManager INSTANCE = new PlayerCountManager(); + } +} diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/L2World.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/L2World.java index 9b02364b07..bea222354b 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/L2World.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/L2World.java @@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -135,6 +136,8 @@ public final class L2World if (object.isPlayer()) { + PlayerCountManager.getInstance().incConnectedCount(); + final L2PcInstance newPlayer = (L2PcInstance) object; if (newPlayer.isTeleporting()) // TODO: drop when we stop removing player from the world while teleporting. { @@ -170,6 +173,8 @@ public final class L2World _allObjects.remove(object.getObjectId()); if (object.isPlayer()) { + PlayerCountManager.getInstance().decConnectedCount(); + final L2PcInstance player = (L2PcInstance) object; if (player.isTeleporting()) // TODO: drop when we stop removing player from the world while teleportingq. { diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/Gui.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/Gui.java new file mode 100644 index 0000000000..0ea9ac46e0 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/Gui.java @@ -0,0 +1,358 @@ +/* + * 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.ui; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.gameserver.Shutdown; +import com.l2jmobius.gameserver.cache.HtmCache; +import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.BuyListData; +import com.l2jmobius.gameserver.data.xml.impl.MultisellData; +import com.l2jmobius.gameserver.util.Broadcast; +import com.l2jmobius.gameserver.util.Util; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmGameServer; + JTextArea txtrConsole; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + final static String[] abortOptions = + { + "Abort", + "Cancel" + }; + final static String[] confirmOptions = + { + "Confirm", + "Cancel" + }; + + public Gui() + { + frmGameServer = new JFrame(); + frmGameServer.setVisible(false); + frmGameServer.setTitle("Mobius - GameServer"); + frmGameServer.setResizable(false); + frmGameServer.setBounds(100, 100, 825, 618); + frmGameServer.getContentPane().setLayout(null); + frmGameServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmGameServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown server immediately?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + Shutdown.getInstance().startShutdown(null, 1, false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmGameServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmGameServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Shutdown delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, false); + } + } + } + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart GameServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + final Object answer = JOptionPane.showInputDialog(null, "Restart delay in seconds", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, "600"); + if (answer != null) + { + final String input = ((String) answer).trim(); + if (Util.isDigit(input)) + { + final int delay = Integer.valueOf(input); + if (delay > 0) + { + Shutdown.getInstance().startShutdown(null, delay, true); + } + } + } + } + }); + mnActions.add(mntmRestart); + + JMenuItem mntmAbort = new JMenuItem("Abort"); + mntmAbort.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbort.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Abort server shutdown?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, abortOptions, abortOptions[1]) == 0) + { + Shutdown.getInstance().abort(null); + } + }); + mnActions.add(mntmAbort); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmConfigs = new JMenuItem("Configs"); + mntmConfigs.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmConfigs.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload configs?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + Config.load(); + } + }); + mnReload.add(mntmConfigs); + + JMenuItem mntmAccess = new JMenuItem("Access"); + mntmAccess.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAccess.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload admin access levels?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + AdminData.getInstance().load(); + } + }); + mnReload.add(mntmAccess); + + JMenuItem mntmHtml = new JMenuItem("HTML"); + mntmHtml.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmHtml.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload HTML files?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + HtmCache.getInstance().reload(); + } + }); + mnReload.add(mntmHtml); + + JMenuItem mntmMultisells = new JMenuItem("Multisells"); + mntmMultisells.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmMultisells.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload multisells?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + MultisellData.getInstance().load(); + } + }); + mnReload.add(mntmMultisells); + + JMenuItem mntmBuylists = new JMenuItem("Buylists"); + mntmBuylists.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBuylists.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Reload buylists?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, confirmOptions, confirmOptions[1]) == 0) + { + BuyListData.getInstance().load(); + } + }); + mnReload.add(mntmBuylists); + + JMenu mnAnnounce = new JMenu("Announce"); + mnAnnounce.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnAnnounce); + + JMenuItem mntmNormal = new JMenuItem("Normal"); + mntmNormal.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmNormal.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, false); + } + } + }); + mnAnnounce.add(mntmNormal); + + JMenuItem mntmCritical = new JMenuItem("Critical"); + mntmCritical.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmCritical.addActionListener(arg0 -> + { + final Object input = JOptionPane.showInputDialog(null, "Critical announce message", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, ""); + if (input != null) + { + final String message = ((String) input).trim(); + if (!message.isEmpty()) + { + Broadcast.toAllOnlinePlayers(message, true); + } + } + }); + mnAnnounce.add(mntmCritical); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmGameServer.setIconImages(icons); + + // System Panel. + JPanel systemPanel = new SystemPanel(); + JLayeredPane layeredPanel = new JLayeredPane(); + frmGameServer.getContentPane().add(layeredPanel, BorderLayout.CENTER); + layeredPanel.setBounds(0, 0, 819, 566); + layeredPanel.add(scrollPanel, new Integer(0), 0); + layeredPanel.add(systemPanel, new Integer(1), 0); + + // Center frame to screen. + frmGameServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmGameServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/Locator.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/Locator.java new file mode 100644 index 0000000000..e891609b67 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/Locator.java @@ -0,0 +1,295 @@ +/* + * 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.ui; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Locale; + +final class Locator +{ + /** + * Constructor for Locator. + */ + private Locator() + { + } + + /** + * Method getClassSource. + * @param c Class + * @return File + */ + static File getClassSource(Class c) + { + String classResource = c.getName().replace('.', '/') + ".class"; + return getResourceSource(c.getClassLoader(), classResource); + } + + /** + * Method getResourceSource. + * @param c ClassLoader + * @param resource String + * @return File + */ + private static File getResourceSource(ClassLoader c, String resource) + { + if (c == null) + { + c = Locator.class.getClassLoader(); + } + + URL url = null; + + if (c == null) + { + url = ClassLoader.getSystemResource(resource); + } + else + { + url = c.getResource(resource); + } + + if (url != null) + { + String u = url.toString(); + + if (u.startsWith("jar:file:")) + { + int pling = u.indexOf("!"); + String jarName = u.substring(4, pling); + return new File(fromURI(jarName)); + } + else if (u.startsWith("file:")) + { + int tail = u.indexOf(resource); + String dirName = u.substring(0, tail); + return new File(fromURI(dirName)); + } + } + + return null; + } + + /** + * Method fromURI. + * @param uri String + * @return String + */ + private static String fromURI(String uri) + { + URL url = null; + + try + { + url = new URL(uri); + } + catch (MalformedURLException emYouEarlEx) + { + // empty catch clause + } + + if ((url == null) || !"file".equals(url.getProtocol())) + { + throw new IllegalArgumentException("Can only handle valid file: URIs"); + } + + StringBuilder buf = new StringBuilder(url.getHost()); + + if (buf.length() > 0) + { + buf.insert(0, File.separatorChar).insert(0, File.separatorChar); + } + + String file = url.getFile(); + int queryPos = file.indexOf('?'); + buf.append(queryPos < 0 ? file : file.substring(0, queryPos)); + uri = buf.toString().replace('/', File.separatorChar); + + if ((File.pathSeparatorChar == ';') && uri.startsWith("\\") && (uri.length() > 2) && Character.isLetter(uri.charAt(1)) && (uri.lastIndexOf(':') > -1)) + { + uri = uri.substring(1); + } + + String path = decodeUri(uri); + return path; + } + + /** + * Method decodeUri. + * @param uri String + * @return String + */ + private static String decodeUri(String uri) + { + if (uri.indexOf('%') == -1) + { + return uri; + } + + StringBuilder sb = new StringBuilder(); + CharacterIterator iter = new StringCharacterIterator(uri); + + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + { + if (c == '%') + { + char c1 = iter.next(); + + if (c1 != CharacterIterator.DONE) + { + int i1 = Character.digit(c1, 16); + char c2 = iter.next(); + + if (c2 != CharacterIterator.DONE) + { + int i2 = Character.digit(c2, 16); + sb.append((char) ((i1 << 4) + i2)); + } + } + } + else + { + sb.append(c); + } + } + + String path = sb.toString(); + return path; + } + + /** + * Method getToolsJar. + * @return File + */ + static File getToolsJar() + { + boolean toolsJarAvailable = false; + + try + { + Class.forName("com.sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e) + { + try + { + Class.forName("sun.tools.javac.Main"); + toolsJarAvailable = true; + } + catch (Exception e2) + { + // empty catch clause + } + } + + if (toolsJarAvailable) + { + return null; + } + + String javaHome = System.getProperty("java.home"); + + if (javaHome.toLowerCase(Locale.US).endsWith("jre")) + { + javaHome = javaHome.substring(0, javaHome.length() - 4); + } + + File toolsJar = new File(javaHome + "/lib/tools.jar"); + + if (!toolsJar.exists()) + { + System.out.println("Unable to locate tools.jar. " + "Expected to find it in " + toolsJar.getPath()); + return null; + } + + return toolsJar; + } + + /** + * Method getLocationURLs. + * @param location File + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + static URL[] getLocationURLs(File location) throws MalformedURLException + { + return getLocationURLs(location, new String[] + { + ".jar" + }); + } + + /** + * Method getLocationURLs. + * @param location File + * @param extensions String[] + * @return URL[] * @throws MalformedURLException + * @throws MalformedURLException + */ + private static URL[] getLocationURLs(File location, final String[] extensions) throws MalformedURLException + { + URL[] urls = new URL[0]; + + if (!location.exists()) + { + return urls; + } + + if (!location.isDirectory()) + { + urls = new URL[1]; + String path = location.getPath(); + + for (String extension : extensions) + { + if (path.toLowerCase().endsWith(extension)) + { + urls[0] = location.toURI().toURL(); + break; + } + } + + return urls; + } + + File[] matches = location.listFiles((FilenameFilter) (dir, name) -> + { + for (String extension : extensions) + { + if (name.toLowerCase().endsWith(extension)) + { + return true; + } + } + return false; + }); + urls = new URL[matches.length]; + + for (int i = 0; i < matches.length; ++i) + { + urls[i] = matches[i].toURI().toURL(); + } + + return urls; + } +} diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/SystemPanel.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/SystemPanel.java new file mode 100644 index 0000000000..68cabb3c12 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/SystemPanel.java @@ -0,0 +1,142 @@ +/* + * 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.ui; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.LineBorder; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.GameServer; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; + +/** + * @author Mobius + */ +public class SystemPanel extends JPanel +{ + final static long startTime = System.currentTimeMillis(); + + public SystemPanel() + { + setBackground(Color.WHITE); + setBounds(500, 20, 284, 140); + setBorder(new LineBorder(new Color(0, 0, 0), 1, false)); + setOpaque(true); + setLayout(null); + + JLabel lblProtocol = new JLabel("Protocol"); + lblProtocol.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblProtocol.setBounds(10, 5, 264, 17); + add(lblProtocol); + + JLabel lblConnected = new JLabel("Connected"); + lblConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblConnected.setBounds(10, 23, 264, 17); + add(lblConnected); + + JLabel lblMaxConnected = new JLabel("Max connected"); + lblMaxConnected.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblMaxConnected.setBounds(10, 41, 264, 17); + add(lblMaxConnected); + + JLabel lblOfflineShops = new JLabel("Offline trade"); + lblOfflineShops.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblOfflineShops.setBounds(10, 59, 264, 17); + add(lblOfflineShops); + + JLabel lblElapsedTime = new JLabel("Elapsed time"); + lblElapsedTime.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblElapsedTime.setBounds(10, 77, 264, 17); + add(lblElapsedTime); + + JLabel lblJavaVersion = new JLabel("Build JDK"); + lblJavaVersion.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblJavaVersion.setBounds(10, 95, 264, 17); + add(lblJavaVersion); + + JLabel lblBuildDate = new JLabel("Build date"); + lblBuildDate.setFont(new Font("Monospaced", Font.PLAIN, 16)); + lblBuildDate.setBounds(10, 113, 264, 17); + add(lblBuildDate); + + // Set initial values. + lblProtocol.setText("Protocol: 0"); + lblConnected.setText("Connected: 0"); + lblMaxConnected.setText("Max connected: 0"); + lblOfflineShops.setText("Offline trade: 0"); + lblElapsedTime.setText("Elapsed: 0 sec"); + lblJavaVersion.setText("Java version: " + System.getProperty("java.version")); + lblBuildDate.setText("Build date: Unavailable"); + try + { + File jarName = Locator.getClassSource(GameServer.class); + JarFile jarFile = new JarFile(jarName); + Attributes attrs = jarFile.getManifest().getMainAttributes(); + lblBuildDate.setText("Build date: " + attrs.getValue("Build-Date").split(" ")[0]); + jarFile.close(); + } + catch (Exception e) + { + } + + // Initial update task. + new Timer().schedule(new TimerTask() + { + @Override + public void run() + { + lblProtocol.setText((Config.PROTOCOL_LIST.size() > 1 ? "Protocols: " : "Protocol: ") + Config.PROTOCOL_LIST.toString()); + } + }, 4500); + + // Repeating elapsed time task. + new Timer().scheduleAtFixedRate(new TimerTask() + { + @Override + public void run() + { + lblConnected.setText("Connected: " + PlayerCountManager.getInstance().getConnectedCount()); + lblMaxConnected.setText("Max connected: " + PlayerCountManager.getInstance().getMaxConnectedCount()); + lblOfflineShops.setText("Offline trade: " + PlayerCountManager.getInstance().getOfflineTradeCount()); + lblElapsedTime.setText("Elapsed: " + getDurationBreakdown(System.currentTimeMillis() - startTime)); + } + }, 1000, 1000); + } + + static String getDurationBreakdown(long millis) + { + long days = TimeUnit.MILLISECONDS.toDays(millis); + millis -= TimeUnit.DAYS.toMillis(days); + long hours = TimeUnit.MILLISECONDS.toHours(millis); + millis -= TimeUnit.HOURS.toMillis(hours); + long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); + millis -= TimeUnit.MINUTES.toMillis(minutes); + long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); + + return (days + "d " + hours + "h " + minutes + "m " + seconds + "s"); + } +} diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/frmAbout.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/frmAbout.java new file mode 100644 index 0000000000..e8a4f9a47c --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/ui/frmAbout.java @@ -0,0 +1,143 @@ +/* + * 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.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +import com.l2jmobius.Config; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblSupports = new JLabel("Server Protocol"); + lblSupports.setHorizontalAlignment(SwingConstants.CENTER); + lblSupports.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblSupports.setBounds(10, 78, 271, 23); + frmAbout.getContentPane().add(lblSupports); + + JLabel lblProtocols = new JLabel("Protocol Number"); + lblProtocols.setHorizontalAlignment(SwingConstants.CENTER); + lblProtocols.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblProtocols.setBounds(10, 92, 271, 23); + frmAbout.getContentPane().add(lblProtocols); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Generate protocols text. + String protocols = ""; + if (Config.PROTOCOL_LIST.size() > 1) + { + for (Integer number : Config.PROTOCOL_LIST) + { + if (!protocols.isEmpty()) + { + protocols += " - "; + } + protocols += number; + } + lblSupports.setText("Server Protocols"); + } + else + { + protocols += Config.PROTOCOL_LIST.get(0); + } + lblProtocols.setText(protocols); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +} diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java index ecc40e644b..056fa7ea38 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/util/OfflineTradeUtil.java @@ -20,6 +20,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable; +import com.l2jmobius.gameserver.instancemanager.PlayerCountManager; import com.l2jmobius.gameserver.model.actor.L2Summon; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.olympiad.OlympiadManager; @@ -100,6 +101,8 @@ public final class OfflineTradeUtil return false; } + PlayerCountManager.getInstance().incOfflineTradeCount(); + final L2GameClient client = player.getClient(); client.setDetached(true); diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/GameServerTable.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/GameServerTable.java index 362aa93ad5..73110fb6dc 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/GameServerTable.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/GameServerTable.java @@ -409,7 +409,18 @@ public final class GameServerTable implements IGameXmlReader */ public void setStatus(int status) { - _status = status; + if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) + { + _status = ServerStatus.STATUS_DOWN; + } + else if (LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) + { + _status = ServerStatus.STATUS_GM_ONLY; + } + else + { + _status = status; + } } /** diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/LoginServer.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/LoginServer.java index 6c2062e622..39377afee3 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/LoginServer.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/LoginServer.java @@ -16,6 +16,7 @@ */ package com.l2jmobius.loginserver; +import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -32,35 +33,43 @@ import com.l2jmobius.Config; import com.l2jmobius.Server; import com.l2jmobius.commons.database.DatabaseBackup; import com.l2jmobius.commons.database.DatabaseFactory; +import com.l2jmobius.gameserver.network.loginserverpackets.game.ServerStatus; import com.l2jmobius.loginserver.network.ClientNetworkManager; +import com.l2jmobius.loginserver.ui.Gui; /** * @author KenM */ public final class LoginServer { - private final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); + public final Logger LOGGER = Logger.getLogger(LoginServer.class.getName()); public static final int PROTOCOL_REV = 0x0106; - private static LoginServer _instance; + private static LoginServer INSTANCE; private GameServerListener _gameServerListener; private Thread _restartLoginServer; + private static int _loginStatus = ServerStatus.STATUS_NORMAL; public static void main(String[] args) throws Exception { - new LoginServer(); + INSTANCE = new LoginServer(); } public static LoginServer getInstance() { - return _instance; + return INSTANCE; } private LoginServer() throws Exception { - _instance = this; Server.serverMode = Server.MODE_LOGINSERVER; + // GUI + if (!GraphicsEnvironment.isHeadless()) + { + new Gui(); + } + // Create log folder final File logFolder = new File(".", "log"); logFolder.mkdir(); @@ -96,6 +105,14 @@ public final class LoginServer loadBanFile(); + if (Config.LOGIN_SERVER_SCHEDULE_RESTART) + { + LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); + _restartLoginServer = new LoginServerRestart(); + _restartLoginServer.setDaemon(true); + _restartLoginServer.start(); + } + try { _gameServerListener = new GameServerListener(); @@ -116,7 +133,7 @@ public final class LoginServer return _gameServerListener; } - private void loadBanFile() + public void loadBanFile() { final File bannedFile = new File("./banned_ip.cfg"); if (bannedFile.exists() && bannedFile.isFile()) @@ -170,14 +187,6 @@ public final class LoginServer { LOGGER.warning("IP Bans file (" + bannedFile.getName() + ") is missing or is a directory, skipped."); } - - if (Config.LOGIN_SERVER_SCHEDULE_RESTART) - { - LOGGER.info("Scheduled LS restart after " + Config.LOGIN_SERVER_SCHEDULE_RESTART_TIME + " hours"); - _restartLoginServer = new LoginServerRestart(); - _restartLoginServer.setDaemon(true); - _restartLoginServer.start(); - } } class LoginServerRestart extends Thread @@ -213,4 +222,14 @@ public final class LoginServer } Runtime.getRuntime().exit(restart ? 2 : 0); } + + public int getStatus() + { + return _loginStatus; + } + + public void setStatus(int status) + { + _loginStatus = status; + } } diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java index 670365b761..fa5c1e0a3a 100644 --- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/network/clientpackets/RequestServerLogin.java @@ -20,8 +20,10 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.IIncomingPacket; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; import com.l2jmobius.loginserver.SessionKey; import com.l2jmobius.loginserver.network.L2LoginClient; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; import com.l2jmobius.loginserver.network.serverpackets.LoginFail.LoginFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayFail.PlayFailReason; import com.l2jmobius.loginserver.network.serverpackets.PlayOk; @@ -61,7 +63,11 @@ public class RequestServerLogin implements IIncomingPacket // if we didnt showed the license we cant check these values if (!Config.SHOW_LICENCE || sk.checkLoginPair(_skey1, _skey2)) { - if (LoginController.getInstance().isLoginPossible(client, _serverId)) + if ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_DOWN) || ((LoginServer.getInstance().getStatus() == ServerStatus.STATUS_GM_ONLY) && (client.getAccessLevel() < 1))) + { + client.close(LoginFailReason.REASON_ACCESS_FAILED); + } + else if (LoginController.getInstance().isLoginPossible(client, _serverId)) { client.setJoinedGS(true); client.sendPacket(new PlayOk(sk)); diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/ui/Gui.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/ui/Gui.java new file mode 100644 index 0000000000..7dfddb4985 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/ui/Gui.java @@ -0,0 +1,275 @@ +/* + * 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.loginserver.ui; + +import java.awt.Font; +import java.awt.Image; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DropMode; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +import com.l2jmobius.commons.util.LimitLinesDocumentListener; +import com.l2jmobius.commons.util.SplashScreen; +import com.l2jmobius.loginserver.GameServerTable; +import com.l2jmobius.loginserver.GameServerTable.GameServerInfo; +import com.l2jmobius.loginserver.LoginController; +import com.l2jmobius.loginserver.LoginServer; +import com.l2jmobius.loginserver.network.gameserverpackets.ServerStatus; + +/** + * @author Mobius + */ +public class Gui +{ + JFrame frmLoginServer; + JTextArea txtrConsole; + + JCheckBoxMenuItem chckbxmntmEnabled; + JCheckBoxMenuItem chckbxmntmDisabled; + JCheckBoxMenuItem chckbxmntmGmOnly; + + final static String[] shutdownOptions = + { + "Shutdown", + "Cancel" + }; + final static String[] restartOptions = + { + "Restart", + "Cancel" + }; + + public Gui() + { + frmLoginServer = new JFrame(); + frmLoginServer.setVisible(false); + frmLoginServer.setTitle("Mobius - LoginServer"); + frmLoginServer.setResizable(false); + frmLoginServer.setBounds(100, 100, 825, 618); + frmLoginServer.getContentPane().setLayout(null); + frmLoginServer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frmLoginServer.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent ev) + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + } + }); + + JScrollPane scrollPanel = new JScrollPane(); + scrollPanel.setBounds(10, 11, 799, 544); + frmLoginServer.getContentPane().add(scrollPanel); + + txtrConsole = new JTextArea(); + txtrConsole.setWrapStyleWord(true); + txtrConsole.setEditable(false); + txtrConsole.setFont(new Font("Monospaced", Font.PLAIN, 16)); + scrollPanel.setViewportView(txtrConsole); + txtrConsole.setDropMode(DropMode.INSERT); + txtrConsole.setLineWrap(true); + txtrConsole.setEditable(false); + + JMenuBar menuBar = new JMenuBar(); + menuBar.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + frmLoginServer.setJMenuBar(menuBar); + + JMenu mnActions = new JMenu("Actions"); + mnActions.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnActions); + + JMenuItem mntmShutdown = new JMenuItem("Shutdown"); + mntmShutdown.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmShutdown.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Shutdown LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, shutdownOptions, shutdownOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(false); + } + }); + mnActions.add(mntmShutdown); + + JMenuItem mntmRestart = new JMenuItem("Restart"); + mntmRestart.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmRestart.addActionListener(arg0 -> + { + if (JOptionPane.showOptionDialog(null, "Restart LoginServer?", "Select an option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, restartOptions, restartOptions[1]) == 0) + { + LoginServer.getInstance().shutdown(true); + } + }); + mnActions.add(mntmRestart); + + JMenu mnReload = new JMenu("Reload"); + mnReload.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnReload); + + JMenuItem mntmBannedIps = new JMenuItem("Banned IPs"); + mntmBannedIps.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmBannedIps.addActionListener(arg0 -> + { + LoginController.getInstance().getBannedIps().clear(); + LoginServer.getInstance().loadBanFile(); + }); + mnReload.add(mntmBannedIps); + + JMenu mnStatus = new JMenu("Status"); + mnStatus.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnStatus); + + chckbxmntmEnabled = new JCheckBoxMenuItem("Enabled"); + chckbxmntmEnabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmEnabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(true); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_NORMAL); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_NORMAL); + } + LoginServer.getInstance().LOGGER.info("Status changed to enabled."); + }); + chckbxmntmEnabled.setSelected(true); + mnStatus.add(chckbxmntmEnabled); + + chckbxmntmDisabled = new JCheckBoxMenuItem("Disabled"); + chckbxmntmDisabled.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmDisabled.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(true); + chckbxmntmGmOnly.setSelected(false); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_DOWN); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_DOWN); + } + LoginServer.getInstance().LOGGER.info("Status changed to disabled."); + }); + mnStatus.add(chckbxmntmDisabled); + + chckbxmntmGmOnly = new JCheckBoxMenuItem("GM only"); + chckbxmntmGmOnly.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + chckbxmntmGmOnly.addActionListener(arg0 -> + { + chckbxmntmEnabled.setSelected(false); + chckbxmntmDisabled.setSelected(false); + chckbxmntmGmOnly.setSelected(true); + LoginServer.getInstance().setStatus(ServerStatus.STATUS_GM_ONLY); + for (GameServerInfo gsi : GameServerTable.getInstance().getRegisteredGameServers().values()) + { + gsi.setStatus(ServerStatus.STATUS_GM_ONLY); + } + LoginServer.getInstance().LOGGER.info("Status changed to GM only."); + }); + mnStatus.add(chckbxmntmGmOnly); + + // Align menu items bar to right after this. + // menuBar.add(Box.createHorizontalGlue()); + + JMenu mnHelp = new JMenu("Help"); + mnHelp.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + menuBar.add(mnHelp); + + JMenuItem mntmAbout = new JMenuItem("About"); + mntmAbout.setFont(new Font("Segoe UI", Font.PLAIN, 13)); + mntmAbout.addActionListener(arg0 -> + { + new frmAbout(); + }); + mnHelp.add(mntmAbout); + + // Set icons. + List icons = new ArrayList<>(); + icons.add(new ImageIcon("..\\images\\l2jmobius_16x16.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_32x32.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_64x64.png").getImage()); + icons.add(new ImageIcon("..\\images\\l2jmobius_128x128.png").getImage()); + frmLoginServer.setIconImages(icons); + + // Center frame to screen. + frmLoginServer.setLocationRelativeTo(null); + + // Limit console lines to 500. + txtrConsole.getDocument().addDocumentListener(new LimitLinesDocumentListener(500)); + + // Redirect output to text area. + redirectSystemStreams(); + + // Show SplashScreen. + new SplashScreen("..\\images\\splash.png", 5000, frmLoginServer); + } + + // Set where the text is redirected. In this case, txtrConsole. + void updateTextArea(String text) + { + SwingUtilities.invokeLater(() -> + { + txtrConsole.append(text); + txtrConsole.setCaretPosition(txtrConsole.getText().length()); + }); + } + + // Method that manages the redirect. + private void redirectSystemStreams() + { + OutputStream out = new OutputStream() + { + @Override + public void write(int b) + { + updateTextArea(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) + { + updateTextArea(new String(b, off, len)); + } + + @Override + public void write(byte[] b) + { + write(b, 0, b.length); + } + }; + + System.setOut(new PrintStream(out, true)); + System.setErr(new PrintStream(out, true)); + } +} diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/ui/frmAbout.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/ui/frmAbout.java new file mode 100644 index 0000000000..b535d860b6 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/loginserver/ui/frmAbout.java @@ -0,0 +1,115 @@ +/* + * 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.loginserver.ui; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Window.Type; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +/** + * @author Mobius + */ +public class frmAbout +{ + private JFrame frmAbout; + final static String URL = "www.l2jmobius.com"; + URI uri; + + public frmAbout() + { + initialize(); + uri = createURI(URL); + frmAbout.setVisible(true); + } + + private void initialize() + { + frmAbout = new JFrame(); + frmAbout.setResizable(false); + frmAbout.setTitle("About"); + frmAbout.setBounds(100, 100, 297, 197); + frmAbout.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frmAbout.setType(Type.UTILITY); + frmAbout.getContentPane().setLayout(null); + + JLabel lblLjmobius = new JLabel("L2jMobius"); + lblLjmobius.setFont(new Font("Tahoma", Font.PLAIN, 32)); + lblLjmobius.setHorizontalAlignment(SwingConstants.CENTER); + lblLjmobius.setBounds(10, 11, 271, 39); + frmAbout.getContentPane().add(lblLjmobius); + + JLabel lblData = new JLabel("2013-" + Calendar.getInstance().get(Calendar.YEAR)); + lblData.setHorizontalAlignment(SwingConstants.CENTER); + lblData.setBounds(10, 44, 271, 14); + frmAbout.getContentPane().add(lblData); + + JLabel lblLoginServer = new JLabel("Login Server"); + lblLoginServer.setHorizontalAlignment(SwingConstants.CENTER); + lblLoginServer.setFont(new Font("Tahoma", Font.PLAIN, 14)); + lblLoginServer.setBounds(10, 86, 271, 23); + frmAbout.getContentPane().add(lblLoginServer); + + JLabel site = new JLabel(URL); + site.setText("" + URL + ""); + site.setHorizontalAlignment(SwingConstants.CENTER); + site.setBounds(76, 148, 140, 14); + site.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent arg0) + { + if (Desktop.isDesktopSupported()) + { + try + { + Desktop.getDesktop().browse(uri); + } + catch (IOException e) + { + } + } + } + }); + frmAbout.getContentPane().add(site); + + // Center frame to screen. + frmAbout.setLocationRelativeTo(null); + } + + public static URI createURI(String str) + { + try + { + return new URI(str); + } + catch (URISyntaxException x) + { + throw new IllegalArgumentException(x.getMessage(), x); + } + } +}