Просмотр исходного кода

Introducing graphical user interface packages for gameserver registration and server settings configuration. I'll commit internationalization files to the datapack and maybe write some post with explanations about it. Please test and report as usual. Big thanks KenM.

DrLecter 16 лет назад
Родитель
Сommit
46234f1a63
25 измененных файлов с 2930 добавлено и 116 удалено
  1. 23 3
      L2_GameServer/build.xml
  2. BIN
      L2_GameServer/dist/GSRegister.exe
  3. BIN
      L2_GameServer/dist/L2JConfig.exe
  4. 2 0
      L2_GameServer/dist/L2JConfig.sh
  5. 3 2
      L2_GameServer/dist/RegisterGameServer.bat
  6. BIN
      L2_GameServer/images/add.png
  7. BIN
      L2_GameServer/images/cross.png
  8. BIN
      L2_GameServer/images/disk.png
  9. BIN
      L2_GameServer/images/help.png
  10. BIN
      L2_GameServer/images/l2jserverlogo.png
  11. 760 0
      L2_GameServer/java/net/sf/l2j/configurator/ConfigUserInterface.java
  12. 329 0
      L2_GameServer/java/net/sf/l2j/configurator/JIPTextField.java
  13. 641 0
      L2_GameServer/java/net/sf/l2j/gsregistering/BaseGameServerRegister.java
  14. 432 0
      L2_GameServer/java/net/sf/l2j/gsregistering/GUserInterface.java
  15. 288 94
      L2_GameServer/java/net/sf/l2j/gsregistering/GameServerRegister.java
  16. 201 0
      L2_GameServer/java/net/sf/l2j/gsregistering/RegisterDialog.java
  17. 74 0
      L2_GameServer/java/net/sf/l2j/i18n/LanguageControl.java
  18. 48 0
      L2_GameServer/java/net/sf/l2j/images/ImagesTable.java
  19. 4 1
      L2_GameServer/java/net/sf/l2j/loginserver/GameServerTable.java
  20. 2 2
      L2_GameServer/java/net/sf/l2j/loginserver/GameServerThread.java
  21. 1 1
      L2_GameServer/java/net/sf/l2j/loginserver/L2LoginClient.java
  22. 18 13
      L2_GameServer/java/net/sf/l2j/loginserver/L2LoginServer.java
  23. 1 0
      L2_GameServer/java/net/sf/l2j/loginserver/crypt/BlowfishEngine.java
  24. 23 0
      L2_GameServer/languages/configurator/Configurator.properties
  25. 80 0
      L2_GameServer/languages/gsregister/GSRegister.properties

+ 23 - 3
L2_GameServer/build.xml

@@ -30,7 +30,9 @@
 	<property name="build.dist.login" location="${build.dist}/login"/>
 	<property name="build.dist.game" location="${build.dist}/gameserver"/>
     <property name="build.dist.libs" location="${build.dist}/libs"/>
-    
+	<property name="build.dist.languages" location="${build.dist}/languages"/>
+	<property name="build.dist.images" location="${build.dist}/images"/>
+	
     <path id="classpath">
         <fileset dir="${lib}">
             <include name="c3p0-0.9.1.2.jar"/>
@@ -122,8 +124,21 @@
 			</fileset>
 		</copy>
     	
+    	<copy todir="${build.dist.languages}">
+    	     <fileset dir="${src}/../languages">
+    	         <include name="**/*"/>
+    	     </fileset>
+    	</copy>
+    	
+        <copy todir="${build.dist.images}">
+             <fileset dir="${src}/../images">
+                 <include name="**/*"/>
+             </fileset>
+        </copy>
+    	
         <copy todir="${build.dist}">
             <fileset dir="${basedir}">
+                <include name="changes.txt"/>
                 <include name="LICENSE.txt"/>
                 <include name="README.txt"/>
             </fileset>
@@ -142,12 +157,18 @@
                 <include name="LoginServer_loop.sh"/>
                 <include name="startLoginServer.*"/>
             	<include name="RegisterGameServer.*"/>
+            	<include name="GSRegister.exe"/>
+                <include name="L2JConfig.exe"/>
+            	<include name="L2JConfig.sh"/>
             </fileset>
         </copy>
     	<copy todir="${build.dist.game}">
             <fileset dir="dist">
                 <include name="GameServer_loop.sh"/>
                 <include name="startGameServer.*"/>
+                <include name="L2JConfig.exe"/>
+            	 <include name="L2JConfig.sh"/>
+            	<include name="hibernate.cfg.xml"/>
             </fileset>
         </copy>
     	
@@ -254,7 +275,6 @@
 
     <target name="clean"
             description="Remove the output directories">
-
         <delete dir="${build}"/>
     </target>
-</project>
+</project>

BIN
L2_GameServer/dist/GSRegister.exe


BIN
L2_GameServer/dist/L2JConfig.exe


+ 2 - 0
L2_GameServer/dist/L2JConfig.sh

@@ -0,0 +1,2 @@
+#!/bin/sh
+java -Djava.util.logging.config.file=console.cfg -cp ./../libs/*:l2jserver.jar net.sf.l2j.configurator.ConfigUserInterface

+ 3 - 2
L2_GameServer/dist/RegisterGameServer.bat

@@ -1,2 +1,3 @@
-@java -Djava.util.logging.config.file=console.cfg -cp ./../libs/*;l2jserver.jar net.sf.l2j.gsregistering.GameServerRegister
-@pause
+@echo off
+javaw -Djava.util.logging.config.file=console.cfg -cp ./../libs/*;l2jserver.jar net.sf.l2j.gsregistering.BaseGameServerRegister
+exit

BIN
L2_GameServer/images/add.png


BIN
L2_GameServer/images/cross.png


BIN
L2_GameServer/images/disk.png


BIN
L2_GameServer/images/help.png


BIN
L2_GameServer/images/l2jserverlogo.png


+ 760 - 0
L2_GameServer/java/net/sf/l2j/configurator/ConfigUserInterface.java

@@ -0,0 +1,760 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.sf.l2j.configurator;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+import java.util.ResourceBundle;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+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.JTabbedPane;
+import javax.swing.JTextField;
+import javax.swing.JToolBar;
+import javax.swing.SwingUtilities;
+import javax.swing.ToolTipManager;
+import javax.swing.UIManager;
+
+import javolution.util.FastList;
+import net.sf.l2j.configurator.ConfigUserInterface.ConfigFile.ConfigComment;
+import net.sf.l2j.configurator.ConfigUserInterface.ConfigFile.ConfigProperty;
+import net.sf.l2j.i18n.LanguageControl;
+import net.sf.l2j.images.ImagesTable;
+
+/**
+ *
+ * @author  KenM
+ */
+public class ConfigUserInterface extends JFrame implements ActionListener
+{
+	
+	/**
+     * Comment for <code>serialVersionUID</code>
+     */
+    private static final long serialVersionUID = 1L;
+    
+    private JTabbedPane _tabPane = new JTabbedPane();
+    
+    private List<ConfigFile> _configs = new FastList<ConfigFile>();
+    
+    private ResourceBundle _bundle;
+
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args)
+	{
+		Locale locale = null;
+		
+		
+		try
+        {
+	        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+        }
+        catch (Exception e)
+        {
+        	// couldn't care less
+        }
+		if (locale == null)
+			{
+				locale = Locale.getDefault();
+			}
+		final ResourceBundle bundle = ResourceBundle.getBundle("configurator.Configurator", locale, LanguageControl.INSTANCE);
+
+        SwingUtilities.invokeLater
+        (
+        		new Runnable()
+        		{
+					@Override
+                    public void run()
+                    {
+						ConfigUserInterface cui = new ConfigUserInterface(bundle);
+						cui.setVisible(true);
+                    }
+        		}
+        );
+	}
+	
+	public ConfigUserInterface(ResourceBundle bundle)
+	{
+		setBundle(bundle);
+		this.setTitle(bundle.getString("toolName"));
+		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+		this.setSize(750, 500);
+		this.setLayout(new GridBagLayout());
+		
+		GridBagConstraints cons = new GridBagConstraints();
+		cons.fill = GridBagConstraints.HORIZONTAL;
+		cons.gridx = 0;
+		cons.gridy = 0;
+		cons.weighty = 0;
+		cons.weightx = 1;
+		
+		JMenuBar menubar = new JMenuBar();
+		
+		JMenu fileMenu = new JMenu(bundle.getString("fileMenu"));
+		JMenu helpMenu = new JMenu(bundle.getString("helpMenu"));
+		
+		JMenuItem exitItem = new JMenuItem(bundle.getString("exitItem"));
+		exitItem.setActionCommand("exit");
+		exitItem.addActionListener(this);
+		fileMenu.add(exitItem);
+		
+		JMenuItem aboutItem = new JMenuItem(bundle.getString("aboutItem"));
+		aboutItem.setActionCommand("about");
+		aboutItem.addActionListener(this);
+		helpMenu.add(aboutItem);
+		
+		menubar.add(fileMenu);
+		menubar.add(helpMenu);
+		
+		this.setJMenuBar(menubar);
+		
+		JToolBar toolBar = new JToolBar();
+		toolBar.setFloatable(false);
+		toolBar.setRollover(true);
+		toolBar.add(this.createToolButton("disk.png", bundle.getString("save"), "save"));
+		this.add(toolBar, cons);
+		
+		cons.gridy++;
+		cons.fill = GridBagConstraints.BOTH;
+		cons.weighty = 1;
+		this.loadConfigs();
+		this.buildInterface();
+		this.add(_tabPane, cons);
+	}
+	
+	private JButton createToolButton(String image, String text, String action)
+	{
+		JButton button = new JButton(text, ImagesTable.getImage(image));
+		button.setActionCommand(action);
+		button.addActionListener(this);
+		return button;
+	}
+	
+	/**
+     * 
+     */
+    private void buildInterface()
+    {
+    	ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE);
+		ToolTipManager.sharedInstance().setInitialDelay(0);
+		ToolTipManager.sharedInstance().setReshowDelay(0);
+		
+    	GridBagConstraints cons = new GridBagConstraints();
+    	cons.fill = GridBagConstraints.NONE;
+    	cons.anchor = GridBagConstraints.FIRST_LINE_START;
+    	cons.insets = new Insets(2, 2, 2, 2);
+	    for (ConfigFile cf : getConfigs())
+	    {
+	    	JPanel panel = new JPanel();
+	    	panel.setLayout(new GridBagLayout());
+	    	
+	    	cons.gridy = 0;
+	    	cons.weighty = 0;
+	    	for (ConfigComment cc : cf.getConfigProperties())
+	    	{
+	    		if (!(cc instanceof ConfigProperty))
+	    		{
+	    			continue;
+	    		}
+	    		
+	    		ConfigProperty cp = (ConfigProperty) cc;
+	    		cons.gridx = 0;
+	    		
+	    		JLabel keyLabel = new JLabel(cp.getDisplayName()+':', ImagesTable.getImage("help.png"), JLabel.LEFT);
+	    		String comments = "<b>"+cp.getName()+":</b><br>"+cp.getComments();
+	    		comments = comments.replace("\r\n", "<br>");
+	    		comments = "<html>"+comments+"</html>";
+	    		keyLabel.setToolTipText(comments);
+	    		cons.weightx = 0;
+	    		panel.add(keyLabel, cons);
+	    		cons.gridx++;
+	    		
+	    		JComponent valueComponent = cp.getValueComponent();
+	    		cons.weightx = 1;
+	    		panel.add(valueComponent, cons);
+	    		cons.gridx++;
+	    		cons.gridy++;
+	    	}
+	    	cons.gridy++;
+	    	cons.weighty = 1;
+		    panel.add(new JLabel(), cons); // filler
+		    _tabPane.addTab(cf.getName(), new JScrollPane(panel));
+	    }
+    }
+
+	/**
+     * 
+     */
+    private void loadConfigs()
+    {
+    	File configsDir = new File("config");
+	    for (File file : configsDir.listFiles())
+	    {
+	    	if (file.getName().endsWith(".properties") && file.isFile() && file.canWrite())
+	    	{
+	    		try
+                {
+	                this.parsePropertiesFile(file);
+                }
+                catch (IOException e)
+                {
+                	JOptionPane.showMessageDialog(ConfigUserInterface.this,getBundle().getString("errorReading")+file.getName(),getBundle().getString("error"),JOptionPane.ERROR_MESSAGE);
+                	System.exit(3);
+	                // e.printStackTrace();
+                }
+	    	}
+	    }
+    }
+
+	/**
+     * @param file
+	 * @throws IOException 
+     */
+    private void parsePropertiesFile(File file) throws IOException
+    {
+	    LineNumberReader lnr = new LineNumberReader(new InputStreamReader(new FileInputStream(file)));
+	    
+	    String line;
+	    StringBuilder commentBuffer = new StringBuilder();
+	    ConfigFile cf = new ConfigFile(file);
+	    while ((line = lnr.readLine()) != null)
+	    {
+	    	line = line.trim();
+	    	
+	    	if (line.startsWith("#"))
+	    	{
+	    		if (commentBuffer.length() > 0)
+	    		{
+		    		commentBuffer.append("\r\n");
+	    		}
+	    		commentBuffer.append(line.substring(1));
+	    	}
+	    	else if (line.length() == 0)
+	    	{
+	    		// blank line, reset comments
+	    		if (commentBuffer.length() > 0)
+	    		{
+	    			cf.addConfigComment(commentBuffer.toString());
+	    		}
+	    		commentBuffer.setLength(0);
+	    	}
+	    	else if (line.indexOf('=') >= 0)
+	    	{
+	    		String[] kv = line.split("=");
+	    		String key = kv[0].trim();
+	    		String value = "";
+	    		if (kv.length > 1)
+	    		{
+	    			value = kv[1].trim();
+	    		}
+	    		
+	    		String comments = commentBuffer.toString();
+	    		commentBuffer.setLength(0); //reset
+	    		
+	    		cf.addConfigProperty(key, parseValue(value), comments);
+	    	}
+	    }
+    	getConfigs().add(cf);
+    }
+
+    /**
+     * @param value
+     */
+    private Object parseValue(String value)
+    {
+	    if (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("true"))
+	    {
+	    	return Boolean.parseBoolean(value);
+	    }
+	    
+	    /*try
+	    {
+	    	double parseDouble = Double.parseDouble(value);
+	    	return parseDouble;
+	    }
+	    catch (NumberFormatException e)
+	    {
+	    	// not a double, ignore
+	    }*/
+	    
+	    // localhost -> 127.0.0.1
+	    if (value.equals("localhost"))
+	    {
+	    	value = "127.0.0.1";
+	    }
+	    
+	    String[] parts = value.split("\\.");
+	    if (parts.length == 4)
+	    {
+	    	boolean ok = true;
+	    	for (int i = 0; i < 4 && ok; i++)
+	    	{
+	    		try
+	    		{
+	    			int parseInt = Integer.parseInt(parts[i]);
+	    			if (parseInt < 0 || parseInt > 255)
+	    			{
+	    				ok = false;
+	    			}
+	    		}
+	    		catch (NumberFormatException e)
+	    		{
+	    			ok = false;
+	    		}
+	    	}
+	    	
+	    	if (ok)
+	    	{
+	    		try
+		    	{
+		    		InetAddress address = InetAddress.getByName(value);
+		    		return address;
+		    	}
+		    	catch (UnknownHostException e)
+		    	{
+		    		// ignore
+		    	}
+	    	}
+	    }
+	    
+	    return value;
+    }
+
+	static class ConfigFile
+    {
+    	private File _file;
+    	private String _name;
+    	private final List<ConfigComment> _configs = new FastList<ConfigComment>();
+    	
+    	
+    	public ConfigFile(File file)
+    	{
+    		_file = file;
+    		int lastIndex = file.getName().lastIndexOf('.');
+    		setName(file.getName().substring(0, lastIndex));
+    	}
+    	
+    	public void addConfigProperty(String name, Object value, ValueType type, String comments)
+    	{
+    		_configs.add(new ConfigProperty(name, value, type, comments));
+    	}
+    	
+    	public void addConfigComment(String comment)
+    	{
+    		_configs.add(new ConfigComment(comment));
+    	}
+    	
+    	public void addConfigProperty(String name, Object value, String comments)
+    	{
+    		this.addConfigProperty(name, value, ValueType.firstTypeMatch(value), comments);
+    	}
+    	
+    	public List<ConfigComment> getConfigProperties()
+    	{
+    		return _configs;
+    	}
+    	
+    	/**
+         * @param name The name to set.
+         */
+        public void setName(String name)
+        {
+	        _name = name;
+        }
+
+		/**
+         * @return Returns the name.
+         */
+        public String getName()
+        {
+	        return _name;
+        }
+        
+        public void save() throws IOException
+        {
+        	BufferedWriter bufWriter = null;
+        	try
+        	{
+        		bufWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(_file)));
+        		for (ConfigComment cc : _configs)
+        		{
+        			cc.save(bufWriter);
+        		}
+        	}
+        	finally
+        	{
+        		if (bufWriter != null)
+        		{
+        			bufWriter.close();
+        		}
+        	}
+        }
+
+        class ConfigComment
+    	{
+
+    		private String _comments;
+
+			/**
+             * @param comments
+             */
+            public ConfigComment(String comments)
+            {
+	            _comments = comments;
+            }
+    		
+
+			/**
+             * @return Returns the comments.
+             */
+            public String getComments()
+            {
+            	return _comments;
+            }
+            
+			/**
+             * @param comments The comments to set.
+             */
+            public void setComments(String comments)
+            {
+            	_comments = comments;
+            }
+            
+            public void save(Writer writer) throws IOException
+            {
+            	StringBuilder sb = new StringBuilder();
+            	sb.append('#');
+        		sb.append(this.getComments().replace("\r\n", "\r\n#"));
+        		sb.append("\r\n\r\n");
+        		writer.write(sb.toString());
+            }
+    	}
+        
+		class ConfigProperty extends ConfigComment
+    	{
+    		private String _propname;
+    		private Object _value;
+    		private ValueType _type;
+			private JComponent _component;
+    		
+			/**
+             * @param name
+			 * @param value
+			 * @param type
+			 * @param comments
+             */
+            public ConfigProperty(String name, Object value, ValueType type, String comments)
+            {
+            	super(comments);
+            	if (!type.getType().isAssignableFrom(value.getClass()))
+            	{
+            		throw new IllegalArgumentException("Value Instance Type doesn't match the type argument.");
+            	}
+	            _propname = name;
+	            _type = type;
+	            _value = value;
+            }
+            
+			/**
+             * @return Returns the name.
+             */
+            public String getName()
+            {
+            	return _propname;
+            }
+            
+			/**
+             * @return Returns the name.
+             */
+            public String getDisplayName()
+            {
+            	return unCamelize(_propname);
+            }
+            
+			/**
+             * @param name The name to set.
+             */
+            public void setName(String name)
+            {
+            	_propname = name;
+            }
+            
+			/**
+             * @return Returns the value.
+             */
+            public Object getValue()
+            {
+            	return _value;
+            }
+            
+			/**
+             * @param value The value to set.
+             */
+            public void setValue(String value)
+            {
+            	_value = value;
+            }
+            
+			/**
+             * @return Returns the type.
+             */
+            public ValueType getType()
+            {
+            	return _type;
+            }
+            
+			/**
+             * @param type The type to set.
+             */
+            public void setType(ValueType type)
+            {
+            	_type = type;
+            }
+            
+            public JComponent getValueComponent()
+            {
+            	if (_component == null)
+            	{
+            		_component = createValueComponent();
+            	}
+            	return _component;
+            }
+            
+            public JComponent createValueComponent()
+            {
+            	switch (this.getType())
+            	{
+            		case BOOLEAN:
+            			boolean bool = (Boolean) this.getValue();
+            			JCheckBox checkBox = new JCheckBox();
+            			checkBox.setSelected(bool);
+            			return checkBox;
+            		case IPv4:
+            			return new JIPTextField((Inet4Address) this.getValue());
+            		case DOUBLE:
+            		case INTEGER:
+            		case STRING:
+            		default:
+            			String val = this.getValue().toString();
+            			JTextField textField = new JTextField(val);
+            			textField.setColumns(Math.max(val.length(), 20));
+            			return textField;
+            	}
+            }
+            
+            public void save(Writer writer) throws IOException
+            {
+            	String value;
+            	if (this.getValueComponent() instanceof JCheckBox)
+            	{
+            		value = ((JCheckBox) this.getValueComponent()).isSelected()+"";
+            	}
+            	else if (this.getValueComponent() instanceof JIPTextField)
+            	{
+            		value = ((JIPTextField) this.getValueComponent()).getText();
+            	}
+            	else if (this.getValueComponent() instanceof JTextField)
+            	{
+            		value = ((JTextField) this.getValueComponent()).getText();
+            	}
+            	else
+            	{
+            		throw new IllegalStateException("Unhandled component value");
+            	}
+            	
+            	StringBuilder sb = new StringBuilder();
+            	sb.append('#');
+        		sb.append(this.getComments().replace("\r\n", "\r\n#"));
+        		sb.append("\r\n");
+        		sb.append(this.getName());
+        		sb.append(" = ");
+        		sb.append(value);
+        		sb.append("\r\n");
+        		sb.append("\r\n");
+        		writer.write(sb.toString());
+            	
+            }
+    	}
+    }
+    
+    
+    
+    public static enum ValueType
+    {
+    	BOOLEAN (Boolean.class),
+    	DOUBLE (Double.class),
+    	INTEGER (Integer.class),
+    	IPv4 (Inet4Address.class),
+    	STRING (String.class);
+    	
+    	private final Class<?> _type;
+    	
+    	private ValueType(Class<?> type)
+    	{
+    		_type = type;
+    	}
+
+		/**
+         * @return Returns the type.
+         */
+        public Class<?> getType()
+        {
+	        return _type;
+        }
+        
+        public static ValueType firstTypeMatch(Object value)
+        {
+        	for (ValueType vt : ValueType.values())
+        	{
+        		if (vt.getType() == value.getClass())
+        		{
+        			return vt;
+        		}
+        	}
+        	throw new NoSuchElementException("No match for: "+value.getClass().getName());
+        }
+    }
+
+
+
+	/**
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    @Override
+    public void actionPerformed(ActionEvent e)
+    {
+	    String cmd = e.getActionCommand();
+	    
+	    StringBuilder errors = new StringBuilder();
+	    
+	    if (cmd.equals("save"))
+	    {
+	    	for (ConfigFile cf : ConfigUserInterface.this.getConfigs())
+	    	{
+	    		try
+                {
+	                cf.save();
+                }
+                catch (Exception e1)
+                {
+                	e1.printStackTrace();
+                	errors.append(getBundle().getString("errorSaving")+cf.getName()+".properties. "+getBundle().getString("reason")+e1.getLocalizedMessage()+"\r\n");
+                }
+	    	}
+	    	if (errors.length() == 0)
+            {
+            	JOptionPane.showMessageDialog(ConfigUserInterface.this, getBundle().getString("success"), "OK", JOptionPane.INFORMATION_MESSAGE);
+            }
+            else
+            {
+            	JOptionPane.showMessageDialog(ConfigUserInterface.this,errors,getBundle().getString("error"),JOptionPane.ERROR_MESSAGE);
+            	System.exit(2);
+            }
+	    }
+	    else if (cmd.equals("exit"))
+	    {
+	    	System.exit(0);
+	    }
+	    else if (cmd.equals("about"))
+	    {
+	    	JOptionPane.showMessageDialog(ConfigUserInterface.this, getBundle().getString("credits") + "\nhttp://www.l2jserver.com\n\n"+getBundle().getString("icons")+"\n\n"+getBundle().getString("language")+'\n'+getBundle().getString("translation"), getBundle().getString("aboutItem"), JOptionPane.INFORMATION_MESSAGE, ImagesTable.getImage("l2jserverlogo.png"));
+	    }
+    }
+
+	/**
+     * @param configs The configuration to set.
+     */
+    public void setConfigs(List<ConfigFile> configs)
+    {
+	    _configs = configs;
+    }
+
+	/**
+     * @return Returns the configuration.
+     */
+    public List<ConfigFile> getConfigs()
+    {
+	    return _configs;
+    }
+    
+    /**
+     * @return Returns the configuration setting name in a
+     * human readable form.
+     */
+    
+    public static String unCamelize(final String keyName) {
+    	Pattern p = Pattern.compile("\\p{Lu}");
+    	Matcher m = p.matcher(keyName);
+    	StringBuffer sb = new StringBuffer();
+    	int last = 0;
+    	while (m.find())
+    	{
+    		if (m.start() != last + 1)
+    		{
+    			m.appendReplacement(sb," " + m.group());
+    		}
+    		last = m.start();
+    	}
+    	m.appendTail(sb);
+    	return sb.toString().trim();
+    }
+
+	/**
+     * @param bundle The bundle to set.
+     */
+    public void setBundle(ResourceBundle bundle)
+    {
+	    _bundle = bundle;
+    }
+
+	/**
+     * @return Returns the bundle.
+     */
+    public ResourceBundle getBundle()
+    {
+	    return _bundle;
+    }
+}

+ 329 - 0
L2_GameServer/java/net/sf/l2j/configurator/JIPTextField.java

@@ -0,0 +1,329 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.sf.l2j.configurator;
+
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.PlainDocument;
+
+/**
+ * 
+ *
+ * @author  KenM
+ */
+public class JIPTextField extends JPanel implements FocusListener
+{
+	/**
+     * Comment for <code>serialVersionUID</code>
+     */
+    private static final long serialVersionUID = 1L;
+	private JTextField[] _textFields;
+	private List<FocusListener> _focusListeners;
+
+	public JIPTextField(String textIp)
+	{
+		super.addFocusListener(this);
+
+		initIPTextField(textIp);
+
+		for (int i = 0; i < _textFields.length; i++)
+		{
+			_textFields[i].addFocusListener(this);
+		}
+	}
+	
+	public JIPTextField()
+	{
+		this("...");
+	}
+
+	/**
+     * @param value
+     */
+    public JIPTextField(Inet4Address value)
+    {
+	    this(value.getHostAddress());
+    }
+	
+
+	private void initIPTextField(String textIp)
+	{
+		final ActionListener nextfocusaction = new ActionListener()
+		{
+			public void actionPerformed(ActionEvent evt)
+			{
+				((Component) evt.getSource()).transferFocus();
+			}
+		};
+		
+		this.setLayout(new GridBagLayout());
+		_textFields = new JTextField[4];
+
+		GridBagConstraints cons = new GridBagConstraints();
+		cons.anchor = GridBagConstraints.PAGE_START;
+		cons.fill = GridBagConstraints.HORIZONTAL;
+		cons.insets = new Insets(1, 1, 1, 1);
+		cons.gridx = 0;
+		cons.gridy = 0;
+		
+		
+		MaxLengthDocument previous = null;
+		String[] parts = textIp.split("\\.");
+		for (int i = 0; i < 4; i++)
+		{
+			String str = parts[i];
+			if (i > 0)
+			{
+				JLabel dot = new JLabel(".");
+				cons.weightx = 0;
+				add(dot, cons);
+				cons.gridx++;
+			}
+			MaxLengthDocument maxDoc = new MaxLengthDocument(3);
+			_textFields[i] = new JTextField(maxDoc, str, 3);
+			if (previous != null)
+			{
+				previous.setNext(_textFields[i]);
+			}
+			previous = maxDoc;
+			//ic.weightx = 1;
+			add(_textFields[i], cons);
+			_textFields[i].addActionListener(nextfocusaction);
+			cons.gridx++;
+		}
+	}
+
+	public void addFocusListener(FocusListener fl)
+	{
+		if (_focusListeners == null)
+		{
+			_focusListeners = new LinkedList<FocusListener>();
+		}
+
+		if (fl != null && !_focusListeners.contains(fl))
+		{
+			_focusListeners.add(fl);
+		}
+	}
+
+	public void removeFocusListener(FocusListener fl)
+	{
+		if (_focusListeners != null)
+		{
+			_focusListeners.remove(fl);
+		}
+	}
+
+	public String getText()
+	{
+		String str = "";
+		for (int i = 0; i < 4; i++)
+		{
+			if (_textFields[i].getText().length() == 0)
+			{
+				str += "0";
+			}
+			else
+			{
+				str += _textFields[i].getText();
+			}
+			if (i < 3)
+			{
+				str += ".";
+			}
+		}
+		return str;
+	}
+
+	public void setText(String str)
+	{
+		try
+		{
+			// make sure string is not null; throw a NullPointerException otherwise
+			str.length();
+
+			InetAddress ip = InetAddress.getByName(str);
+			byte b[] = ip.getAddress();
+			for (int i = 0; i < 4; i++)
+			{
+				// byte always have a sign in Java, IP addresses aren't
+				if (b[i] >= 0)
+				{
+					_textFields[i].setText(Byte.toString(b[i]));
+				}
+				else
+				{
+					_textFields[i].setText(Integer.toString(b[i] + 256));
+				}
+			}
+			return;
+		}
+		catch (UnknownHostException ex)
+		{
+		}
+		catch (NullPointerException npe)
+		{
+		}
+		for (int i = 0; i < 4; i++)
+		{
+			_textFields[i].setText("");
+		}
+	}
+
+	public void setEnabled(boolean enabled)
+	{
+		for(int i=0;i<_textFields.length;i++)
+		{
+			if(_textFields[i] != null)
+			{
+				_textFields[i].setEnabled(enabled);
+			}
+		}
+	}
+
+	public boolean isEmpty()
+	{
+		for (int i = 0; i < 4; i++)
+		{
+			if (_textFields[i].getText().length() != 0)
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	public boolean isCorrect()
+	{
+		for (int i = 0; i < 4; i++)
+		{
+			if (_textFields[i].getText().length() == 0)
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+
+	public void focusGained(FocusEvent event)
+	{
+		if (_focusListeners != null)
+		{
+			for (FocusListener fl : _focusListeners)
+			{
+				fl.focusGained(event);
+			}
+		}
+	}
+
+	public void focusLost(FocusEvent event)
+	{
+		if (isCorrect() || isEmpty())
+		{
+			if (_focusListeners != null)
+			{
+				for (FocusListener fl : _focusListeners)
+				{
+					fl.focusLost(event);
+				}
+			}
+		}
+	}
+
+	public class MaxLengthDocument extends PlainDocument
+	{
+		
+		/**
+         * Comment for <code>serialVersionUID</code>
+         */
+        private static final long serialVersionUID = 1L;
+        
+		private int _max;
+		private JTextField _next;
+		
+		public MaxLengthDocument(int maxLength)
+		{
+			this(maxLength, null);
+		}
+		
+		public MaxLengthDocument(int maxLength, JTextField next)
+		{
+			_max = maxLength;
+			setNext(next);
+		}
+		
+		public void insertString(int offset, String str, AttributeSet a) throws BadLocationException
+		{
+			if (getLength() + str.length() > _max)
+			{
+				if (getNext() != null)
+				{
+					if (this.getNext().getText().length() > 0)
+					{
+						this.getNext().select(0, this.getNext().getText().length());
+					}
+					else
+					{
+						this.getNext().getDocument().insertString(0, str, a);
+					}
+					getNext().requestFocusInWindow();
+				}
+				else
+				{
+					Toolkit.getDefaultToolkit().beep();
+				}
+			}
+			else
+			{
+				super.insertString(offset, str, a);
+			}
+		}
+
+		/**
+         * @param next The next to set.
+         */
+        public void setNext(JTextField next)
+        {
+	        _next = next;
+        }
+
+		/**
+         * @return Returns the next.
+         */
+        public JTextField getNext()
+        {
+	        return _next;
+        }
+	}
+}

+ 641 - 0
L2_GameServer/java/net/sf/l2j/gsregistering/BaseGameServerRegister.java

@@ -0,0 +1,641 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.sf.l2j.gsregistering;
+
+import java.awt.HeadlessException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.Map.Entry;
+
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+
+import net.sf.l2j.Config;
+import net.sf.l2j.L2DatabaseFactory;
+import net.sf.l2j.Server;
+import net.sf.l2j.gameserver.LoginServerThread;
+import net.sf.l2j.i18n.LanguageControl;
+import net.sf.l2j.loginserver.GameServerTable;
+
+/**
+ *
+ * @author KenM
+ */
+public abstract class BaseGameServerRegister
+{
+	private boolean _loaded = false;
+	private ResourceBundle _bundle;
+	
+	public static void main(String[] args)
+	{
+		Locale locale = null;
+		boolean gui = true;
+		boolean interactive = true;
+		boolean force = false;
+		boolean fallback = false;
+		BaseTask task = null;
+		
+		ResourceBundle bundle = null;
+		try
+		{
+			if (locale == null)
+			{
+				locale = Locale.getDefault();
+			}
+			bundle = ResourceBundle.getBundle("gsregister.GSRegister", locale, LanguageControl.INSTANCE);
+		}
+		catch (Throwable t)
+		{
+			System.out.println("FATAL: Failed to load default translation.");
+			System.exit(666);
+		}
+		
+		String arg;
+		for (int i = 0 ; i < args.length; i++)
+		{
+			arg = args[i];
+			
+			/* --cmd : no gui */
+			if (arg.equals("-c") || arg.equals("--cmd"))
+			{
+				gui = false;
+			}
+			/* --force
+			 * Forces GameServer register operations to overwrite a server if necessary
+			 */
+			else if (arg.equals("-f") || arg.equals("--force"))
+			{
+				force = true;
+			}
+			/* --fallback
+			 * If an register operation fails due to ID already being in use it will then try to register first available ID
+			 */
+			else if (arg.equals("-b") || arg.equals("--fallback"))
+			{
+				fallback = true;
+			}
+			/* --register <id> <hexid_dest_dir>
+			 * Register GameServer with ID <id> and output hexid on <hexid_dest_dir>
+			 * Fails if <id> already in use, unless -force is used (overwrites)
+			 */
+			else if (arg.equals("-r") || arg.equals("--register"))
+			{
+				gui = false;
+				interactive = false;
+				int id = Integer.parseInt(args[++i]);
+				String dir = args[++i];
+				
+				task = new RegisterTask(id, dir, force, fallback);
+			}
+			/* --unregister <id>
+			 * Removes GameServer denoted by <id>
+			 */
+			else if (arg.equals("-u") || arg.equals("--unregister"))
+			{
+				gui = false;
+				interactive = false;
+				String gsId = args[++i];
+				if (gsId.equalsIgnoreCase("all"))
+				{
+					task = new UnregisterAllTask();
+				}
+				else
+				{
+					try
+					{
+						int id = Integer.parseInt(gsId);
+						task = new UnregisterTask(id);
+					}
+					catch (NumberFormatException e)
+					{
+						System.out.printf(bundle.getString("wrongUnregisterArg")+'\n',gsId);
+						System.exit(1);
+					}
+				}
+			}
+			/* --language <locale>
+			 * Sets the app to use the specified locale, overriding auto-detection
+			 */
+			else if (arg.equals("-l") || arg.equals("--language"))
+			{
+				String loc = args[++i];
+				Locale[] availableLocales = Locale.getAvailableLocales();
+				Locale l;
+				for (int j = 0; j < availableLocales.length && locale == null; j++)
+				{
+					l = availableLocales[j];
+					if (l.toString().equals(loc))
+					{
+						locale = l;
+					}
+				}
+				if (locale == null)
+				{
+					System.out.println("Specified locale '"+loc+"' was not found, using default behaviour.");
+				}
+				else
+				{
+					try
+					{
+						bundle = ResourceBundle.getBundle("gsregister.GSRegister", locale, LanguageControl.INSTANCE);
+					}
+					catch (Throwable t)
+					{
+						System.out.println("Failed to load translation ''");
+					}
+				}
+			}
+			/* --help
+			 * Prints usage/arguments/credits
+			 */
+			else if (arg.equals("-h") || arg.equals("--help"))
+			{
+				gui = false;
+				interactive = false;
+				
+				BaseGameServerRegister.printHelp(bundle);
+			}
+		}
+		
+		try
+		{
+			if (gui)
+			{
+				BaseGameServerRegister.startGUI(bundle);
+			}
+			else
+			{
+				if (interactive)
+				{
+					BaseGameServerRegister.startCMD(bundle);
+				}
+				else
+				{
+					// if there is a task, do it
+					// else the app has already finished
+					if (task != null)
+					{
+						task.setBundle(bundle);
+						task.run();
+					}
+				}
+			}
+		}
+		catch (HeadlessException e)
+		{
+			BaseGameServerRegister.startCMD(bundle);
+		}
+	}
+	
+	private static void printHelp(ResourceBundle bundle)
+	{
+		String[] help = 
+		{ 
+				bundle.getString("purpose") ,
+				"",
+				bundle.getString("options"),
+				"-b, --fallback\t\t\t\t"+bundle.getString("fallbackOpt"),
+				"-c, --cmd\t\t\t\t"+bundle.getString("cmdOpt"),
+				"-f, --force\t\t\t\t"+bundle.getString("forceOpt"),
+				"-h, --help\t\t\t\t"+bundle.getString("helpOpt"),
+				"-l, --language\t\t\t\t"+bundle.getString("languageOpt"),
+				"-r, --register <id> <hexid_dest_dir>\t"+bundle.getString("registerOpt1"),
+				"\t\t\t\t\t"+bundle.getString("registerOpt2"),
+				"\t\t\t\t\t"+bundle.getString("registerOpt3"),
+				"",
+				"-u, --unregister <id>|all\t\t"+bundle.getString("unregisterOpt"),
+				"",
+				bundle.getString("credits"),
+				bundle.getString("bugReports")+" http://www.l2jserver.com"
+				
+				/*
+				"-b, --fallback\t\t\t\tIf an register operation fails due to ID already being in use it will then try to register first available ID",
+				"-c, --cmd\t\t\t\tForces application to run in command-line mode even if the GUI is supported.",
+				"-f, --force\t\t\t\tForces GameServer register operations to overwrite a server if necessary",
+				"-h, --help\t\t\t\tPrints this help message",
+				"-l, --language <locale>\t\t\t\tAsks the application to use the specified locale, overriding auto-detection",
+				"-r, --register <id> <hexid_dest_dir>\tRegister GameServer with ID <id> and output hexid on <hexid_dest_dir>",
+				"\t\t\t\t\tUse a negative value on <id> to register the first available ID",
+				"\t\t\t\t\tFails if <id> already in use, unless --force is used (overwrites)",
+				"",
+				"-u, --unregister <id>|all\t\tRemoves GameServer denoted by <id>, use \"all\" for removing all registered GameServers",
+				"",
+				"Copyright (C) L2J Team 2008-2009.",
+				"Report bugs: http://www.l2jserver.com"
+				*/
+		};
+		
+		for (String str : help)
+		{
+			System.out.println(str);
+		}
+	}
+	
+	private static void startGUI(final ResourceBundle bundle)
+	{
+		try
+		{
+			// avoid that ugly Metal LaF
+			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+		}
+		catch (Exception e)
+		{
+			// couldn't care less
+		}
+		
+		SwingUtilities.invokeLater
+		(
+				new Runnable()
+				{
+					@Override
+                    public void run()
+                    {
+						GUserInterface gui = new GUserInterface(bundle);
+						gui.getFrame().setVisible(true);
+                    }
+				}
+		);
+	}
+	
+	private static void startCMD(final ResourceBundle bundle)
+	{
+		GameServerRegister cmdUi = new GameServerRegister(bundle);
+		try
+        {
+	        cmdUi.consoleUI();
+        }
+        catch (IOException e)
+        {
+        	cmdUi.showError("I/O exception trying to get input from keyboard.", e);
+        }
+	}
+	
+	public BaseGameServerRegister(ResourceBundle bundle)
+	{
+		setBundle(bundle);
+	}
+	
+	public void load()
+	{
+		try
+		{
+			this.loadImp();
+		}
+		catch (Exception e)
+		{
+			this.showError(this.getBundle().getString("gsListRetrieveError"), e);
+		}
+	}
+	
+	/**
+	 * Loads Configs and SQL.<BR>
+	 * This method must be invoked manually as to allow the given interface 
+	 * to do in the most convenient way.<BR>
+	 * 
+	 * @throws Exception
+	 */
+	protected void loadImp() throws Exception
+	{
+		Server.serverMode = Server.MODE_LOGINSERVER;
+		
+		Config.load();
+		GameServerTable.load();
+		
+		_loaded = true;
+	}
+	
+	public boolean isLoaded()
+	{
+		return _loaded;
+	}
+	
+	/**
+     * @param bundle The bundle to set.
+     */
+    public void setBundle(ResourceBundle bundle)
+    {
+	    _bundle = bundle;
+    }
+
+	/**
+     * @return Returns the bundle.
+     */
+    public ResourceBundle getBundle()
+    {
+	    return _bundle;
+    }
+	
+	public abstract void showError(String msg, Throwable t);
+	
+	/**
+     * @param id
+	 * @throws SQLException 
+     */
+    public static void unregisterGameServer(int id) throws SQLException
+    {
+    	java.sql.Connection con = null;
+		PreparedStatement statement = null;
+		
+		try
+		{
+			con = L2DatabaseFactory.getInstance().getConnection();
+			statement = con.prepareStatement("DELETE FROM gameservers WHERE server_id = ?");
+			statement.setInt(1, id);
+			statement.executeUpdate();
+			GameServerTable.getInstance().getRegisteredGameServers().remove(id);
+		}
+		finally
+		{
+			try
+			{
+				statement.close();
+			}
+			catch (SQLException e)
+			{
+				// nothing
+			}
+			
+			if (con != null)
+			{
+				try
+				{
+					
+					con.close();
+				}
+				catch (SQLException e)
+				{
+					// nothing
+				}
+			}
+		}
+    }
+    
+    public static void unregisterAllGameServers() throws SQLException
+	{
+		java.sql.Connection con = null;
+		PreparedStatement statement = null;
+		
+		try
+		{
+			con = L2DatabaseFactory.getInstance().getConnection();
+			statement = con.prepareStatement("DELETE FROM gameservers");
+			statement.executeUpdate();
+			GameServerTable.getInstance().getRegisteredGameServers().clear();
+		}
+		finally
+		{
+			try
+			{
+				statement.close();
+			}
+			catch (SQLException e)
+			{
+				// nothing
+			}
+			
+			if (con != null)
+			{
+				try
+				{
+					
+					con.close();
+				}
+				catch (SQLException e)
+				{
+					// nothing
+				}
+			}
+		}
+	}
+    
+    public static void registerGameServer(int id, String outDir) throws IOException
+    {
+    	byte[] hexId = LoginServerThread.generateHex(16);
+    	GameServerTable.getInstance().registerServerOnDB(hexId, id, "");
+		
+    	Properties hexSetting = new Properties();
+    	File file = new File(outDir, "hexid.txt");
+    	//Create a new empty file only if it doesn't exist
+    	file.createNewFile();
+    	OutputStream out = new FileOutputStream(file);
+    	hexSetting.setProperty("ServerID",String.valueOf(id));
+    	hexSetting.setProperty("HexID", new BigInteger(hexId).toString(16));
+    	hexSetting.store(out,"The HexId to Auth into LoginServer");
+    	out.close();
+    }
+    
+    public static int registerFirstAvailable(String outDir) throws IOException
+    {
+    	for (Entry<Integer, String> e : GameServerTable.getInstance().getServerNames().entrySet())
+		{
+			if (!GameServerTable.getInstance().hasRegisteredGameServerOnId(e.getKey()))
+			{
+				BaseGameServerRegister.registerGameServer(e.getKey(), outDir);
+				return e.getKey();
+			}
+		}
+    	return -1;
+    }
+    
+    static abstract class BaseTask implements Runnable
+    {
+    	private ResourceBundle _bundle;
+
+		/**
+         * @param bundle The bundle to set.
+         */
+        public void setBundle(ResourceBundle bundle)
+        {
+	        _bundle = bundle;
+        }
+
+		/**
+         * @return Returns the bundle.
+         */
+        public ResourceBundle getBundle()
+        {
+	        return _bundle;
+        }
+        
+        public void showError(String msg, Throwable t)
+    	{
+    		String title;
+    		if (this.getBundle() != null)
+    		{
+    			title = this.getBundle().getString("error");
+    			msg += '\n'+this.getBundle().getString("reason")+' '+t.getLocalizedMessage();
+    		}
+    		else
+    		{
+    			title = "Error";
+    			msg += "\nCause: "+t.getLocalizedMessage();
+    		}
+    		System.out.println(title+": "+msg);
+    	}
+    }
+    
+    static class RegisterTask extends BaseTask
+    {
+    	
+    	private final int _id;
+		private final String _outDir;
+		private boolean _force;
+		private boolean _fallback;
+		
+		public RegisterTask(int id, String outDir, boolean force, boolean fallback)
+    	{
+			_id = id;
+			_outDir = outDir;
+			_force = force;
+			_fallback = fallback;
+    	}
+		
+		public void setActions(boolean force, boolean fallback)
+		{
+			_force = force;
+			_fallback = fallback;
+		}
+    	
+		/**
+         * @see java.lang.Runnable#run()
+         */
+        @Override
+        public void run()
+        {
+        	try
+        	{
+        		if (_id < 0)
+        		{
+        			int registeredId = BaseGameServerRegister.registerFirstAvailable(_outDir);
+					
+					
+					if (registeredId < 0)
+					{
+						System.out.println(getBundle().getString("noFreeId"));
+					}
+					else
+					{
+						System.out.printf(getBundle().getString("registrationOk")+'\n', registeredId);
+					}
+        		}
+        		else
+        		{
+        			System.out.printf(getBundle().getString("checkingIdInUse")+'\n', _id);
+        			if (GameServerTable.getInstance().hasRegisteredGameServerOnId(_id))
+        			{
+        				System.out.println(getBundle().getString("yes"));
+        				if (_force)
+        				{
+        					System.out.printf(getBundle().getString("forcingRegistration")+'\n', _id);
+        					BaseGameServerRegister.unregisterGameServer(_id);
+        					BaseGameServerRegister.registerGameServer(_id, _outDir);
+        					System.out.printf(getBundle().getString("registrationOk")+'\n', _id);
+        				}
+        				else if (_fallback)
+        				{
+        					System.out.println(getBundle().getString("fallingBack"));
+        					int registeredId = BaseGameServerRegister.registerFirstAvailable(_outDir);
+        					
+        					
+        					if (registeredId < 0)
+        					{
+        						System.out.println(getBundle().getString("noFreeId"));
+        					}
+        					else
+        					{
+        						System.out.printf(getBundle().getString("registrationOk")+'\n', registeredId);
+        					}
+        				}
+        				else
+        				{
+        					System.out.println(getBundle().getString("noAction"));
+        				}
+        			}
+        			else
+        			{
+        				System.out.println(getBundle().getString("no"));
+        				BaseGameServerRegister.registerGameServer(_id, _outDir);
+        			}
+        		}
+        	}
+        	catch (SQLException e)
+        	{
+        		this.showError(getBundle().getString("sqlErrorRegister"), e);
+        	}
+            catch (IOException e)
+            {
+            	this.showError(getBundle().getString("ioErrorRegister"), e);
+            }
+        }
+    	
+    }
+    
+    static class UnregisterTask extends BaseTask
+    {
+    	private final int _id;
+
+		public UnregisterTask(int id)
+    	{
+			_id = id;
+    		
+    	}
+    	
+		/**
+         * @see java.lang.Runnable#run()
+         */
+        @Override
+        public void run()
+        {
+        	System.out.printf(getBundle().getString("removingGsId")+'\n', _id);
+        	try
+            {
+	            BaseGameServerRegister.unregisterGameServer(_id);
+            }
+            catch (SQLException e)
+            {
+            	this.showError(getBundle().getString("sqlErrorRegister"), e);
+            }
+        }
+    	
+    }
+    
+    static class UnregisterAllTask extends BaseTask
+    {
+		/**
+         * @see java.lang.Runnable#run()
+         */
+        @Override
+        public void run()
+        {
+	        try
+            {
+	            BaseGameServerRegister.unregisterAllGameServers();
+            }
+            catch (SQLException e)
+            {
+            	this.showError(getBundle().getString("sqlErrorUnregisterAll"), e);
+            }
+        }
+    	
+    }
+}

+ 432 - 0
L2_GameServer/java/net/sf/l2j/gsregistering/GUserInterface.java

@@ -0,0 +1,432 @@
+package net.sf.l2j.gsregistering;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.sql.SQLException;
+import java.util.ResourceBundle;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+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.JProgressBar;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.SwingUtilities;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+
+import net.sf.l2j.images.ImagesTable;
+import net.sf.l2j.loginserver.GameServerTable;
+
+/**
+ * @author KenM
+ *
+ */
+public class GUserInterface extends BaseGameServerRegister implements ActionListener
+{
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	private final JFrame _frame;
+
+	
+	JTableModel _dtm;
+	JProgressBar _progressBar;
+
+	public JTable _gsTable;
+	
+	public GUserInterface(ResourceBundle bundle)
+	{
+		super(bundle);
+
+		_frame = new JFrame();
+		getFrame().setTitle(getBundle().getString("toolName"));
+		getFrame().setSize(600, 400);
+		getFrame().setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+		getFrame().setLayout(new GridBagLayout());
+		GridBagConstraints cons = new GridBagConstraints();
+		
+		JMenuBar menubar = new JMenuBar();
+		getFrame().setJMenuBar(menubar);
+		
+		JMenu fileMenu = new JMenu(getBundle().getString("fileMenu"));
+		
+		JMenuItem exitItem = new JMenuItem(getBundle().getString("exitItem"));
+		exitItem.addActionListener(this);
+		exitItem.setActionCommand("exit");
+		
+		fileMenu.add(exitItem);
+		
+		JMenu helpMenu = new JMenu(getBundle().getString("helpMenu"));
+		
+		JMenuItem aboutItem = new JMenuItem(getBundle().getString("aboutItem"));
+		aboutItem.addActionListener(this);
+		aboutItem.setActionCommand("about");
+		
+		helpMenu.add(aboutItem);
+		
+		menubar.add(fileMenu);
+		menubar.add(helpMenu);
+		
+		JButton btnRegister = new JButton(getBundle().getString("btnRegister"), ImagesTable.getImage("add.png"));
+		btnRegister.addActionListener(this);
+		btnRegister.setActionCommand("register");
+		getFrame().add(btnRegister, cons);
+		
+		cons.gridx = 1;
+		cons.anchor = GridBagConstraints.LINE_END;
+		JButton btnRemoveAll = new JButton(getBundle().getString("btnRemoveAll"), ImagesTable.getImage("cross.png"));
+		btnRemoveAll.addActionListener(this);
+		btnRemoveAll.setActionCommand("removeAll");
+		getFrame().add(btnRemoveAll, cons);
+		
+		String name = getBundle().getString("gsName");
+		String action = getBundle().getString("gsAction");
+
+		_dtm = new JTableModel(new Object[] { "ID", name, action });
+		_gsTable = new JTable(_dtm);
+		_gsTable.addMouseListener(new JTableButtonMouseListener(_gsTable));
+		
+		_gsTable.getColumnModel().getColumn(0).setMaxWidth(30);
+		
+		TableColumn actionCollumn = _gsTable.getColumnModel().getColumn(2);
+		actionCollumn.setCellRenderer(new ButtonCellRenderer());
+		
+		cons.fill = GridBagConstraints.BOTH;
+		cons.gridx = 0;
+		cons.gridy = 1;
+		cons.weighty = 1.0;
+		cons.weightx = 1.0;
+		cons.gridwidth = 2;
+		JLayeredPane layer = new JLayeredPane();
+		layer.setLayout(new BoxLayout(layer, BoxLayout.PAGE_AXIS));
+		layer.add(new JScrollPane(_gsTable), 0);
+		_progressBar = new JProgressBar();
+		_progressBar.setIndeterminate(true);
+		_progressBar.setVisible(false);
+		layer.add(_progressBar, BorderLayout.CENTER, 1);
+		//layer.setV
+		getFrame().add(layer, cons);
+		
+		
+		// maximize, doesn't seem really needed 
+		//getFrame().setExtendedState(JFrame.MAXIMIZED_BOTH);
+		/*
+		// Work-around JVM maximize issue on linux
+		String osName = System.getProperty("os.name");
+		if (osName.equals("Linux"))
+		{
+		   Toolkit toolkit = Toolkit.getDefaultToolkit();
+		   Dimension screenSize = toolkit.getScreenSize();
+		   getFrame().setSize(screenSize);
+		}
+		*/
+		this.refreshAsync();
+	}
+	
+	public void refreshAsync()
+	{
+		Runnable r = new Runnable()
+		{
+			@Override
+            public void run()
+            {
+				GUserInterface.this.refreshServers();
+            }
+		};
+		Thread t = new Thread(r, "LoaderThread");
+		t.start();
+	}
+	
+	@Override
+    public void load()
+    {
+		
+		SwingUtilities.invokeLater
+		(
+				new Runnable()
+				{
+					@Override
+                    public void run()
+                    {
+						_progressBar.setVisible(true);
+                    }
+				}
+		);
+	    
+	    super.load();
+	    
+	    SwingUtilities.invokeLater
+		(
+				new Runnable()
+				{
+					@Override
+                    public void run()
+                    {
+						_progressBar.setVisible(false);
+                    }
+				}
+		);
+    }
+
+
+	/**
+     * @see net.sf.l2j.gsregistering.BaseGameServerRegister#showError(java.lang.String, java.lang.String, java.lang.Throwable)
+     */
+    @Override
+    public void showError(String msg, Throwable t)
+    {
+    	String title;
+    	if (this.getBundle() != null)
+    	{
+    		title = this.getBundle().getString("error");
+    		msg += '\n'+this.getBundle().getString("reason")+' '+t.getLocalizedMessage();
+    	}
+    	else
+    	{
+    		title = "Error";
+    		msg += "\nCause: "+t.getLocalizedMessage();
+    	}
+	    JOptionPane.showMessageDialog(this.getFrame(), msg, title, JOptionPane.ERROR_MESSAGE);
+    }
+
+	int i = 0;
+	protected void refreshServers()
+	{
+		if (!this.isLoaded())
+		{
+			this.load();
+		}
+		
+		// load succeeded?
+		if (this.isLoaded())
+		{
+			SwingUtilities.invokeLater
+			(
+					new Runnable()
+					{
+						@Override
+						public void run()
+						{
+							int size = GameServerTable.getInstance().getServerNames().size();
+							if (size == 0)
+							{
+						    	String title = getBundle().getString("error");
+								String msg = getBundle().getString("noServerNames"); 
+								JOptionPane.showMessageDialog(getFrame(), msg, title, JOptionPane.ERROR_MESSAGE);
+								System.exit(1);
+							}
+							// reset
+							_dtm.setRowCount(0);
+							
+							for (final int id : GameServerTable.getInstance().getRegisteredGameServers().keySet())
+							{
+								String name = GameServerTable.getInstance().getServerNameById(id);
+								JButton button = new JButton(getBundle().getString("btnRemove"), ImagesTable.getImage("cross.png"));
+								button.addActionListener
+								(
+										new ActionListener()
+										{
+											@Override
+											public void actionPerformed(ActionEvent e)
+											{
+												String sid = String.valueOf(id);
+												String sname = GameServerTable.getInstance().getServerNameById(id);
+												
+												int choice = JOptionPane.showConfirmDialog(getFrame(), getBundle().getString("confirmRemoveText").replace("%d", sid).replace("%s",sname), getBundle().getString("confirmRemoveTitle"), JOptionPane.YES_NO_OPTION);
+												if (choice == JOptionPane.YES_OPTION)
+												{
+													try
+													{
+														BaseGameServerRegister.unregisterGameServer(id);
+														GUserInterface.this.refreshAsync();
+													}
+													catch (SQLException e1)
+													{
+														GUserInterface.this.showError(getBundle().getString("errorUnregister"), e1);
+													}
+												}
+											}
+										}
+								);
+								_dtm.addRow(new Object[] { id, name, button });
+							}
+						}
+					}
+			);
+		}
+	}
+
+	
+
+	/* (non-Javadoc)
+	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+	 */
+	@Override
+	public void actionPerformed(ActionEvent e)
+	{
+		String cmd = e.getActionCommand();
+		
+		if (cmd.equals("register"))
+		{
+			RegisterDialog rd = new RegisterDialog(this);
+			rd.setVisible(true);
+		}
+		else if (cmd.equals("exit"))
+		{
+			System.exit(0);
+		}
+		else if (cmd.equals("about"))
+		{
+			JOptionPane.showMessageDialog(getFrame(), getBundle().getString("credits") + "\nhttp://www.l2jserver.com\n\n"+getBundle().getString("icons")+"\n\n"+getBundle().getString("language")+'\n'+getBundle().getString("translation"), getBundle().getString("aboutItem"), JOptionPane.INFORMATION_MESSAGE, ImagesTable.getImage("l2jserverlogo.png"));
+		}
+		else if (cmd.equals("removeAll"))
+		{
+			int choice = JOptionPane.showConfirmDialog(getFrame(), getBundle().getString("confirmRemoveAllText"), getBundle().getString("confirmRemoveTitle"), JOptionPane.YES_NO_OPTION);
+			if (choice == JOptionPane.YES_OPTION)
+			{
+				try
+                {
+	                BaseGameServerRegister.unregisterAllGameServers();
+	                this.refreshAsync();
+                }
+                catch (SQLException e1)
+                {
+                	GUserInterface.this.showError(getBundle().getString("errorUnregister"), e1);
+                }
+			}
+		}
+	}
+
+	/**
+     * @return Returns the frame.
+     */
+    public JFrame getFrame()
+    {
+	    return _frame;
+    }
+
+	class ButtonCellRenderer implements TableCellRenderer
+	{
+
+		/* (non-Javadoc)
+		 * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int)
+		 */
+		@Override
+		public Component getTableCellRendererComponent(JTable table,
+				Object value, boolean isSelected, boolean hasFocus, int row,
+				int column)
+		{
+			return (Component) value;
+		}
+		
+	}
+	
+	/**
+	 * Forward mouse-events from table to buttons inside.
+	 * Buttons animate properly.
+	 *
+	 * @author  KenM
+	 */
+	class JTableButtonMouseListener implements MouseListener
+	{
+		private final JTable _table;
+		
+		public JTableButtonMouseListener(JTable table)
+		{
+			_table = table;
+		}
+		
+		private void forwardEvent(MouseEvent e)
+	    {
+	        TableColumnModel columnModel = _table.getColumnModel();
+	        int column = columnModel.getColumnIndexAtX(e.getX());
+	        int row    = e.getY() / _table.getRowHeight();
+	        Object value;
+
+	        if (row >= _table.getRowCount() || row < 0 || column >= _table.getColumnCount() || column < 0)
+	        {
+	            return;
+	        }
+
+	        value = _table.getValueAt(row, column);
+	        
+	        if (value instanceof JButton)
+	        {
+	            final JButton b = (JButton) value;
+	            if (e.getID() == MouseEvent.MOUSE_PRESSED)
+	            {
+	            	b.getModel().setPressed(true);
+					b.getModel().setArmed(true);
+					_table.repaint();
+	            }
+	            else if (e.getID() == MouseEvent.MOUSE_RELEASED)
+	            {
+	            	b.doClick();
+	            }
+	        }
+	    }
+
+	    public void mouseEntered(MouseEvent e)
+	    {
+	        forwardEvent(e);
+	    }
+
+	    public void mouseExited(MouseEvent e)
+	    {
+	        forwardEvent(e);
+	    }
+
+	    public void mousePressed(MouseEvent e)
+	    {
+	        forwardEvent(e);
+	    }
+
+	    public void mouseClicked(MouseEvent e)
+	    {
+	    	forwardEvent(e);
+	    }
+	    
+	    public void mouseReleased(MouseEvent e)
+	    {
+	    	forwardEvent(e);
+	    }
+	}
+	
+	@SuppressWarnings("serial")
+	class JTableModel extends DefaultTableModel
+	{
+		public JTableModel(Object[] columnNames)
+		{
+			super(columnNames, 0);
+		}
+		
+		@Override
+		public boolean isCellEditable(int row, int column)
+		{
+			return false;
+		}
+		
+		@Override
+		public Class<?> getColumnClass(int column)
+		{
+			return getValueAt(0, column).getClass();
+		}
+	}
+}

+ 288 - 94
L2_GameServer/java/net/sf/l2j/gsregistering/GameServerRegister.java

@@ -17,133 +17,327 @@ package net.sf.l2j.gsregistering;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.LineNumberReader;
-import java.math.BigInteger;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
 import java.sql.SQLException;
-import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Map.Entry;
 
-import net.sf.l2j.Config;
-import net.sf.l2j.L2DatabaseFactory;
-import net.sf.l2j.Server;
-import net.sf.l2j.gameserver.LoginServerThread;
 import net.sf.l2j.loginserver.GameServerTable;
 
-public class GameServerRegister
+public class GameServerRegister extends BaseGameServerRegister
 {
-	private static String _choice;
-	private static boolean _choiceOk;
-
-	public static void main(String[] args) throws IOException
+	private LineNumberReader _in;
+	
+	public static void main(String[] args)
 	{
-		Server.serverMode = Server.MODE_LOGINSERVER;
-
-		Config.load();
-
-		LineNumberReader _in = new LineNumberReader(new InputStreamReader(System.in));
-		try
-		{
-			GameServerTable.load();
-		}
-		catch (Exception e)
+		// Backwards compatibility, redirect to the new one
+		BaseGameServerRegister.main(args);
+	}
+	
+	/**
+	 * 
+	 * @param bundle
+	 */
+	public GameServerRegister(ResourceBundle bundle)
+	{
+		super(bundle);
+		this.load();
+		
+		int size = GameServerTable.getInstance().getServerNames().size();
+		if (size == 0)
 		{
-			System.out.println("FATAL: Failed loading GameServerTable. Reason: "+e.getMessage());
-			e.printStackTrace();
+			System.out.println(this.getBundle().getString("noServerNames"));
 			System.exit(1);
 		}
-		GameServerTable gameServerTable = GameServerTable.getInstance();
-		System.out.println("Welcome to L2J GameServer Registration");
-		System.out.println("Enter The id of the server you want to register");
-		System.out.println("Type 'help' to get a list of ids.");
-		System.out.println("Type 'clean' to unregister all currently registered gameservers on this LoginServer.");
-		while (!_choiceOk)
+	}
+	
+	public void consoleUI() throws IOException
+	{
+		_in = new LineNumberReader(new InputStreamReader(System.in));
+		boolean choiceOk = false;
+		String choice;
+		
+		while (true)
 		{
-			System.out.println("Your choice:");
-			_choice = _in.readLine();
-			if(_choice.equalsIgnoreCase("help"))
+			this.hr();
+			System.out.println("GSRegister");
+			System.out.println('\n');
+			System.out.println("1 - "+this.getBundle().getString("cmdMenuRegister"));
+			System.out.println("2 - "+this.getBundle().getString("cmdMenuListNames"));
+			System.out.println("3 - "+this.getBundle().getString("cmdMenuRemoveGS"));
+			System.out.println("4 - "+this.getBundle().getString("cmdMenuRemoveAll"));
+			System.out.println("5 - "+this.getBundle().getString("cmdMenuExit"));
+			
+			do
 			{
-				for (Map.Entry<Integer, String> entry : gameServerTable.getServerNames().entrySet())
+				System.out.print(this.getBundle().getString("yourChoice")+' ');
+				choice = _in.readLine();
+				try
+				{
+					int choiceNumber = Integer.parseInt(choice);
+					choiceOk = true;
+					
+					switch (choiceNumber)
+					{
+						case 1:
+							this.registerNewGS();
+							break;
+						case 2:
+							this.listGSNames();
+							break;
+						case 3:
+							this.unregisterSingleGS();
+							break;
+						case 4:
+							this.unregisterAllGS();
+							break;
+						case 5:
+							System.exit(0);
+							break;
+						default:
+							System.out.printf(this.getBundle().getString("invalidChoice")+'\n', choice);
+							choiceOk = false;
+					}
+					
+				}
+				catch (NumberFormatException nfe)
 				{
-					System.out.println("Server: ID: "+entry.getKey()+"\t- "+entry.getValue()+" - In Use: "+(gameServerTable.hasRegisteredGameServerOnId(entry.getKey()) ? "YES" : "NO"));
+					System.out.printf(this.getBundle().getString("invalidChoice")+'\n', choice);
 				}
-				System.out.println("You can also see servername.xml");
 			}
-			else if(_choice.equalsIgnoreCase("clean"))
+			while (!choiceOk);
+		}
+	}
+	
+	/**
+     * 
+     */
+    private void hr()
+    {
+    	System.out.println("_____________________________________________________\n");
+    }
+
+	/**
+	 * 
+	 */
+	private void listGSNames()
+	{
+		int idMaxLen = 0;
+		int nameMaxLen = 0;
+		for (Entry<Integer, String> e : GameServerTable.getInstance().getServerNames().entrySet())
+		{
+			if (e.getKey().toString().length() > idMaxLen)
+			{
+				idMaxLen = e.getKey().toString().length();
+			}
+			if (e.getValue().length() > nameMaxLen)
 			{
-				System.out.print("This is going to UNREGISTER ALL servers from this LoginServer. Are you sure? (y/n) ");
-				_choice = _in.readLine();
-				if (_choice.equals("y"))
+				nameMaxLen = e.getValue().length();
+			}
+		}
+		idMaxLen += 2;
+		nameMaxLen += 2;
+		
+		String id;
+		boolean inUse;
+		String gsInUse = this.getBundle().getString("gsInUse");
+		String gsFree = this.getBundle().getString("gsFree");
+		int gsStatusMaxLen = Math.max(gsInUse.length(), gsFree.length()) + 2;
+		for (Entry<Integer, String> e : GameServerTable.getInstance().getServerNames().entrySet())
+		{
+			id = e.getKey().toString();
+			System.out.print(id);
+			
+			for (int i = id.length(); i < idMaxLen; i++)
+			{
+				System.out.print(' ');
+			}
+			System.out.print("| ");
+			
+			System.out.print(e.getValue());
+			
+			for (int i = e.getValue().length(); i < nameMaxLen; i++)
+			{
+				System.out.print(' ');
+			}
+			System.out.print("| ");
+			
+			inUse = GameServerTable.getInstance().hasRegisteredGameServerOnId(e.getKey());
+			String inUseStr = (inUse ? gsInUse : gsFree);
+			System.out.print(inUseStr);
+			
+			for (int i = inUseStr.length(); i < gsStatusMaxLen; i++)
+			{
+				System.out.print(' ');
+			}
+			System.out.println('|');
+		}
+	}
+	
+	/**
+	 * @throws IOException 
+	 * 
+	 */
+	private void unregisterAllGS() throws IOException
+	{
+		if (this.yesNoQuestion(this.getBundle().getString("confirmRemoveAllText")))
+		{
+			try
+			{
+				BaseGameServerRegister.unregisterAllGameServers();
+				System.out.println(this.getBundle().getString("unregisterAllOk"));
+			}
+			catch (SQLException e)
+			{
+				this.showError(this.getBundle().getString("sqlErrorUnregisterAll"), e);
+			}
+		}
+	}
+	
+	private boolean yesNoQuestion(String question) throws IOException
+	{
+		
+		do
+		{
+			this.hr();
+			System.out.println(question);
+			System.out.println("1 - "+this.getBundle().getString("yes"));
+			System.out.println("2 - "+this.getBundle().getString("no"));
+			System.out.print(this.getBundle().getString("yourChoice")+' ');
+			String choice;
+			choice = _in.readLine();
+			if (choice.equals("1"))
+			{
+				return true;
+			}
+			else if (choice.equals("2"))
+			{
+				return false;
+			}
+			else
+			{
+				System.out.printf(this.getBundle().getString("invalidChoice")+'\n', choice);
+			}
+		}
+		while (true);
+	}
+	
+	/**
+	 * @throws IOException 
+	 * 
+	 */
+	private void unregisterSingleGS() throws IOException
+	{
+		String line;
+		int id = Integer.MIN_VALUE;
+		
+		do
+		{
+			System.out.print(this.getBundle().getString("enterDesiredId")+' ');
+			line = _in.readLine();
+			try
+			{
+				id = Integer.parseInt(line);
+			}
+			catch (NumberFormatException e)
+			{
+				System.out.printf(this.getBundle().getString("invalidChoice")+'\n', line);
+			}
+		}
+		while (id == Integer.MIN_VALUE);
+		
+		String name = GameServerTable.getInstance().getServerNameById(id);
+		if (name == null)
+		{
+			System.out.printf(this.getBundle().getString("noNameForId")+'\n', id);
+		}
+		else
+		{
+			if (GameServerTable.getInstance().hasRegisteredGameServerOnId(id))
+			{
+				System.out.printf(this.getBundle().getString("confirmRemoveText")+'\n', id, name);
+				try
 				{
-					GameServerRegister.cleanRegisteredGameServersFromDB();
-					gameServerTable.getRegisteredGameServers().clear();
+					BaseGameServerRegister.unregisterGameServer(id);
+					System.out.printf(this.getBundle().getString("unregisterOk")+'\n', id);
 				}
-				else
+				catch (SQLException e)
 				{
-					System.out.println("ABORTED");
+					this.showError(this.getBundle().getString("sqlErrorUnregister"), e);
 				}
+				
+			}
+			else
+			{
+				System.out.printf(this.getBundle().getString("noServerForId")+'\n', id);
+			}
+		}
+		
+		
+	}
+	
+	private void registerNewGS() throws IOException
+	{
+		String line;
+		int id = Integer.MIN_VALUE;
+		
+		do
+		{
+			System.out.println(this.getBundle().getString("enterDesiredId"));
+			line = _in.readLine();
+			try
+			{
+				id = Integer.parseInt(line);
+			}
+			catch (NumberFormatException e)
+			{
+				System.out.printf(this.getBundle().getString("invalidChoice")+'\n', line);
+			}
+		}
+		while (id == Integer.MIN_VALUE);
+		
+		
+		String name = GameServerTable.getInstance().getServerNameById(id);
+		if (name == null)
+		{
+			System.out.printf(this.getBundle().getString("noNameForId")+'\n', id);
+		}
+		else
+		{
+			if (GameServerTable.getInstance().hasRegisteredGameServerOnId(id))
+			{
+				System.out.println(this.getBundle().getString("idIsNotFree"));
 			}
 			else
 			{
 				try
 				{
-					int id = Integer.parseInt(_choice);
-					int size = gameServerTable.getServerNames().size();
-
-					if (size == 0)
-					{
-						System.out.println("No server names avalible, please make sure that servername.xml is in the LoginServer directory.");
-						System.exit(1);
-					}
-
-					String name = gameServerTable.getServerNameById(id);
-					if (name == null)
-					{
-						System.out.println("No name for id: "+id);
-						continue;
-					}
-					else
-					{
-						if (gameServerTable.hasRegisteredGameServerOnId(id))
-						{
-							System.out.println("This id is not free");
-						}
-						else
-						{
-							byte[] hexId = LoginServerThread.generateHex(16);
-							gameServerTable.registerServerOnDB(hexId, id, "");
-							Config.saveHexid(id, new BigInteger(hexId).toString(16),"hexid(server "+id+").txt");
-							System.out.println("Server Registered hexid saved to 'hexid(server "+id+").txt'");
-							System.out.println("Put this file in the /config folder of your gameserver and rename it to 'hexid.txt'");
-							return;
-						}
-					}
+					BaseGameServerRegister.registerGameServer(id, ".");
 				}
-				catch (NumberFormatException nfe)
+				catch (IOException e)
 				{
-					System.out.println("Please, type a number or 'help'");
+					this.showError(getBundle().getString("ioErrorRegister"), e);
 				}
 			}
 		}
 	}
-
-	public static void cleanRegisteredGameServersFromDB()
+	
+	/**
+	 * @see net.sf.l2j.gsregistering.BaseGameServerRegister#showError(java.lang.String, java.lang.Throwable)
+	 */
+	@Override
+	public void showError(String msg, Throwable t)
 	{
-		Connection con = null;
-		PreparedStatement statement = null;
-		try
-		{
-			con = L2DatabaseFactory.getInstance().getConnection();
-			statement = con.prepareStatement("DELETE FROM gameservers");
-			statement.executeUpdate();
-			statement.close();
-		}
-		catch (SQLException e)
+		String title;
+		if (this.getBundle() != null)
 		{
-			System.out.println("SQL error while cleaning registered servers: "+e);
+			title = this.getBundle().getString("error");
+			msg += '\n'+this.getBundle().getString("reason")+' '+t.getLocalizedMessage();
 		}
-		finally
+		else
 		{
-			try { con.close();} catch (Exception e) {}
+			title = "Error";
+			msg += "\nCause: "+t.getLocalizedMessage();
 		}
+		System.out.println(title+": "+msg);
 	}
-}
+}

+ 201 - 0
L2_GameServer/java/net/sf/l2j/gsregistering/RegisterDialog.java

@@ -0,0 +1,201 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.sf.l2j.gsregistering;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JTextPane;
+import javax.swing.filechooser.FileFilter;
+
+import net.sf.l2j.loginserver.GameServerTable;
+
+/**
+ *
+ * @author  KenM
+ */
+@SuppressWarnings("serial")
+public class RegisterDialog extends JDialog implements ActionListener
+{
+	
+	private ResourceBundle _bundle;
+	private final JComboBox _combo;
+	private final GUserInterface _owner;
+	
+	public RegisterDialog(final GUserInterface owner)
+	{
+		super(owner.getFrame(), true);
+		_owner = owner;
+		this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+		_bundle = owner.getBundle();
+		this.setTitle(_bundle.getString("registerGS"));
+		this.setResizable(false);
+		this.setLayout(new GridBagLayout());
+		GridBagConstraints cons = new GridBagConstraints();
+		cons.weightx = 0.5;
+		cons.weighty = 0.5;
+		cons.gridx = 0;
+		cons.gridy = 0;
+		cons.fill = GridBagConstraints.BOTH;
+		
+		final JLabel label = new JLabel(_bundle.getString("serverName"));
+		this.add(label, cons);
+		
+		_combo = new JComboBox();
+		_combo.setEditable(false);
+		for (Map.Entry<Integer, String> entry : GameServerTable.getInstance().getServerNames().entrySet())
+		{
+			if (!GameServerTable.getInstance().hasRegisteredGameServerOnId(entry.getKey()))
+			{
+				_combo.addItem(new ComboServer(entry.getKey(), entry.getValue()));
+			}
+		}
+		cons.gridx = 1;
+		cons.gridy = 0;
+		this.add(_combo, cons);
+		
+		cons.gridx = 0;
+		cons.gridy = 1;
+		cons.gridwidth = 2;
+		JTextPane textPane = new JTextPane();
+		textPane.setText(_bundle.getString("saveHexId"));
+		textPane.setEditable(false);
+		textPane.setBackground(label.getBackground());
+		this.add(textPane, cons);
+		cons.gridwidth = 1;
+		
+		JButton btnSave = new JButton(_bundle.getString("save"));
+		btnSave.setActionCommand("save");
+		btnSave.addActionListener(this);
+		cons.gridx = 0;
+		cons.gridy = 2;
+		this.add(btnSave, cons);
+		
+		JButton btnCancel = new JButton(_bundle.getString("cancel"));
+		btnCancel.setActionCommand("cancel");
+		btnCancel.addActionListener(this);
+		cons.gridx = 1;
+		cons.gridy = 2;
+		this.add(btnCancel, cons);
+		
+		final double leftSize = Math.max(label.getPreferredSize().getWidth(), btnSave.getPreferredSize().getWidth());
+		final double rightSize = Math.max(_combo.getPreferredSize().getWidth(), btnCancel.getPreferredSize().getWidth());
+		
+		final double height = _combo.getPreferredSize().getHeight()+ 4 * textPane.getPreferredSize().getHeight()+btnSave.getPreferredSize().getHeight();
+		this.setSize((int) (leftSize + rightSize + 30), (int) (height + 20));
+		
+		this.setLocationRelativeTo(owner.getFrame());
+	}
+	
+	class ComboServer
+	{
+		private final int _id;
+		private final String _name;
+
+		public ComboServer(int id, String name)
+		{
+			_id = id;
+			_name = name;
+		}
+
+		/**
+         * @return Returns the id.
+         */
+        public int getId()
+        {
+	        return _id;
+        }
+
+		/**
+         * @return Returns the name.
+         */
+        public String getName()
+        {
+	        return _name;
+        }
+
+		@Override
+        public String toString()
+        {
+	        return this.getName();
+        }
+	}
+
+	/**
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    @Override
+    public void actionPerformed(ActionEvent e)
+    {
+	    String cmd = e.getActionCommand();
+	    
+	    if (cmd.equals("save"))
+	    {
+	    	ComboServer server = (ComboServer) _combo.getSelectedItem();
+	    	int gsId = server.getId();
+	    	
+	    	JFileChooser fc = new JFileChooser();
+	    	//fc.setS
+	    	fc.setDialogTitle(_bundle.getString("hexidDest"));
+	        fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+	    	fc.setFileFilter
+	    	(
+	    		new FileFilter()
+	    		{
+
+					@Override
+                    public boolean accept(File f)
+                    {
+	                    return f.isDirectory();
+                    }
+
+					@Override
+                    public String getDescription()
+                    {
+	                    return null;
+                    }
+	    			
+	    		}
+	    	);
+	    	fc.showOpenDialog(this);
+	    	
+	    	try
+            {
+	            GUserInterface.registerGameServer(gsId, fc.getSelectedFile().getAbsolutePath());
+	            _owner.refreshAsync();
+	            this.setVisible(false);
+            }
+            catch (IOException e1)
+            {
+	            _owner.showError(_bundle.getString("ioErrorRegister"), e1);
+            }
+	    }
+	    else if (cmd.equals("cancel"))
+	    {
+	    	this.setVisible(false);
+	    }
+    }
+}

+ 74 - 0
L2_GameServer/java/net/sf/l2j/i18n/LanguageControl.java

@@ -0,0 +1,74 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.sf.l2j.i18n;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+import java.util.ResourceBundle.Control;
+
+/**
+ *
+ * @author  KenM
+ */
+public class LanguageControl extends Control
+{
+	public static final String LANGUAGES_DIRECTORY = "../languages/";
+	
+	public static final LanguageControl INSTANCE = new LanguageControl();
+	
+	/**
+	 * prevent instancing, allows sub-classing
+	 */
+	protected LanguageControl()
+	{
+		
+	}
+	
+	@Override
+	public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException
+	{
+		if (baseName == null || locale == null || format == null || loader == null)
+		{
+			throw new NullPointerException();
+		}
+		ResourceBundle bundle = null;
+		if (format.equals("java.properties"))
+		{
+			format = "properties";
+			String bundleName = toBundleName(baseName, locale);
+			String resourceName = LANGUAGES_DIRECTORY + toResourceName(bundleName, format);
+			InputStream stream = new FileInputStream(resourceName);
+			if (stream != null)
+			{
+				BufferedInputStream bis = new BufferedInputStream(stream);
+				try
+				{
+					bundle = new PropertyResourceBundle(bis);
+				}
+				finally
+				{
+					bis.close();
+				}
+			}
+		}
+		return bundle;
+	}
+	
+}

+ 48 - 0
L2_GameServer/java/net/sf/l2j/images/ImagesTable.java

@@ -0,0 +1,48 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.sf.l2j.images;
+
+import java.util.Map;
+
+import javax.swing.ImageIcon;
+
+import javolution.util.FastMap;
+
+/**
+ * Usage of this class causes images to be loaded and kept in memory, and therefore should only be used by helper applications.
+ * Some icons from famfamfam (http://www.famfamfam.com/) credit *MUST* be given.
+ * 
+ * @author  KenM
+ */
+public class ImagesTable
+{
+	private static final Map<String, ImageIcon> IMAGES = new FastMap<String, ImageIcon>();
+	
+	public static final String IMAGES_DIRECTORY = "../images/";
+	
+	public static ImageIcon getImage(String name)
+	{
+		if (!IMAGES.containsKey(name))
+		{
+			IMAGES.put(name, new ImageIcon(IMAGES_DIRECTORY+name));
+		}
+		return IMAGES.get(name);
+	}
+	
+	private ImagesTable()
+	{
+		//none
+	}
+}

+ 4 - 1
L2_GameServer/java/net/sf/l2j/loginserver/GameServerTable.java

@@ -30,6 +30,7 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import javolution.io.UTF8StreamReader;
@@ -236,7 +237,7 @@ public class GameServerTable
 		}
 		catch (SQLException e)
 		{
-			_log.warning("SQL error while saving gameserver: " + e);
+			_log.log(Level.SEVERE, "SQL error while saving gameserver.", e);
 		}
 		finally
 		{
@@ -273,7 +274,9 @@ public class GameServerTable
 	private String hexToString(byte[] hex)
 	{
 		if (hex == null)
+		{
 			return "null";
+		}
 		return new BigInteger(hex).toString(16);
 	}
 	

+ 2 - 2
L2_GameServer/java/net/sf/l2j/loginserver/GameServerThread.java

@@ -568,7 +568,7 @@ public class GameServerThread extends Thread
 	 * @param ipAddress
 	 * @return
 	 */
-	public static boolean isBannedGameserverIP(String ipAddress)
+	public static boolean isBannedGameserverIP(@SuppressWarnings("unused") String ipAddress)
 	{
 		// TODO Auto-generated method stub
 		return false;
@@ -724,4 +724,4 @@ public class GameServerThread extends Thread
 		}
 		return -1;
 	}
-}
+}

+ 1 - 1
L2_GameServer/java/net/sf/l2j/loginserver/L2LoginClient.java

@@ -43,7 +43,7 @@ public final class L2LoginClient extends MMOClient<MMOConnection<L2LoginClient>>
 {
 	private static Logger _log = Logger.getLogger(L2LoginClient.class.getName());
 
-	public static enum LoginClientState { CONNECTED, AUTHED_GG, AUTHED_LOGIN}
+	public static enum LoginClientState { CONNECTED, AUTHED_GG, AUTHED_LOGIN};
 
 	private LoginClientState _state;
 

+ 18 - 13
L2_GameServer/java/net/sf/l2j/loginserver/L2LoginServer.java

@@ -25,6 +25,7 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.security.GeneralSecurityException;
 import java.sql.SQLException;
+import java.util.logging.Level;
 import java.util.logging.LogManager;
 import java.util.logging.Logger;
 
@@ -79,6 +80,7 @@ public class L2LoginServer
 		{
 			is = new FileInputStream(new File(LOG_NAME));
 			LogManager.getLogManager().readConfiguration(is);
+			is.close();
 		}
 		catch (IOException e)
 		{
@@ -89,9 +91,12 @@ public class L2LoginServer
 		{
 			try
 			{
-				is.close();
+				if (is != null)
+				{
+					is.close();
+				}
 			}
-			catch (Exception e)
+			catch (IOException e)
 			{
 				e.printStackTrace();
 			}
@@ -107,7 +112,7 @@ public class L2LoginServer
 		}
 		catch (SQLException e)
 		{
-			_log.severe("FATAL: Failed initializing database. Reason: "+e.getMessage());
+			_log.log(Level.SEVERE, "FATAL: Failed initializing database. Reason: "+e.getMessage(), e);
 			if (Config.DEVELOPER)
 			{
 				e.printStackTrace();
@@ -121,7 +126,7 @@ public class L2LoginServer
 		}
 		catch (GeneralSecurityException e)
 		{
-			_log.severe("FATAL: Failed initializing LoginController. Reason: "+e.getMessage());
+			_log.log(Level.SEVERE, "FATAL: Failed initializing LoginController. Reason: "+e.getMessage(), e);
 			if (Config.DEVELOPER)
 			{
 				e.printStackTrace();
@@ -135,7 +140,7 @@ public class L2LoginServer
 		}
 		catch (GeneralSecurityException e)
 		{
-			_log.severe("FATAL: Failed to load GameServerTable. Reason: "+e.getMessage());
+			_log.log(Level.SEVERE, "FATAL: Failed to load GameServerTable. Reason: "+e.getMessage(), e);
 			if (Config.DEVELOPER)
 			{
 				e.printStackTrace();
@@ -144,7 +149,7 @@ public class L2LoginServer
 		}
 		catch (SQLException e)
 		{
-			_log.severe("FATAL: Failed to load GameServerTable. Reason: "+e.getMessage());
+			_log.log(Level.SEVERE, "FATAL: Failed to load GameServerTable. Reason: "+e.getMessage(), e);
 			if (Config.DEVELOPER)
 			{
 				e.printStackTrace();
@@ -161,12 +166,12 @@ public class L2LoginServer
 			{
 				bindAddress = InetAddress.getByName(Config.LOGIN_BIND_ADDRESS);
 			}
-			catch (UnknownHostException e1)
+			catch (UnknownHostException e)
 			{
-				_log.severe("WARNING: The LoginServer bind address is invalid, using all avaliable IPs. Reason: "+e1.getMessage());
+				_log.warning("WARNING: The LoginServer bind address is invalid, using all avaliable IPs. Reason: "+e.getMessage());
 				if (Config.DEVELOPER)
 				{
-					e1.printStackTrace();
+					e.printStackTrace();
 				}
 			}
 		}
@@ -182,7 +187,7 @@ public class L2LoginServer
 		}
 		catch (IOException e)
 		{
-			_log.severe("FATAL: Failed to open Selector. Reason: "+e.getMessage());
+			_log.log(Level.SEVERE, "FATAL: Failed to open Selector. Reason: "+e.getMessage(), e);
 			if (Config.DEVELOPER)
 			{
 				e.printStackTrace();
@@ -198,7 +203,7 @@ public class L2LoginServer
 		}
 		catch (IOException e)
 		{
-			_log.severe("FATAL: Failed to start the Game Server Listener. Reason: "+e.getMessage());
+			_log.log(Level.SEVERE, "FATAL: Failed to start the Game Server Listener. Reason: "+e.getMessage(), e);
 			if (Config.DEVELOPER)
 			{
 				e.printStackTrace();
@@ -215,7 +220,7 @@ public class L2LoginServer
 			}
 			catch (IOException e)
 			{
-				_log.severe("Failed to start the Telnet Server. Reason: "+e.getMessage());
+				_log.warning("Failed to start the Telnet Server. Reason: "+e.getMessage());
 				if (Config.DEVELOPER)
 				{
 					e.printStackTrace();
@@ -233,7 +238,7 @@ public class L2LoginServer
 		}
 		catch (IOException e)
 		{
-			_log.severe("FATAL: Failed to open server socket. Reason: "+e.getMessage());
+			_log.log(Level.SEVERE, "FATAL: Failed to open server socket. Reason: "+e.getMessage(), e);
 			if (Config.DEVELOPER)
 			{
 				e.printStackTrace();

+ 1 - 0
L2_GameServer/java/net/sf/l2j/loginserver/crypt/BlowfishEngine.java

@@ -285,6 +285,7 @@ public class BlowfishEngine
         encrypting = pEncrypting;
         workingKey = key;
         setKey(workingKey);
+        return;
     }
 
     public String getAlgorithmName()

+ 23 - 0
L2_GameServer/languages/configurator/Configurator.properties

@@ -0,0 +1,23 @@
+language = English
+toolName = Server Configuration Tool
+
+success = Configuration saved successfully
+error = Error
+errorReading = Error reading
+errorSaving = Error saving
+reason = Reason:
+yes = Yes
+no = No
+
+fileMenu = File
+exitItem = Exit
+helpMenu = Help
+aboutItem = About
+
+save = Save
+cancel = Cancel
+
+credits = © 2008-2009 L2J Team. All rights reserved.
+language = Language: English
+icons = Icons by http://www.famfamfam.com
+translation = Translation: L2J Team

+ 80 - 0
L2_GameServer/languages/gsregister/GSRegister.properties

@@ -0,0 +1,80 @@
+language = English
+toolName = GS Registering Tool
+
+error = Error
+reason = Reason:
+yes = Yes
+no = No
+
+fileMenu = File
+exitItem = Exit
+helpMenu = Help
+aboutItem = About
+
+btnRemove = Remove
+btnRemoveAll = Remove All
+btnRegister = Register GameServer
+confirmRemoveTitle = Confirm Removal
+confirmRemoveText = Are you sure you want to remove GameServer %d - %s?
+confirmRemoveAllText = Are you sure you want to remove ALL GameServers?
+gsListRetrieveError = There was an error while attempting to retrieve the list of currently registered GameServers.
+
+gsName = GameServer Name
+gsAction = Action
+
+registerGS = Register GameServer
+serverName = Server name:
+save = Save
+cancel = Cancel
+saveHexId = The hexid.txt file should be saved on GameServer's 'configs' folder to properly complete this process.
+hexidDest = Choose hexid file destination folder...
+
+purpose = Allows to register/remove GameServers from LoginServer.
+options = Options:
+fallbackOpt = If during the register operation the specified GameServer ID is in use, an attempt with the first available ID will be made.
+forceOpt = Forces GameServer register operation to overwrite a previous registration on the specified ID, if necessary.
+cmdOpt = Forces this application to run in console mode, even if GUI is supported.
+helpOpt = Shows this help message and exits.
+languageOpt = Attempts to use the language for the specified locale, on failure reverts to auto-detection.
+registerOpt1 = Registers a GameServer on ID <id> and saves the hexid.txt file on <hexid_dest_dir>.
+registerOpt2 = You can provide a negative value for <id> to register under the first available ID.
+registerOpt3 = Nothing is done if <id> is already in use, unless --force or --fallback is used.
+unregisterOpt = Removes the GameServer specified by <id>, use "all" to remove all currently registered GameServers.
+wrongUnregisterArg = wrong argument for GameServer removal, specify a numeric ID or "all" without quotes to remove all.
+noAction = No action to be taken.
+checkingIdInUse = Checking if GameServer ID %d is in use...
+removingGsId = Removing GameServer ID: %d
+forcingRegistration = Forcing registration on ID %d, an existing registration on this ID is being overwritten.
+fallingBack = Trying to register on the first available ID.
+registrationOk = GameServer successfully registered on LoginServer with ID %d.
+unregisterOk = GameServer ID: %d was successfully removed from LoginServer.
+unregisterAllOk = All GameServers were successfully removed.
+noFreeId = There was no free ID available to register.
+sqlErrorRegister = An SQL error occurred while trying to register the GameServer.
+ioErrorRegister = An error saving the hexid file occurred while trying to register the GameServer.
+errorRegister = An error occurred while trying to register the GameServer.
+errorUnregister = An error occurred while trying to remove the GameServer.
+sqlErrorUnregister = An SQL error occurred while trying to remove the GameServer.
+sqlErrorUnregisterAll = An SQL error occurred while trying to remove ALL GameServers.
+noServerNames = No available names for GameServer, verify servername.xml file exists in the LoginServer folder.
+noNameForId = No name for ID: %d
+idIsNotFree = This ID is not available.
+noServerForId = No GameServer is registered on ID: %d
+
+
+cmdMenuRegister = Register GameServer
+cmdMenuListNames = List GameServers Names and IDs
+cmdMenuRemoveGS = Remove GameServer
+cmdMenuRemoveAll = Remove ALL GameServers
+cmdMenuExit = Exit
+yourChoice = Choice:
+invalidChoice = Invalid Choice: %s
+gsInUse = In Use
+gsFree = Free
+enterDesiredId = Enter desired ID:
+
+credits = © 2008-2009 L2J Team. All rights reserved.
+language = Language: English
+icons = Icons by http://www.famfamfam.com
+translation = Translation: L2J Team
+bugReports = Bug Reports: