Merge pull request #1 from magefree/master

Merge main repo with my fork
This commit is contained in:
marthinwurer 2016-01-25 21:34:20 -05:00
commit ecef4838d9
1006 changed files with 28082 additions and 5194 deletions

5
.gitignore vendored
View file

@ -82,6 +82,7 @@ Mage.Server.Plugins/Mage.Draft.8PlayerBooster/target
*.classpath *.classpath
*.iml *.iml
hs_err*.log
/submitted /submitted
/Mage.Server/config/ai.please.cast.this.txt /Mage.Server/config/ai.please.cast.this.txt
@ -92,3 +93,7 @@ Mage.Server.Plugins/Mage.Draft.8PlayerBooster/target
Mage.Client/serverlist.txt Mage.Client/serverlist.txt
/bin/ /bin/
/target/ /target/
client_secrets.json
dependency-reduced-pom.xml

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-root</artifactId> <artifactId>mage-root</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>

View file

@ -1,6 +1,6 @@
XMage.de 1 (Europe/Germany) fast :xmage.de:17171 XMage.de 1 (Europe/Germany) fast :xmage.de:17171
woogerworks (North America/USA) :xmage.woogerworks.info:17171 woogerworks (North America/USA) :xmage.woogerworks.info:17171
XMage.info 1 (Europe/France) new network code -> see forum :176.31.186.181:17171 XMage Testserver (Europe/France) 1.4.8v0 :176.31.186.181:17171
XMage BR (South America/Brazil) :ec2-54-233-67-0.sa-east-1.compute.amazonaws.com:17171 XMage BR (South America/Brazil) :ec2-54-233-67-0.sa-east-1.compute.amazonaws.com:17171
Seedds Server (Asia) :115.29.203.80:17171 Seedds Server (Asia) :115.29.203.80:17171
localhost -> connect to your local server (must be started):localhost:17171 localhost -> connect to your local server (must be started):localhost:17171

View file

@ -107,6 +107,7 @@ import mage.client.draft.DraftPanel;
import mage.client.game.GamePane; import mage.client.game.GamePane;
import mage.client.game.GamePanel; import mage.client.game.GamePanel;
import mage.client.plugins.impl.Plugins; import mage.client.plugins.impl.Plugins;
import mage.client.preference.MagePreferences;
import mage.client.remote.CallbackClientImpl; import mage.client.remote.CallbackClientImpl;
import mage.client.table.TablesPane; import mage.client.table.TablesPane;
import mage.client.tournament.TournamentPane; import mage.client.tournament.TournamentPane;
@ -745,9 +746,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
} }
private boolean performConnect() { private boolean performConnect() {
String userName = prefs.get("userName", ""); String server = MagePreferences.getServerAddress();
String server = prefs.get("serverAddress", ""); int port = MagePreferences.getServerPort();
int port = Integer.parseInt(prefs.get("serverPort", "")); String userName = MagePreferences.getUserName(server);
String password = MagePreferences.getPassword(server);
String proxyServer = prefs.get("proxyAddress", ""); String proxyServer = prefs.get("proxyAddress", "");
int proxyPort = Integer.parseInt(prefs.get("proxyPort", "0")); int proxyPort = Integer.parseInt(prefs.get("proxyPort", "0"));
ProxyType proxyType = ProxyType.valueByText(prefs.get("proxyType", "None")); ProxyType proxyType = ProxyType.valueByText(prefs.get("proxyType", "None"));
@ -757,6 +759,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
setCursor(new Cursor(Cursor.WAIT_CURSOR)); setCursor(new Cursor(Cursor.WAIT_CURSOR));
Connection connection = new Connection(); Connection connection = new Connection();
connection.setUsername(userName); connection.setUsername(userName);
connection.setPassword(password);
connection.setHost(server); connection.setHost(server);
connection.setPort(port); connection.setPort(port);
connection.setProxyType(proxyType); connection.setProxyType(proxyType);

View file

@ -241,8 +241,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
public void event(Event event) { public void event(Event event) {
if (mode.equals(DeckEditorMode.FREE_BUILDING)) { if (mode.equals(DeckEditorMode.FREE_BUILDING)) {
switch (event.getEventName()) { switch (event.getEventName()) {
case "double-click": case "double-click": {
{
SimpleCardView cardView = (SimpleCardView) event.getSource(); SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (card.getId().equals(cardView.getId())) { if (card.getId().equals(cardView.getId())) {
@ -254,8 +253,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
refreshDeck(); refreshDeck();
break; break;
} }
case "alt-double-click": case "alt-double-click": {
{
SimpleCardView cardView = (SimpleCardView) event.getSource(); SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (card.getId().equals(cardView.getId())) { if (card.getId().equals(cardView.getId())) {
@ -268,8 +266,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
refreshDeck(); refreshDeck();
break; break;
} }
case "set-number": case "set-number": {
{
setCardNumberToCardsList(event, deck.getCards()); setCardNumberToCardsList(event, deck.getCards());
} }
} }
@ -277,8 +274,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
// constructing phase or sideboarding during match -> card goes always to sideboard // constructing phase or sideboarding during match -> card goes always to sideboard
switch (event.getEventName()) { switch (event.getEventName()) {
case "double-click": case "double-click":
case "alt-double-click": case "alt-double-click": {
{
SimpleCardView cardView = (SimpleCardView) event.getSource(); SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (card.getId().equals(cardView.getId())) { if (card.getId().equals(cardView.getId())) {
@ -328,8 +324,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
hidePopup(); hidePopup();
refreshDeck(); refreshDeck();
break; break;
case "set-number": case "set-number": {
{
setCardNumberToCardsList(event, deck.getSideboard()); setCardNumberToCardsList(event, deck.getSideboard());
} }
} }
@ -345,7 +340,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
deck.getCards().add(card); deck.getCards().add(card);
break; break;
} }
} hidePopup(); }
hidePopup();
refreshDeck(); refreshDeck();
break; break;
} }
@ -382,7 +378,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
} }
} else { } else {
// remove cards // remove cards
for (Card card: toDelete) { for (Card card : toDelete) {
cards.remove(card); cards.remove(card);
} }
} }
@ -483,7 +479,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
text = text + Integer.toString(second); text = text + Integer.toString(second);
} }
this.txtTimeRemaining.setText(text); this.txtTimeRemaining.setText(text);
if (s==60) { if (s == 60) {
AudioManager.playOnCountdown1(); AudioManager.playOnCountdown1();
} }
} }
@ -611,10 +607,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
.addComponent(lblDeckName) .addComponent(lblDeckName)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtDeckName, javax.swing.GroupLayout.DEFAULT_SIZE, 189, Short.MAX_VALUE)) .addComponent(txtDeckName, javax.swing.GroupLayout.DEFAULT_SIZE, 189, Short.MAX_VALUE))
.addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addComponent(btnSave) .addComponent(btnSave)
@ -697,7 +691,9 @@ public class DeckEditorPanel extends javax.swing.JPanel {
} }
refreshDeck(); refreshDeck();
try { try {
if (file != null) {
MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath()); MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath());
}
} catch (IOException ex) { } catch (IOException ex) {
} }
} }

View file

@ -28,18 +28,13 @@
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="btnConnect" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0"> <Group type="103" groupAlignment="1" attributes="0">
<Component id="lblPort" alignment="1" min="-2" max="-2" attributes="0"/> <Component id="lblPort" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblServer" min="-2" max="-2" attributes="0"/> <Component id="lblServer" min="-2" max="-2" attributes="0"/>
<Component id="lblUserName" min="-2" max="-2" attributes="0"/> <Component id="lblUserName" min="-2" max="-2" attributes="0"/>
<Component id="lblPassword" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Component id="lblFlag" alignment="1" min="-2" max="-2" attributes="0"/> <Component id="lblFlag" alignment="1" min="-2" max="-2" attributes="0"/>
</Group> </Group>
@ -53,14 +48,29 @@
<Component id="txtServer" pref="286" max="32767" attributes="0"/> <Component id="txtServer" pref="286" max="32767" attributes="0"/>
<Component id="txtPort" alignment="0" min="-2" pref="71" max="-2" attributes="0"/> <Component id="txtPort" alignment="0" min="-2" pref="71" max="-2" attributes="0"/>
<Component id="txtUserName" alignment="1" max="32767" attributes="0"/> <Component id="txtUserName" alignment="1" max="32767" attributes="0"/>
<Component id="txtPassword" alignment="1" max="32767" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="btnFind" min="-2" max="-2" attributes="0"/> <Component id="btnFind" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Component id="chkForceUpdateDB" alignment="0" max="32767" attributes="0"/> <Component id="chkForceUpdateDB" alignment="0" max="32767" attributes="0"/>
<Component id="chkAutoConnect" alignment="0" pref="358" max="32767" attributes="0"/> <Component id="chkAutoConnect" alignment="0" pref="375" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="btnRegister" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Component id="btnConnect" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnForgotPassword" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
</Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
@ -85,6 +95,11 @@
<Component id="txtUserName" min="-2" max="-2" attributes="0"/> <Component id="txtUserName" min="-2" max="-2" attributes="0"/>
<Component id="lblUserName" min="-2" max="-2" attributes="0"/> <Component id="lblUserName" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtPassword" min="-2" max="-2" attributes="0"/>
<Component id="lblPassword" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0"> <Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="lblFlag" max="32767" attributes="0"/> <Component id="lblFlag" max="32767" attributes="0"/>
@ -96,13 +111,16 @@
<Component id="chkForceUpdateDB" min="-2" max="-2" attributes="0"/> <Component id="chkForceUpdateDB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="jProxySettingsButton" min="-2" max="-2" attributes="0"/> <Component id="jProxySettingsButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="50" max="32767" attributes="0"/> <EmptySpace pref="38" max="32767" attributes="0"/>
<Component id="lblStatus" min="-2" pref="24" max="-2" attributes="0"/> <Component id="lblStatus" min="-2" pref="24" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="btnConnect" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="btnConnect" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnForgotPassword" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
<Component id="btnRegister" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
@ -152,6 +170,16 @@
</Component> </Component>
<Component class="javax.swing.JTextField" name="txtUserName"> <Component class="javax.swing.JTextField" name="txtUserName">
</Component> </Component>
<Component class="javax.swing.JLabel" name="lblPassword">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtPassword"/>
</Property>
<Property name="text" type="java.lang.String" value="Password:"/>
</Properties>
</Component>
<Component class="javax.swing.JPasswordField" name="txtPassword">
</Component>
<Component class="javax.swing.JLabel" name="lblFlag"> <Component class="javax.swing.JLabel" name="lblFlag">
<Properties> <Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
@ -209,5 +237,23 @@
</Component> </Component>
<Component class="javax.swing.JLabel" name="lblStatus"> <Component class="javax.swing.JLabel" name="lblStatus">
</Component> </Component>
<Component class="javax.swing.JButton" name="btnRegister">
<Properties>
<Property name="text" type="java.lang.String" value="Register new user"/>
<Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;XMage now supports user authentication.&lt;br&gt;Register your account before you log in.&lt;html&gt;"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRegisterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnForgotPassword">
<Properties>
<Property name="text" type="java.lang.String" value="Forgot password"/>
<Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;You can reset your password if you have registered&lt;br&gt;your account with an email address.&lt;/html&gt;"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnForgotPasswordActionPerformed"/>
</Events>
</Component>
</SubComponents> </SubComponents>
</Form> </Form>

View file

@ -56,16 +56,17 @@ import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import mage.client.MageFrame; import mage.client.MageFrame;
import static mage.client.dialog.PreferencesDialog.KEY_CONNECTION_URL_SERVER_LIST; import static mage.client.dialog.PreferencesDialog.KEY_CONNECTION_URL_SERVER_LIST;
import static mage.client.dialog.PreferencesDialog.KEY_CONNECT_AUTO_CONNECT; import static mage.client.dialog.PreferencesDialog.KEY_CONNECT_AUTO_CONNECT;
import static mage.client.dialog.PreferencesDialog.KEY_CONNECT_FLAG; import static mage.client.dialog.PreferencesDialog.KEY_CONNECT_FLAG;
import mage.client.preference.MagePreferences;
import mage.client.util.Config; import mage.client.util.Config;
import mage.client.util.gui.countryBox.CountryItemEditor; import mage.client.util.gui.countryBox.CountryItemEditor;
import mage.remote.Connection; import mage.remote.Connection;
import mage.remote.Connection.ProxyType;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
/** /**
@ -76,6 +77,8 @@ public class ConnectDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(ConnectDialog.class); private static final Logger logger = Logger.getLogger(ConnectDialog.class);
private Connection connection; private Connection connection;
private ConnectTask task; private ConnectTask task;
private RegisterUserDialog registerUserDialog;
private ResetPasswordDialog resetPasswordDialog;
private final ActionListener connectAction = new ActionListener() { private final ActionListener connectAction = new ActionListener() {
@Override @Override
@ -90,15 +93,24 @@ public class ConnectDialog extends MageDialog {
public ConnectDialog() { public ConnectDialog() {
initComponents(); initComponents();
this.txtUserName.addActionListener(connectAction);
this.txtServer.addActionListener(connectAction); this.txtServer.addActionListener(connectAction);
this.txtPort.addActionListener(connectAction); this.txtPort.addActionListener(connectAction);
this.txtUserName.addActionListener(connectAction);
this.txtPassword.addActionListener(connectAction);
registerUserDialog = new RegisterUserDialog(this);
MageFrame.getDesktop().add(registerUserDialog, JLayeredPane.POPUP_LAYER);
resetPasswordDialog = new ResetPasswordDialog(this);
MageFrame.getDesktop().add(resetPasswordDialog, JLayeredPane.POPUP_LAYER);
} }
public void showDialog() { public void showDialog() {
this.txtServer.setText(MageFrame.getPreferences().get("serverAddress", Config.serverName)); String serverAddress = MagePreferences.getServerAddressWithDefault(Config.serverName);
this.txtPort.setText(MageFrame.getPreferences().get("serverPort", Integer.toString(Config.port))); this.txtServer.setText(serverAddress);
this.txtUserName.setText(MageFrame.getPreferences().get("userName", "")); this.txtPort.setText(Integer.toString(MagePreferences.getServerPortWithDefault(Config.port)));
this.txtUserName.setText(MagePreferences.getUserName(serverAddress));
this.txtPassword.setText(MagePreferences.getPassword(serverAddress));
this.chkAutoConnect.setSelected(Boolean.parseBoolean(MageFrame.getPreferences().get(KEY_CONNECT_AUTO_CONNECT, "false"))); this.chkAutoConnect.setSelected(Boolean.parseBoolean(MageFrame.getPreferences().get(KEY_CONNECT_AUTO_CONNECT, "false")));
this.chkForceUpdateDB.setSelected(false); // has always to be set manually to force comparison this.chkForceUpdateDB.setSelected(false); // has always to be set manually to force comparison
@ -117,9 +129,11 @@ public class ConnectDialog extends MageDialog {
} }
private void saveSettings() { private void saveSettings() {
MageFrame.getPreferences().put("serverAddress", txtServer.getText().trim()); String serverAddress = txtServer.getText().trim();
MageFrame.getPreferences().put("serverPort", txtPort.getText().trim()); MagePreferences.setServerAddress(serverAddress);
MageFrame.getPreferences().put("userName", txtUserName.getText().trim()); MagePreferences.setServerPort(Integer.parseInt(txtPort.getText().trim()));
MagePreferences.setUserName(serverAddress, txtUserName.getText().trim());
MagePreferences.setPassword(serverAddress, txtPassword.getText().trim());
MageFrame.getPreferences().put(KEY_CONNECT_AUTO_CONNECT, Boolean.toString(chkAutoConnect.isSelected())); MageFrame.getPreferences().put(KEY_CONNECT_AUTO_CONNECT, Boolean.toString(chkAutoConnect.isSelected()));
} }
@ -139,6 +153,8 @@ public class ConnectDialog extends MageDialog {
txtPort = new javax.swing.JTextField(); txtPort = new javax.swing.JTextField();
lblUserName = new javax.swing.JLabel(); lblUserName = new javax.swing.JLabel();
txtUserName = new javax.swing.JTextField(); txtUserName = new javax.swing.JTextField();
lblPassword = new javax.swing.JLabel();
txtPassword = new javax.swing.JPasswordField();
lblFlag = new javax.swing.JLabel(); lblFlag = new javax.swing.JLabel();
cbFlag = new mage.client.util.gui.countryBox.CountryComboBox(); cbFlag = new mage.client.util.gui.countryBox.CountryComboBox();
chkAutoConnect = new javax.swing.JCheckBox(); chkAutoConnect = new javax.swing.JCheckBox();
@ -147,6 +163,8 @@ public class ConnectDialog extends MageDialog {
btnConnect = new javax.swing.JButton(); btnConnect = new javax.swing.JButton();
btnCancel = new javax.swing.JButton(); btnCancel = new javax.swing.JButton();
lblStatus = new javax.swing.JLabel(); lblStatus = new javax.swing.JLabel();
btnRegister = new javax.swing.JButton();
btnForgotPassword = new javax.swing.JButton();
setTitle("Connect to server"); setTitle("Connect to server");
setNormalBounds(new java.awt.Rectangle(100, 100, 410, 307)); setNormalBounds(new java.awt.Rectangle(100, 100, 410, 307));
@ -175,6 +193,9 @@ public class ConnectDialog extends MageDialog {
lblUserName.setLabelFor(txtUserName); lblUserName.setLabelFor(txtUserName);
lblUserName.setText("User name:"); lblUserName.setText("User name:");
lblPassword.setLabelFor(txtPassword);
lblPassword.setText("Password:");
lblFlag.setLabelFor(txtUserName); lblFlag.setLabelFor(txtUserName);
lblFlag.setText("User flag:"); lblFlag.setText("User flag:");
@ -217,6 +238,22 @@ public class ConnectDialog extends MageDialog {
} }
}); });
btnRegister.setText("Register new user");
btnRegister.setToolTipText("<html>XMage now supports user authentication.<br>Register your account before you log in.<html>");
btnRegister.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnRegisterActionPerformed(evt);
}
});
btnForgotPassword.setText("Forgot password");
btnForgotPassword.setToolTipText("<html>You can reset your password if you have registered<br>your account with an email address.</html>");
btnForgotPassword.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnForgotPasswordActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout); getContentPane().setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
@ -224,17 +261,13 @@ public class ConnectDialog extends MageDialog {
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(btnConnect)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblPort) .addComponent(lblPort)
.addComponent(lblServer) .addComponent(lblServer)
.addComponent(lblUserName)) .addComponent(lblUserName)
.addComponent(lblPassword))
.addComponent(lblFlag, javax.swing.GroupLayout.Alignment.TRAILING)) .addComponent(lblFlag, javax.swing.GroupLayout.Alignment.TRAILING))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -245,11 +278,23 @@ public class ConnectDialog extends MageDialog {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(txtServer, javax.swing.GroupLayout.DEFAULT_SIZE, 286, Short.MAX_VALUE) .addComponent(txtServer, javax.swing.GroupLayout.DEFAULT_SIZE, 286, Short.MAX_VALUE)
.addComponent(txtPort, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(txtPort, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txtUserName)) .addComponent(txtUserName)
.addComponent(txtPassword))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnFind)) .addComponent(btnFind))
.addComponent(chkForceUpdateDB, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(chkForceUpdateDB, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(chkAutoConnect, javax.swing.GroupLayout.DEFAULT_SIZE, 358, Short.MAX_VALUE)))) .addComponent(chkAutoConnect, javax.swing.GroupLayout.DEFAULT_SIZE, 375, Short.MAX_VALUE)))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(btnRegister)
.addGroup(layout.createSequentialGroup()
.addComponent(btnConnect)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnForgotPassword)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel)))
.addGap(26, 26, 26)))
.addContainerGap()) .addContainerGap())
); );
layout.setVerticalGroup( layout.setVerticalGroup(
@ -269,6 +314,10 @@ public class ConnectDialog extends MageDialog {
.addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblUserName)) .addComponent(lblUserName))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblPassword))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(lblFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(lblFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(cbFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addComponent(cbFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
@ -278,12 +327,15 @@ public class ConnectDialog extends MageDialog {
.addComponent(chkForceUpdateDB) .addComponent(chkForceUpdateDB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jProxySettingsButton) .addComponent(jProxySettingsButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 50, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 38, Short.MAX_VALUE)
.addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnConnect) .addComponent(btnConnect)
.addComponent(btnCancel)) .addComponent(btnCancel)
.addComponent(btnForgotPassword))
.addGap(3, 3, 3)
.addComponent(btnRegister)
.addContainerGap()) .addContainerGap())
); );
@ -302,10 +354,6 @@ public class ConnectDialog extends MageDialog {
private void btnConnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnConnectActionPerformed private void btnConnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnConnectActionPerformed
if (txtUserName.getText().isEmpty()) {
JOptionPane.showMessageDialog(rootPane, "Please provide a user name");
return;
}
if (txtServer.getText().trim().isEmpty()) { if (txtServer.getText().trim().isEmpty()) {
JOptionPane.showMessageDialog(rootPane, "Please provide a server address"); JOptionPane.showMessageDialog(rootPane, "Please provide a server address");
return; return;
@ -314,9 +362,14 @@ public class ConnectDialog extends MageDialog {
JOptionPane.showMessageDialog(rootPane, "Please provide a port number"); JOptionPane.showMessageDialog(rootPane, "Please provide a port number");
return; return;
} }
if (txtUserName.getText().isEmpty()) {
JOptionPane.showMessageDialog(rootPane, "Please provide a user name");
return;
}
// txtPassword is not checked here, because authentication might be disabled by the server config.
if (Integer.valueOf(txtPort.getText()) < 1 || Integer.valueOf(txtPort.getText()) > 65535) { if (Integer.valueOf(txtPort.getText()) < 1 || Integer.valueOf(txtPort.getText()) > 65535) {
JOptionPane.showMessageDialog(rootPane, "Invalid port number"); JOptionPane.showMessageDialog(rootPane, "Invalid port number");
txtPort.setText(MageFrame.getPreferences().get("serverPort", Integer.toString(Config.port))); txtPort.setText(Integer.toString(MagePreferences.getServerPortWithDefault(Config.port)));
return; return;
} }
@ -327,30 +380,10 @@ public class ConnectDialog extends MageDialog {
connection.setHost(this.txtServer.getText().trim()); connection.setHost(this.txtServer.getText().trim());
connection.setPort(Integer.valueOf(this.txtPort.getText().trim())); connection.setPort(Integer.valueOf(this.txtPort.getText().trim()));
connection.setUsername(this.txtUserName.getText().trim()); connection.setUsername(this.txtUserName.getText().trim());
connection.setPassword(this.txtPassword.getText().trim());
connection.setForceDBComparison(this.chkForceUpdateDB.isSelected()); connection.setForceDBComparison(this.chkForceUpdateDB.isSelected());
MageFrame.getPreferences().put(KEY_CONNECT_FLAG, ((CountryItemEditor) cbFlag.getEditor()).getImageItem()); MageFrame.getPreferences().put(KEY_CONNECT_FLAG, ((CountryItemEditor) cbFlag.getEditor()).getImageItem());
PreferencesDialog.setProxyInformation(connection);
ProxyType configProxyType = Connection.ProxyType.valueByText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_TYPE, "None"));
if (configProxyType != null) {
connection.setProxyType(configProxyType);
if (!configProxyType.equals(ProxyType.NONE)) {
String host = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_ADDRESS, "");
String port = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_PORT, "");
if (!host.isEmpty() && !port.isEmpty()) {
connection.setProxyHost(host);
connection.setProxyPort(Integer.valueOf(port));
String username = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_USERNAME, "");
connection.setProxyUsername(username);
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_REMEMBER, "false").equals("true")) {
String password = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_PSWD, "");
connection.setProxyPassword(password);
}
} else {
logger.warn("host or\\and port are empty: host=" + host + ", port=" + port);
}
}
}
// pref settings // pref settings
MageFrame.getInstance().setUserPrefsToConnection(connection); MageFrame.getInstance().setUserPrefsToConnection(connection);
@ -514,8 +547,12 @@ public class ConnectDialog extends MageDialog {
if (selectedServer != null) { if (selectedServer != null) {
String[] params = selectedServer.split(":"); String[] params = selectedServer.split(":");
if (params.length == 3) { if (params.length == 3) {
this.txtServer.setText(params[1]); String serverAddress = params[1];
this.txtServer.setText(serverAddress);
this.txtPort.setText(params[2]); this.txtPort.setText(params[2]);
// Update userName and password according to the chosen server.
this.txtUserName.setText(MagePreferences.getUserName(serverAddress));
this.txtPassword.setText(MagePreferences.getPassword(serverAddress));
} else { } else {
JOptionPane.showMessageDialog(null, "Wrong server data format."); JOptionPane.showMessageDialog(null, "Wrong server data format.");
} }
@ -541,19 +578,47 @@ public class ConnectDialog extends MageDialog {
// TODO add your handling code here: // TODO add your handling code here:
}//GEN-LAST:event_chkForceUpdateDBActionPerformed }//GEN-LAST:event_chkForceUpdateDBActionPerformed
private void txtUserNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtUserNameActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_txtUserNameActionPerformed
private void txtPasswordActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtPasswordActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_txtPasswordActionPerformed
private void btnRegisterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRegisterActionPerformed
registerUserDialog.showDialog();
}//GEN-LAST:event_btnRegisterActionPerformed
private void btnForgotPasswordActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnForgotPasswordActionPerformed
resetPasswordDialog.showDialog();
}//GEN-LAST:event_btnForgotPasswordActionPerformed
public String getServer() {
return this.txtServer.getText();
}
public String getPort() {
return this.txtPort.getText();
}
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnCancel; private javax.swing.JButton btnCancel;
private javax.swing.JButton btnConnect; private javax.swing.JButton btnConnect;
private javax.swing.JButton btnFind; private javax.swing.JButton btnFind;
private javax.swing.JButton btnForgotPassword;
private javax.swing.JButton btnRegister;
private mage.client.util.gui.countryBox.CountryComboBox cbFlag; private mage.client.util.gui.countryBox.CountryComboBox cbFlag;
private javax.swing.JCheckBox chkAutoConnect; private javax.swing.JCheckBox chkAutoConnect;
private javax.swing.JCheckBox chkForceUpdateDB; private javax.swing.JCheckBox chkForceUpdateDB;
private javax.swing.JButton jProxySettingsButton; private javax.swing.JButton jProxySettingsButton;
private javax.swing.JLabel lblFlag; private javax.swing.JLabel lblFlag;
private javax.swing.JLabel lblPassword;
private javax.swing.JLabel lblPort; private javax.swing.JLabel lblPort;
private javax.swing.JLabel lblServer; private javax.swing.JLabel lblServer;
private javax.swing.JLabel lblStatus; private javax.swing.JLabel lblStatus;
private javax.swing.JLabel lblUserName; private javax.swing.JLabel lblUserName;
private javax.swing.JPasswordField txtPassword;
private javax.swing.JTextField txtPort; private javax.swing.JTextField txtPort;
private javax.swing.JTextField txtServer; private javax.swing.JTextField txtServer;
private javax.swing.JTextField txtUserName; private javax.swing.JTextField txtUserName;

View file

@ -2298,6 +2298,30 @@ public class PreferencesDialog extends javax.swing.JDialog {
this.repaint(); this.repaint();
} }
public static void setProxyInformation(Connection connection) {
ProxyType configProxyType = Connection.ProxyType.valueByText(getCachedValue(KEY_PROXY_TYPE, "None"));
if (configProxyType == null) {
return;
}
connection.setProxyType(configProxyType);
if (!configProxyType.equals(ProxyType.NONE)) {
String host = getCachedValue(KEY_PROXY_ADDRESS, "");
String port = getCachedValue(KEY_PROXY_PORT, "");
if (!host.isEmpty() && !port.isEmpty()) {
connection.setProxyHost(host);
connection.setProxyPort(Integer.valueOf(port));
String username = getCachedValue(KEY_PROXY_USERNAME, "");
connection.setProxyUsername(username);
if (getCachedValue(KEY_PROXY_REMEMBER, "false").equals("true")) {
String password = getCachedValue(KEY_PROXY_PSWD, "");
connection.setProxyPassword(password);
}
} else {
log.warn("host or\\and port are empty: host=" + host + ", port=" + port);
}
}
}
/** /**
* @param args the command line arguments * @param args the command line arguments
*/ */

View file

@ -0,0 +1,219 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JInternalFrameFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="3"/>
<Property name="title" type="java.lang.String" value="Register"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Group type="103" alignment="0" groupAlignment="1" attributes="0">
<Component id="lblPasswordConfirmationReasoning" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="lblServer" min="-2" max="-2" attributes="0"/>
<Component id="lblUserName" min="-2" max="-2" attributes="0"/>
<Component id="lblPort" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblPassword" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblPasswordConfirmation" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblEmail" alignment="1" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtServer" min="-2" pref="292" max="-2" attributes="0"/>
<Component id="txtPort" min="-2" pref="292" max="-2" attributes="0"/>
<Component id="txtUserName" alignment="0" min="-2" pref="292" max="-2" attributes="0"/>
<Component id="txtPassword" alignment="0" min="-2" pref="292" max="-2" attributes="0"/>
<Component id="txtPasswordConfirmation" alignment="0" min="-2" pref="292" max="-2" attributes="0"/>
<Component id="txtEmail" min="-2" pref="292" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="lblEmailReasoning" alignment="1" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<Component id="btnRegister" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="lblStatus" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace pref="22" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="9" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblServer" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtServer" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblPort" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtPort" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblUserName" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtUserName" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblPassword" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtPassword" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtPasswordConfirmation" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblPasswordConfirmation" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="lblPasswordConfirmationReasoning" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblEmail" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtEmail" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="lblEmailReasoning" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="lblStatus" min="-2" pref="28" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnRegister" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="lblServer">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtServer"/>
</Property>
<Property name="text" type="java.lang.String" value="Server:"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblPort">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtPort"/>
</Property>
<Property name="text" type="java.lang.String" value="Port:"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblUserName">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtUserName"/>
</Property>
<Property name="text" type="java.lang.String" value="User name:"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblPassword">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtPassword"/>
</Property>
<Property name="text" type="java.lang.String" value="Password:"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtUserName">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="txtUserNameActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JPasswordField" name="txtPassword">
</Component>
<Component class="javax.swing.JButton" name="btnRegister">
<Properties>
<Property name="text" type="java.lang.String" value="Register"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRegisterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnCancel">
<Properties>
<Property name="text" type="java.lang.String" value="Cancel"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCancelActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblStatus">
<Properties>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtServer">
</Component>
<Component class="javax.swing.JTextField" name="txtPort">
</Component>
<Component class="javax.swing.JTextField" name="txtEmail">
</Component>
<Component class="javax.swing.JLabel" name="lblPasswordConfirmation">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtPasswordConfirmation"/>
</Property>
<Property name="text" type="java.lang.String" value="Password:"/>
</Properties>
</Component>
<Component class="javax.swing.JPasswordField" name="txtPasswordConfirmation">
</Component>
<Component class="javax.swing.JLabel" name="lblEmail">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtEmail"/>
</Property>
<Property name="text" type="java.lang.String" value="Email:"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblPasswordConfirmationReasoning">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Lucida Grande" size="10" style="0"/>
</Property>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtPasswordConfirmation"/>
</Property>
<Property name="text" type="java.lang.String" value="(confirmation)"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblEmailReasoning">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Lucida Grande" size="10" style="0"/>
</Property>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtEmail"/>
</Property>
<Property name="text" type="java.lang.String" value="(used for password reset)"/>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
</Component>
</SubComponents>
</Form>

View file

@ -0,0 +1,286 @@
package mage.client.dialog;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.swing.SwingWorker;
import mage.client.MageFrame;
import mage.client.preference.MagePreferences;
import mage.remote.Connection;
import mage.remote.Session;
import mage.remote.SessionImpl;
import org.apache.log4j.Logger;
public class RegisterUserDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(ConnectDialog.class);
private ConnectDialog connectDialog;
private Connection connection;
private ConnectTask task;
private Session session;
/**
* Creates new form RegisterUserDialog
*/
public RegisterUserDialog(ConnectDialog connectDialog) {
initComponents();
this.connectDialog = connectDialog;
}
public void showDialog() {
this.txtServer.setText(this.connectDialog.getServer());
this.txtPort.setText(this.connectDialog.getPort());
this.lblStatus.setText("");
this.setModal(true);
this.setLocation(50, 50);
this.setVisible(true);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
lblServer = new javax.swing.JLabel();
lblPort = new javax.swing.JLabel();
lblUserName = new javax.swing.JLabel();
lblPassword = new javax.swing.JLabel();
txtUserName = new javax.swing.JTextField();
txtPassword = new javax.swing.JPasswordField();
btnRegister = new javax.swing.JButton();
btnCancel = new javax.swing.JButton();
lblStatus = new javax.swing.JLabel();
txtServer = new javax.swing.JTextField();
txtPort = new javax.swing.JTextField();
txtEmail = new javax.swing.JTextField();
lblPasswordConfirmation = new javax.swing.JLabel();
txtPasswordConfirmation = new javax.swing.JPasswordField();
lblEmail = new javax.swing.JLabel();
lblPasswordConfirmationReasoning = new javax.swing.JLabel();
lblEmailReasoning = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("Register");
lblServer.setLabelFor(txtServer);
lblServer.setText("Server:");
lblPort.setLabelFor(txtPort);
lblPort.setText("Port:");
lblUserName.setLabelFor(txtUserName);
lblUserName.setText("User name:");
lblPassword.setLabelFor(txtPassword);
lblPassword.setText("Password:");
txtUserName.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtUserNameActionPerformed(evt);
}
});
btnRegister.setText("Register");
btnRegister.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnRegisterActionPerformed(evt);
}
});
btnCancel.setText("Cancel");
btnCancel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCancelActionPerformed(evt);
}
});
lblStatus.setToolTipText("");
lblPasswordConfirmation.setLabelFor(txtPasswordConfirmation);
lblPasswordConfirmation.setText("Password:");
lblEmail.setLabelFor(txtEmail);
lblEmail.setText("Email:");
lblPasswordConfirmationReasoning.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
lblPasswordConfirmationReasoning.setLabelFor(txtPasswordConfirmation);
lblPasswordConfirmationReasoning.setText("(confirmation)");
lblEmailReasoning.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
lblEmailReasoning.setLabelFor(txtEmail);
lblEmailReasoning.setText("(used for password reset)");
lblEmailReasoning.setToolTipText("");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblPasswordConfirmationReasoning)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblServer)
.addComponent(lblUserName)
.addComponent(lblPort)
.addComponent(lblPassword)
.addComponent(lblPasswordConfirmation)
.addComponent(lblEmail))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addComponent(lblEmailReasoning)
.addGroup(layout.createSequentialGroup()
.addComponent(btnRegister)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel)))
.addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(22, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(9, 9, 9)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblServer)
.addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblPort)
.addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblUserName)
.addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblPassword)
.addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblPasswordConfirmation))
.addComponent(lblPasswordConfirmationReasoning)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblEmail)
.addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblEmailReasoning)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnCancel)
.addComponent(btnRegister))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void txtUserNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtUserNameActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_txtUserNameActionPerformed
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
this.hideDialog();
}//GEN-LAST:event_btnCancelActionPerformed
private void btnRegisterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRegisterActionPerformed
if (!this.txtPassword.getText().equals(this.txtPasswordConfirmation.getText())) {
MageFrame.getInstance().showError("Passwords don't match.");
return;
}
connection = new Connection();
connection.setHost(this.txtServer.getText().trim());
connection.setPort(Integer.valueOf(this.txtPort.getText().trim()));
connection.setUsername(this.txtUserName.getText().trim());
connection.setPassword(this.txtPassword.getText().trim());
connection.setEmail(this.txtEmail.getText().trim());
PreferencesDialog.setProxyInformation(connection);
task = new ConnectTask();
task.execute();
}//GEN-LAST:event_btnRegisterActionPerformed
private class ConnectTask extends SwingWorker<Boolean, Void> {
private boolean result = false;
private static final int CONNECTION_TIMEOUT_MS = 2100;
@Override
protected Boolean doInBackground() throws Exception {
lblStatus.setText("Connecting...");
btnRegister.setEnabled(false);
session = new SessionImpl(MageFrame.getInstance());
result = session.register(connection);
return result;
}
@Override
protected void done() {
try {
get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (result) {
// Save settings.
MagePreferences.setServerAddress(connection.getHost());
MagePreferences.setServerPort(connection.getPort());
MagePreferences.setUserName(connection.getHost(), connection.getUsername());
MagePreferences.setPassword(connection.getHost(), connection.getPassword());
MagePreferences.setEmail(connection.getHost(), connection.getEmail());
String message = "Registration succeeded";
lblStatus.setText(message);
MageFrame.getInstance().showMessage(message);
hideDialog();
} else {
lblStatus.setText("Could not register");
}
} catch (InterruptedException | ExecutionException ex) {
logger.fatal("Registration task error", ex);
} catch (CancellationException ex) {
logger.info("Registration was canceled");
lblStatus.setText("Registration was canceled (but an account might have been actually created)");
} catch (TimeoutException ex) {
logger.fatal("Registration timeout: ", ex);
} finally {
MageFrame.stopConnecting();
btnRegister.setEnabled(true);
}
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnCancel;
private javax.swing.JButton btnRegister;
private javax.swing.JLabel lblEmail;
private javax.swing.JLabel lblEmailReasoning;
private javax.swing.JLabel lblPassword;
private javax.swing.JLabel lblPasswordConfirmation;
private javax.swing.JLabel lblPasswordConfirmationReasoning;
private javax.swing.JLabel lblPort;
private javax.swing.JLabel lblServer;
private javax.swing.JLabel lblStatus;
private javax.swing.JLabel lblUserName;
private javax.swing.JTextField txtEmail;
private javax.swing.JPasswordField txtPassword;
private javax.swing.JPasswordField txtPasswordConfirmation;
private javax.swing.JTextField txtPort;
private javax.swing.JTextField txtServer;
private javax.swing.JTextField txtUserName;
// End of variables declaration//GEN-END:variables
}

View file

@ -0,0 +1,320 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JInternalFrameFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="3"/>
<Property name="title" type="java.lang.String" value="Reset password"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jPanel2" alignment="1" max="32767" attributes="0"/>
<Component id="jPanel1" alignment="0" max="32767" attributes="0"/>
<Component id="lblStatus" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="lblServer" min="-2" max="-2" attributes="0"/>
<Component id="lblPort" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtServer" max="32767" attributes="0"/>
<Component id="txtPort" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblServer" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtServer" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtPort" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblPort" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="jPanel1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jPanel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblStatus" min="-2" pref="28" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel2">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="jLabel6" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="lblAuthToken" alignment="1" min="-2" pref="74" max="-2" attributes="0"/>
<Component id="lblPassword" alignment="0" max="32767" attributes="0"/>
<Component id="lblPasswordConfirmation" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtAuthToken" max="32767" attributes="0"/>
<Component id="txtPassword" alignment="0" max="32767" attributes="0"/>
<Component id="txtPasswordConfirmation" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="204" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblPasswordConfirmationReasoning" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="btnSubmitNewPassword" alignment="1" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel6" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblAuthToken" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtAuthToken" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblPassword" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtPassword" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblPasswordConfirmation" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtPasswordConfirmation" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblPasswordConfirmationReasoning" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="btnSubmitNewPassword" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="9" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel6">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Lucida Grande" size="13" style="1"/>
</Property>
<Property name="text" type="java.lang.String" value="Step 2:"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblAuthToken">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtAuthToken"/>
</Property>
<Property name="text" type="java.lang.String" value="Auth token:"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblPassword">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtPassword"/>
</Property>
<Property name="text" type="java.lang.String" value="New password:"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblPasswordConfirmation">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtPasswordConfirmation"/>
</Property>
<Property name="text" type="java.lang.String" value="New password:"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtAuthToken">
</Component>
<Component class="javax.swing.JButton" name="btnSubmitNewPassword">
<Properties>
<Property name="text" type="java.lang.String" value="Submit a new password"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnSubmitNewPasswordActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblPasswordConfirmationReasoning">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Lucida Grande" size="10" style="0"/>
</Property>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtPasswordConfirmation"/>
</Property>
<Property name="text" type="java.lang.String" value="(confirmation)"/>
</Properties>
</Component>
<Component class="javax.swing.JPasswordField" name="txtPassword">
</Component>
<Component class="javax.swing.JPasswordField" name="txtPasswordConfirmation">
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="jPanel1">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel5" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" attributes="0">
<Component id="lblEmail" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txtEmail" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="btnGetAuthToken" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel5" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblEmail" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtEmail" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="btnGetAuthToken" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel5">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Lucida Grande" size="13" style="1"/>
</Property>
<Property name="text" type="java.lang.String" value="Step 1:"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblEmail">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtEmail"/>
</Property>
<Property name="text" type="java.lang.String" value="Email:"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtEmail">
</Component>
<Component class="javax.swing.JButton" name="btnGetAuthToken">
<Properties>
<Property name="text" type="java.lang.String" value="Email an auth token"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnGetAuthTokenActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="lblStatus">
</Component>
<Component class="javax.swing.JButton" name="btnCancel">
<Properties>
<Property name="text" type="java.lang.String" value="Cancel"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCancelActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblServer">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtServer"/>
</Property>
<Property name="text" type="java.lang.String" value="Server:"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txtServer">
</Component>
<Component class="javax.swing.JTextField" name="txtPort">
</Component>
<Component class="javax.swing.JLabel" name="lblPort">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="txtPort"/>
</Property>
<Property name="text" type="java.lang.String" value="Port:"/>
</Properties>
</Component>
</SubComponents>
</Form>

View file

@ -0,0 +1,431 @@
package mage.client.dialog;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.swing.SwingWorker;
import mage.client.MageFrame;
import mage.client.preference.MagePreferences;
import mage.remote.Connection;
import mage.remote.Session;
import mage.remote.SessionImpl;
import org.apache.log4j.Logger;
public class ResetPasswordDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(ResetPasswordDialog.class);
private ConnectDialog connectDialog;
private Connection connection;
private Session session;
private GetAuthTokenTask getAuthTokenTask;
private ResetPasswordTask resetPasswordTask;
/**
* Creates new form ResetPasswordDialog
*/
public ResetPasswordDialog(ConnectDialog connectDialog) {
initComponents();
this.connectDialog = connectDialog;
}
public void showDialog() {
String serverAddress = this.connectDialog.getServer();
this.txtServer.setText(serverAddress);
this.txtPort.setText(this.connectDialog.getPort());
this.txtEmail.setText(MagePreferences.getEmail(serverAddress));
this.lblStatus.setText("");
this.setModal(true);
this.setLocation(50, 50);
this.setVisible(true);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jPanel2 = new javax.swing.JPanel();
jLabel6 = new javax.swing.JLabel();
lblAuthToken = new javax.swing.JLabel();
lblPassword = new javax.swing.JLabel();
lblPasswordConfirmation = new javax.swing.JLabel();
txtAuthToken = new javax.swing.JTextField();
btnSubmitNewPassword = new javax.swing.JButton();
lblPasswordConfirmationReasoning = new javax.swing.JLabel();
txtPassword = new javax.swing.JPasswordField();
txtPasswordConfirmation = new javax.swing.JPasswordField();
jPanel1 = new javax.swing.JPanel();
jLabel5 = new javax.swing.JLabel();
lblEmail = new javax.swing.JLabel();
txtEmail = new javax.swing.JTextField();
btnGetAuthToken = new javax.swing.JButton();
lblStatus = new javax.swing.JLabel();
btnCancel = new javax.swing.JButton();
lblServer = new javax.swing.JLabel();
txtServer = new javax.swing.JTextField();
txtPort = new javax.swing.JTextField();
lblPort = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("Reset password");
jPanel2.setBorder(javax.swing.BorderFactory.createEtchedBorder());
jLabel6.setFont(new java.awt.Font("Lucida Grande", 1, 13)); // NOI18N
jLabel6.setText("Step 2:");
lblAuthToken.setLabelFor(txtAuthToken);
lblAuthToken.setText("Auth token:");
lblPassword.setLabelFor(txtPassword);
lblPassword.setText("New password:");
lblPasswordConfirmation.setLabelFor(txtPasswordConfirmation);
lblPasswordConfirmation.setText("New password:");
btnSubmitNewPassword.setText("Submit a new password");
btnSubmitNewPassword.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnSubmitNewPasswordActionPerformed(evt);
}
});
lblPasswordConfirmationReasoning.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
lblPasswordConfirmationReasoning.setLabelFor(txtPasswordConfirmation);
lblPasswordConfirmationReasoning.setText("(confirmation)");
javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addComponent(jLabel6)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(lblAuthToken, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblPassword, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lblPasswordConfirmation, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(txtAuthToken)
.addComponent(txtPassword)
.addComponent(txtPasswordConfirmation)))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
.addGap(0, 204, Short.MAX_VALUE)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblPasswordConfirmationReasoning, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(btnSubmitNewPassword, javax.swing.GroupLayout.Alignment.TRAILING))))
.addContainerGap())
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addComponent(jLabel6)
.addGap(24, 24, 24)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblAuthToken)
.addComponent(txtAuthToken, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblPassword)
.addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblPasswordConfirmation)
.addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblPasswordConfirmationReasoning)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(btnSubmitNewPassword)
.addContainerGap(9, Short.MAX_VALUE))
);
jPanel1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
jLabel5.setFont(new java.awt.Font("Lucida Grande", 1, 13)); // NOI18N
jLabel5.setText("Step 1:");
lblEmail.setLabelFor(txtEmail);
lblEmail.setText("Email:");
btnGetAuthToken.setText("Email an auth token");
btnGetAuthToken.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnGetAuthTokenActionPerformed(evt);
}
});
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(jLabel5)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(lblEmail)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtEmail))
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(btnGetAuthToken)))
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(jLabel5)
.addGap(24, 24, 24)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblEmail)
.addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btnGetAuthToken)
.addContainerGap())
);
btnCancel.setText("Cancel");
btnCancel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCancelActionPerformed(evt);
}
});
lblServer.setLabelFor(txtServer);
lblServer.setText("Server:");
lblPort.setLabelFor(txtPort);
lblPort.setText("Port:");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(btnCancel))
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblServer)
.addComponent(lblPort))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(txtServer)
.addComponent(txtPort))))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblServer)
.addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblPort))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void btnGetAuthTokenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGetAuthTokenActionPerformed
if (this.txtEmail.getText().length() == 0) {
MageFrame.getInstance().showError("Please enter an email address.");
return;
}
connection = new Connection();
connection.setHost(this.txtServer.getText().trim());
connection.setPort(Integer.valueOf(this.txtPort.getText().trim()));
PreferencesDialog.setProxyInformation(connection);
connection.setEmail(this.txtEmail.getText().trim());
getAuthTokenTask = new GetAuthTokenTask();
getAuthTokenTask.execute();
}//GEN-LAST:event_btnGetAuthTokenActionPerformed
private void btnSubmitNewPasswordActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSubmitNewPasswordActionPerformed
if (this.txtEmail.getText().length() == 0) {
MageFrame.getInstance().showError("Please enter an email address.");
return;
}
if (this.txtAuthToken.getText().length() == 0) {
MageFrame.getInstance().showError("Please enter an auth token.");
return;
}
if (this.txtPassword.getText().length() == 0) {
MageFrame.getInstance().showError("Please enter a new password.");
return;
}
if (!this.txtPassword.getText().equals(this.txtPasswordConfirmation.getText())) {
MageFrame.getInstance().showError("Passwords don't match.");
return;
}
connection = new Connection();
connection.setHost(this.txtServer.getText().trim());
connection.setPort(Integer.valueOf(this.txtPort.getText().trim()));
PreferencesDialog.setProxyInformation(connection);
connection.setEmail(this.txtEmail.getText().trim());
connection.setAuthToken(this.txtAuthToken.getText().trim());
connection.setPassword(this.txtPassword.getText().trim());
resetPasswordTask = new ResetPasswordTask();
resetPasswordTask.execute();
}//GEN-LAST:event_btnSubmitNewPasswordActionPerformed
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
this.hideDialog();
}//GEN-LAST:event_btnCancelActionPerformed
void disableButtons() {
btnGetAuthToken.setEnabled(false);
btnSubmitNewPassword.setEnabled(false);
}
void enableButtons() {
btnGetAuthToken.setEnabled(true);
btnSubmitNewPassword.setEnabled(true);
}
private class GetAuthTokenTask extends SwingWorker<Boolean, Void> {
private boolean result = false;
private static final int CONNECTION_TIMEOUT_MS = 2100;
@Override
protected Boolean doInBackground() throws Exception {
lblStatus.setText("Connecting...");
disableButtons();
session = new SessionImpl(MageFrame.getInstance());
result = session.emailAuthToken(connection);
return result;
}
@Override
protected void done() {
try {
get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (result) {
// Save settings.
MagePreferences.setEmail(connection.getHost(), connection.getEmail());
String message = "Auth token is emailed. Please check your inbox.";
lblStatus.setText(message);
MageFrame.getInstance().showMessage(message);
} else {
lblStatus.setText("There was an issue while requesting an auth token.");
}
} catch (InterruptedException | ExecutionException ex) {
logger.fatal("Get Auth Token Task error", ex);
} catch (CancellationException ex) {
logger.info("Canceled");
lblStatus.setText("Canceled");
} catch (TimeoutException ex) {
logger.fatal("Timeout: ", ex);
} finally {
MageFrame.stopConnecting();
enableButtons();
}
}
}
private class ResetPasswordTask extends SwingWorker<Boolean, Void> {
private boolean result = false;
private static final int CONNECTION_TIMEOUT_MS = 2100;
@Override
protected Boolean doInBackground() throws Exception {
lblStatus.setText("Connecting...");
disableButtons();
session = new SessionImpl(MageFrame.getInstance());
result = session.resetPassword(connection);
return result;
}
@Override
protected void done() {
try {
get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (result) {
// Save settings.
MagePreferences.setPassword(connection.getHost(), connection.getPassword());
String message = "Password is reset successfully.";
lblStatus.setText(message);
MageFrame.getInstance().showMessage(message);
hideDialog();
} else {
lblStatus.setText("There was an issue while resetting password.");
}
} catch (InterruptedException | ExecutionException ex) {
logger.fatal("Reset Password Task error", ex);
} catch (CancellationException ex) {
logger.info("Canceled");
lblStatus.setText("Canceled");
} catch (TimeoutException ex) {
logger.fatal("Timeout: ", ex);
} finally {
MageFrame.stopConnecting();
enableButtons();
}
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnCancel;
private javax.swing.JButton btnGetAuthToken;
private javax.swing.JButton btnSubmitNewPassword;
private javax.swing.JLabel jLabel5;
private javax.swing.JLabel jLabel6;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JLabel lblAuthToken;
private javax.swing.JLabel lblEmail;
private javax.swing.JLabel lblPassword;
private javax.swing.JLabel lblPasswordConfirmation;
private javax.swing.JLabel lblPasswordConfirmationReasoning;
private javax.swing.JLabel lblPort;
private javax.swing.JLabel lblServer;
private javax.swing.JLabel lblStatus;
private javax.swing.JTextField txtAuthToken;
private javax.swing.JTextField txtEmail;
private javax.swing.JPasswordField txtPassword;
private javax.swing.JPasswordField txtPasswordConfirmation;
private javax.swing.JTextField txtPort;
private javax.swing.JTextField txtServer;
// End of variables declaration//GEN-END:variables
}

View file

@ -26,7 +26,7 @@
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
/* /*
* TableWaitingDialog.java * TableWaitingDialog.java
* *
* Created on Dec 16, 2009, 10:27:44 AM * Created on Dec 16, 2009, 10:27:44 AM
@ -68,7 +68,7 @@ public class TableWaitingDialog extends MageDialog {
private Session session; private Session session;
private final TableWaitModel tableWaitModel; private final TableWaitModel tableWaitModel;
private UpdateSeatsTask updateTask; private UpdateSeatsTask updateTask;
private static final int[] defaultColumnsWidth = {20, 50, 100, 100}; private static final int[] defaultColumnsWidth = {20, 50, 100, 100, 100};
/** /**
* Creates new form TableWaitingDialog * Creates new form TableWaitingDialog
@ -268,11 +268,9 @@ public class TableWaitingDialog extends MageDialog {
if (session.startMatch(roomId, tableId)) { if (session.startMatch(roomId, tableId)) {
closeDialog(); closeDialog();
} }
} else { } else if (session.startTournament(roomId, tableId)) {
if (session.startTournament(roomId, tableId)) {
closeDialog(); closeDialog();
} }
}
}//GEN-LAST:event_btnStartActionPerformed }//GEN-LAST:event_btnStartActionPerformed
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
@ -319,7 +317,7 @@ public class TableWaitingDialog extends MageDialog {
class TableWaitModel extends AbstractTableModel { class TableWaitModel extends AbstractTableModel {
private final String[] columnNames = new String[]{"Seat", "Loc", "Player Name", "Player Type"}; private final String[] columnNames = new String[]{"Seat", "Loc", "Player Name", "Player Type", "History"};
private SeatView[] seats = new SeatView[0]; private SeatView[] seats = new SeatView[0];
public void loadData(TableView table) { public void loadData(TableView table) {
@ -353,6 +351,8 @@ class TableWaitModel extends AbstractTableModel {
return seats[arg0].getPlayerName(); return seats[arg0].getPlayerName();
case 3: case 3:
return seats[arg0].getPlayerType(); return seats[arg0].getPlayerType();
case 4:
return seats[arg0].getHistory();
} }
} }
return ""; return "";

View file

@ -26,7 +26,7 @@
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
/* /*
* PlayerPanel.java * PlayerPanel.java
* *
* Created on Nov 18, 2009, 3:01:31 PM * Created on Nov 18, 2009, 3:01:31 PM
@ -288,7 +288,8 @@ public class PlayerPanelExt extends javax.swing.JPanel {
basicTooltipText = "<HTML>Name: " + player.getName() basicTooltipText = "<HTML>Name: " + player.getName()
+ "<br/>Country: " + countryname + "<br/>Country: " + countryname
+ "<br/>Deck hash code: " + player.getDeckHashCode() + "<br/>Deck hash code: " + player.getDeckHashCode()
+ "<br/>Wins: " + player.getWins() + " of " + player.getWinsNeeded() + " (to win the match)"; + "<br/>This match wins: " + player.getWins() + " of " + player.getWinsNeeded() + " (to win the match)"
+ (player.getUserData() == null ? "" : "<br/>History: " + player.getUserData().getHistory());
} }
// Extend tooltip // Extend tooltip
StringBuilder tooltipText = new StringBuilder(basicTooltipText); StringBuilder tooltipText = new StringBuilder(basicTooltipText);
@ -580,7 +581,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
manaCountLabelX.setText("0"); manaCountLabelX.setText("0");
manaLabels.put("X", manaCountLabelX); manaLabels.put("X", manaCountLabelX);
r = new Rectangle(12, 12); r = new Rectangle(12, 12);
BufferedImage imageManaX = ManaSymbols.getManaSymbolImageSmall("X"); BufferedImage imageManaX = ManaSymbols.getManaSymbolImageSmall("C");
HoverButton btnColorlessMana = new HoverButton(null, imageManaX, imageManaX, imageManaX, r); HoverButton btnColorlessMana = new HoverButton(null, imageManaX, imageManaX, imageManaX, r);
btnColorlessMana.setToolTipText("Colorless mana"); btnColorlessMana.setToolTipText("Colorless mana");
btnColorlessMana.setOpaque(false); btnColorlessMana.setOpaque(false);

View file

@ -0,0 +1,85 @@
package mage.client.preference;
import java.util.prefs.Preferences;
import mage.client.MageFrame;
// TODO: Move all preference related logic from MageFrame and PreferencesDialog to this class.
public class MagePreferences {
private static final String KEY_SERVER_ADDRESS = "serverAddress";
private static final String KEY_SERVER_PORT = "serverPort";
private static final String KEY_USER_NAME = "userName";
private static final String KEY_PASSWORD = "password";
private static final String KEY_EMAIL = "email";
private static final String KEY_AUTO_CONNECT = "autoConnect";
private static Preferences prefs() {
// TODO: Move MageFrame.prefs to this class.
return MageFrame.getPreferences();
}
public static String getServerAddress() {
return prefs().get(KEY_SERVER_ADDRESS, "");
}
public static String getServerAddressWithDefault(String defaultValue) {
return prefs().get(KEY_SERVER_ADDRESS, defaultValue);
}
public static void setServerAddress(String serverAddress) {
prefs().put(KEY_SERVER_ADDRESS, serverAddress);
}
public static int getServerPort() {
return prefs().getInt(KEY_SERVER_PORT, 0);
}
public static int getServerPortWithDefault(int defaultValue) {
return prefs().getInt(KEY_SERVER_PORT, defaultValue);
}
public static void setServerPort(int port) {
prefs().putInt(KEY_SERVER_PORT, port);
}
private static String prefixedKey(String prefix, String key) {
return prefix + "/" + key;
}
public static String getUserName(String serverAddress) {
String userName = prefs().get(prefixedKey(serverAddress, KEY_USER_NAME), "");
if (!userName.isEmpty()) {
return userName;
}
// For clients older than 1.4.7, userName is stored without a serverAddress prefix.
return prefs().get(KEY_USER_NAME, "");
}
public static void setUserName(String serverAddress, String userName) {
prefs().put(prefixedKey(serverAddress, KEY_USER_NAME), userName);
}
public static String getPassword(String serverAddress) {
return prefs().get(prefixedKey(serverAddress, KEY_PASSWORD), "");
}
public static void setPassword(String serverAddress, String password) {
prefs().put(prefixedKey(serverAddress, KEY_PASSWORD), password);
}
public static String getEmail(String serverAddress) {
return prefs().get(prefixedKey(serverAddress, KEY_EMAIL), "");
}
public static void setEmail(String serverAddress, String userName) {
prefs().put(prefixedKey(serverAddress, KEY_EMAIL), userName);
}
public static boolean getAutoConnect() {
return prefs().getBoolean(KEY_AUTO_CONNECT, false);
}
public static void setAutoConnect(boolean autoConnect) {
prefs().putBoolean(KEY_AUTO_CONNECT, autoConnect);
}
}

View file

@ -26,7 +26,7 @@
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
/* /*
* ChatPanel.java * ChatPanel.java
* *
* Created on 15-Dec-2009, 11:04:31 PM * Created on 15-Dec-2009, 11:04:31 PM
@ -61,7 +61,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
private final List<String> players = new ArrayList<>(); private final List<String> players = new ArrayList<>();
private final UserTableModel userTableModel; private final UserTableModel userTableModel;
private static final int[] defaultColumnsWidth = {20, 100, 100, 80, 80}; private static final int[] DEFAULT_COLUMNS_WIDTH = {20, 100, 100, 80, 80};
/* /*
@ -78,7 +78,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
jTablePlayers.setForeground(Color.white); jTablePlayers.setForeground(Color.white);
jTablePlayers.setRowSorter(new MageTableRowSorter(userTableModel)); jTablePlayers.setRowSorter(new MageTableRowSorter(userTableModel));
TableUtil.setColumnWidthAndOrder(jTablePlayers, defaultColumnsWidth, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER); TableUtil.setColumnWidthAndOrder(jTablePlayers, DEFAULT_COLUMNS_WIDTH, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER);
jTablePlayers.setDefaultRenderer(Icon.class, new CountryCellRenderer()); jTablePlayers.setDefaultRenderer(Icon.class, new CountryCellRenderer());
jScrollPaneTalk.setSystemMessagesPane(colorPaneSystem); jScrollPaneTalk.setSystemMessagesPane(colorPaneSystem);
@ -118,7 +118,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
class UserTableModel extends AbstractTableModel { class UserTableModel extends AbstractTableModel {
private final String[] columnNames = new String[]{"Loc", "Players", "Info", "Games", "Connection"}; private final String[] columnNames = new String[]{"Loc", "Players", "History", "Games", "Connection"};
private UsersView[] players = new UsersView[0]; private UsersView[] players = new UsersView[0];
public void loadData(Collection<RoomUsersView> roomUserInfoList) throws MageRemoteException { public void loadData(Collection<RoomUsersView> roomUserInfoList) throws MageRemoteException {
@ -154,7 +154,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
case 1: case 1:
return players[arg0].getUserName(); return players[arg0].getUserName();
case 2: case 2:
return players[arg0].getInfoState(); return players[arg0].getHistory();
case 3: case 3:
return players[arg0].getInfoGames(); return players[arg0].getInfoGames();
case 4: case 4:

View file

@ -1,31 +1,30 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.client.util; package mage.client.util;
import java.awt.Component; import java.awt.Component;
@ -78,64 +77,64 @@ public class ButtonColumn extends AbstractCellEditor implements TableCellRendere
@Override @Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (hasFocus) if (hasFocus) {
{
renderButton.setForeground(table.getForeground()); renderButton.setForeground(table.getForeground());
renderButton.setBackground(UIManager.getColor("Button.background")); renderButton.setBackground(UIManager.getColor("Button.background"));
} } else if (isSelected) {
else if (isSelected)
{
renderButton.setForeground(table.getSelectionForeground()); renderButton.setForeground(table.getSelectionForeground());
renderButton.setBackground(table.getSelectionBackground()); renderButton.setBackground(table.getSelectionBackground());
} } else {
else
{
renderButton.setForeground(table.getForeground()); renderButton.setForeground(table.getForeground());
renderButton.setBackground(UIManager.getColor("Button.background")); renderButton.setBackground(UIManager.getColor("Button.background"));
} }
renderButton.setText( (value == null) ? "" : value.toString() ); renderButton.setText((value == null) ? "" : value.toString());
return renderButton; return renderButton;
} }
@Override @Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
text = (value == null) ? "" : value.toString(); text = (value == null) ? "" : value.toString();
editButton.setText( text ); editButton.setText(text);
return editButton; return editButton;
} }
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
int row = table.convertRowIndexToModel( table.getEditingRow() ); if (table.getRowCount() >= table.getEditingRow()) {
int row = table.convertRowIndexToModel(table.getEditingRow());
fireEditingStopped(); fireEditingStopped();
ActionEvent event = new ActionEvent(table, ActionEvent.ACTION_PERFORMED, "" + row); ActionEvent event = new ActionEvent(table, ActionEvent.ACTION_PERFORMED, "" + row);
action.actionPerformed(event); action.actionPerformed(event);
}
} }
@Override @Override
public void mousePressed(MouseEvent arg0) { public void mousePressed(MouseEvent arg0) {
if (table.isEditing() && table.getCellEditor() == this) if (table.isEditing() && table.getCellEditor() == this) {
isButtonColumnEditor = true; isButtonColumnEditor = true;
} }
}
@Override @Override
public void mouseReleased(MouseEvent arg0) { public void mouseReleased(MouseEvent arg0) {
if (isButtonColumnEditor && table.isEditing()) if (isButtonColumnEditor && table.isEditing()) {
table.getCellEditor().stopCellEditing(); table.getCellEditor().stopCellEditing();
}
isButtonColumnEditor = false; isButtonColumnEditor = false;
} }
@Override @Override
public void mouseClicked(MouseEvent arg0) {} public void mouseClicked(MouseEvent arg0) {
}
@Override @Override
public void mouseEntered(MouseEvent arg0) {} public void mouseEntered(MouseEvent arg0) {
}
@Override @Override
public void mouseExited(MouseEvent arg0) {} public void mouseExited(MouseEvent arg0) {
}
} }

View file

@ -1,14 +1,9 @@
package org.mage.card.arcane; package org.mage.card.arcane;
import mage.cards.repository.ExpansionRepository; import java.awt.Dimension;
import mage.client.dialog.PreferencesDialog; import java.awt.Graphics;
import mage.client.util.ImageHelper; import java.awt.Image;
import mage.client.util.gui.BufferedImageBuilder; import java.awt.Rectangle;
import org.apache.log4j.Logger;
import org.mage.plugins.card.constants.Constants;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.util.HashMap; import java.util.HashMap;
@ -16,6 +11,13 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import mage.cards.repository.ExpansionRepository;
import mage.client.dialog.PreferencesDialog;
import mage.client.util.ImageHelper;
import mage.client.util.gui.BufferedImageBuilder;
import org.apache.log4j.Logger;
import org.mage.plugins.card.constants.Constants;
public class ManaSymbols { public class ManaSymbols {
@ -30,7 +32,7 @@ public class ManaSymbols {
public static void loadImages() { public static void loadImages() {
String[] symbols = new String[]{"0", "1", "10", "11", "12", "15", "16", "2", "3", "4", "5", "6", "7", "8", "9", "B", "BG", String[] symbols = new String[]{"0", "1", "10", "11", "12", "15", "16", "2", "3", "4", "5", "6", "7", "8", "9", "B", "BG",
"BR", "G", "GU", "GW", "R", "RG", "RW", "S", "T", "U", "UB", "UR", "W", "WB", "WU", "BR", "G", "GU", "GW", "R", "RG", "RW", "S", "T", "U", "UB", "UR", "W", "WB", "WU",
"WP", "UP", "BP", "RP", "GP", "X" /*, "Y", "Z", "slash"*/}; "WP", "UP", "BP", "RP", "GP", "X", "C" /*, "Y", "Z", "slash"*/};
for (String symbol : symbols) { for (String symbol : symbols) {
File file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_MANA_MEDIUM + "/" + symbol + ".jpg"); File file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_MANA_MEDIUM + "/" + symbol + ".jpg");
@ -198,6 +200,7 @@ public class ManaSymbols {
} }
public enum Type { public enum Type {
CARD, CARD,
TOOLTIP, TOOLTIP,
PAY PAY

View file

@ -3,10 +3,8 @@
* *
* Created on 25.08.2010 * Created on 25.08.2010
*/ */
package org.mage.plugins.card.dl; package org.mage.plugins.card.dl;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@ -21,7 +19,6 @@ import org.mage.plugins.card.dl.beans.properties.Property;
import org.mage.plugins.card.dl.lm.AbstractLaternaBean; import org.mage.plugins.card.dl.lm.AbstractLaternaBean;
import org.mage.plugins.card.utils.CardImageUtils; import org.mage.plugins.card.utils.CardImageUtils;
/** /**
* The class DownloadJob. * The class DownloadJob.
* *
@ -29,7 +26,9 @@ import org.mage.plugins.card.utils.CardImageUtils;
* @author Clemens Koza * @author Clemens Koza
*/ */
public class DownloadJob extends AbstractLaternaBean { public class DownloadJob extends AbstractLaternaBean {
public static enum State { public static enum State {
NEW, WORKING, FINISHED, ABORTED; NEW, WORKING, FINISHED, ABORTED;
} }
@ -48,7 +47,9 @@ public class DownloadJob extends AbstractLaternaBean {
} }
/** /**
* Sets the job's state. If the state is {@link State#ABORTED}, it instead sets the error to "ABORTED" * Sets the job's state. If the state is {@link State#ABORTED}, it instead
* sets the error to "ABORTED"
*
* @param state * @param state
*/ */
public void setState(State state) { public void setState(State state) {
@ -60,8 +61,9 @@ public class DownloadJob extends AbstractLaternaBean {
} }
/** /**
* Sets the job's state to {@link State#ABORTED} and the error message to the given message. Logs a warning * Sets the job's state to {@link State#ABORTED} and the error message to
* with the given message. * the given message. Logs a warning with the given message.
*
* @param message * @param message
*/ */
public void setError(String message) { public void setError(String message) {
@ -69,8 +71,9 @@ public class DownloadJob extends AbstractLaternaBean {
} }
/** /**
* Sets the job's state to {@link State#ABORTED} and the error to the given exception. Logs a warning with the * Sets the job's state to {@link State#ABORTED} and the error to the given
* given exception. * exception. Logs a warning with the given exception.
*
* @param error * @param error
*/ */
public void setError(Exception error) { public void setError(Exception error) {
@ -78,8 +81,9 @@ public class DownloadJob extends AbstractLaternaBean {
} }
/** /**
* Sets the job's state to {@link State#ABORTED} and the error to the given exception. Logs a warning with the * Sets the job's state to {@link State#ABORTED} and the error to the given
* given message and exception. * exception. Logs a warning with the given message and exception.
*
* @param message * @param message
* @param error * @param error
*/ */
@ -97,6 +101,7 @@ public class DownloadJob extends AbstractLaternaBean {
/** /**
* Sets the job's message. * Sets the job's message.
*
* @param message * @param message
*/ */
public void setMessage(String message) { public void setMessage(String message) {
@ -119,7 +124,6 @@ public class DownloadJob extends AbstractLaternaBean {
return message.getValue(); return message.getValue();
} }
public String getName() { public String getName() {
return name; return name;
} }
@ -163,7 +167,7 @@ public class DownloadJob extends AbstractLaternaBean {
@Override @Override
public String toString() { public String toString() {
return proxy != null ? proxy.type().toString()+" " :"" + url; return proxy != null ? proxy.type().toString() + " " : "" + url;
} }
}; };
@ -192,7 +196,7 @@ public class DownloadJob extends AbstractLaternaBean {
@Override @Override
public String toString() { public String toString() {
return proxy != null ? proxy.type().toString()+" " :"" + url; return proxy != null ? proxy.type().toString() + " " : "" + url;
} }
}; };
} }
@ -213,6 +217,14 @@ public class DownloadJob extends AbstractLaternaBean {
return new FileOutputStream(file); return new FileOutputStream(file);
} }
@Override
public boolean isValid() throws IOException {
if (file.isFile()) {
return file.length() > 0;
}
return false;
}
@Override @Override
public boolean exists() { public boolean exists() {
return file.isFile(); return file.isFile();
@ -228,16 +240,20 @@ public class DownloadJob extends AbstractLaternaBean {
} }
public interface Source { public interface Source {
InputStream open() throws IOException; InputStream open() throws IOException;
int length() throws IOException; int length() throws IOException;
} }
public interface Destination { public interface Destination {
OutputStream open() throws IOException; OutputStream open() throws IOException;
boolean exists() throws IOException; boolean exists() throws IOException;
boolean isValid() throws IOException;
void delete() throws IOException; void delete() throws IOException;
} }
} }

View file

@ -3,7 +3,6 @@
* *
* Created on 25.08.2010 * Created on 25.08.2010
*/ */
package org.mage.plugins.card.dl; package org.mage.plugins.card.dl;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
@ -29,7 +28,6 @@ import org.mage.plugins.card.dl.DownloadJob.Source;
import org.mage.plugins.card.dl.DownloadJob.State; import org.mage.plugins.card.dl.DownloadJob.State;
import org.mage.plugins.card.dl.lm.AbstractLaternaBean; import org.mage.plugins.card.dl.lm.AbstractLaternaBean;
/** /**
* The class Downloader. * The class Downloader.
* *
@ -49,7 +47,7 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
public Downloader() { public Downloader() {
PoolFiberFactory f = new PoolFiberFactory(pool); PoolFiberFactory f = new PoolFiberFactory(pool);
//subscribe multiple fibers for parallel execution //subscribe multiple fibers for parallel execution
for(int i = 0, numThreads = 10; i < numThreads; i++) { for (int i = 0, numThreads = 10; i < numThreads; i++) {
Fiber fiber = f.create(); Fiber fiber = f.create();
fiber.start(); fiber.start();
fibers.add(fiber); fibers.add(fiber);
@ -59,15 +57,15 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
@Override @Override
public void dispose() { public void dispose() {
for(DownloadJob j:getJobs()) { for (DownloadJob j : getJobs()) {
switch(j.getState()) { switch (j.getState()) {
case NEW: case NEW:
case WORKING: case WORKING:
j.setState(State.ABORTED); j.setState(State.ABORTED);
} }
} }
for(Fiber f:fibers) { for (Fiber f : fibers) {
f.dispose(); f.dispose();
} }
pool.shutdown(); pool.shutdown();
@ -84,10 +82,10 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
} }
public void add(DownloadJob job) { public void add(DownloadJob job) {
if(job.getState() == State.WORKING) { if (job.getState() == State.WORKING) {
throw new IllegalArgumentException("Job already running"); throw new IllegalArgumentException("Job already running");
} }
if(job.getState() == State.FINISHED) { if (job.getState() == State.FINISHED) {
throw new IllegalArgumentException("Job already finished"); throw new IllegalArgumentException("Job already finished");
} }
job.setState(State.NEW); job.setState(State.NEW);
@ -100,15 +98,17 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
} }
/** /**
* Performs the download job: Transfers data from {@link Source} to {@link Destination} and updates the * Performs the download job: Transfers data from {@link Source} to
* download job's state to reflect the progress. * {@link Destination} and updates the download job's state to reflect the
* progress.
*/ */
private class DownloadCallback implements Callback<DownloadJob> { private class DownloadCallback implements Callback<DownloadJob> {
@Override @Override
public void onMessage(DownloadJob job) { public void onMessage(DownloadJob job) {
//the job won't be processed by multiple threads //the job won't be processed by multiple threads
synchronized(job) { synchronized (job) {
if(job.getState() != State.NEW) { if (job.getState() != State.NEW) {
return; return;
} }
job.setState(State.WORKING); job.setState(State.WORKING);
@ -118,10 +118,17 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
Destination dst = job.getDestination(); Destination dst = job.getDestination();
BoundedRangeModel progress = job.getProgress(); BoundedRangeModel progress = job.getProgress();
if(dst.exists()) { if (dst.isValid()) {
progress.setMaximum(1); progress.setMaximum(1);
progress.setValue(1); progress.setValue(1);
} else { } else {
if (dst.exists()) {
try {
dst.delete();
} catch (IOException ex1) {
logger.warn("While deleting not valid file", ex1);
}
}
progress.setMaximum(src.length()); progress.setMaximum(src.length());
InputStream is = new BufferedInputStream(src.open()); InputStream is = new BufferedInputStream(src.open());
try { try {
@ -129,45 +136,45 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
try { try {
byte[] buf = new byte[8 * 1024]; byte[] buf = new byte[8 * 1024];
int total = 0; int total = 0;
for(int len; (len = is.read(buf)) != -1;) { for (int len; (len = is.read(buf)) != -1;) {
if(job.getState() == State.ABORTED) { if (job.getState() == State.ABORTED) {
throw new IOException("Job was aborted"); throw new IOException("Job was aborted");
} }
progress.setValue(total += len); progress.setValue(total += len);
os.write(buf, 0, len); os.write(buf, 0, len);
} }
} catch(IOException ex) { } catch (IOException ex) {
try { try {
dst.delete(); dst.delete();
} catch(IOException ex1) { } catch (IOException ex1) {
logger.warn("While deleting", ex1); logger.warn("While deleting", ex1);
} }
throw ex; throw ex;
} finally { } finally {
try { try {
os.close(); os.close();
} catch(IOException ex) { } catch (IOException ex) {
logger.warn("While closing", ex); logger.warn("While closing", ex);
} }
} }
} finally { } finally {
try { try {
is.close(); is.close();
} catch(IOException ex) { } catch (IOException ex) {
logger.warn("While closing", ex); logger.warn("While closing", ex);
} }
} }
} }
job.setState(State.FINISHED); job.setState(State.FINISHED);
} catch(ConnectException ex) { } catch (ConnectException ex) {
String message; String message;
if (ex.getMessage() != null) { if (ex.getMessage() != null) {
message = ex.getMessage(); message = ex.getMessage();
} else { } else {
message = "Unknown error"; message = "Unknown error";
} }
logger.warn("Error resource download " + job.getName() +" from "+ job.getSource().toString() + ": " + message); logger.warn("Error resource download " + job.getName() + " from " + job.getSource().toString() + ": " + message);
} catch(IOException ex) { } catch (IOException ex) {
job.setError(ex); job.setError(ex);
} }
} }

View file

@ -89,6 +89,8 @@ public class MythicspoilerComSource implements CardImageSource {
cardNameAliases.put("BFZ-unisonstrike", "tandemtactics"); cardNameAliases.put("BFZ-unisonstrike", "tandemtactics");
cardNameAliases.put("BFZ-eldrazidevastator", "eldrazidevastator"); cardNameAliases.put("BFZ-eldrazidevastator", "eldrazidevastator");
cardNameAliases.put("BFZ-kozliekschanneler", "kozilekschanneler"); cardNameAliases.put("BFZ-kozliekschanneler", "kozilekschanneler");
cardNameAliases.put("OGW-wastes", "wastes1");
cardNameAliases.put("OGW-wastes2", "wastes2");
cardNameAliasesStart = new HashMap<>(); cardNameAliasesStart = new HashMap<>();
HashSet<String> names = new HashSet<>(); HashSet<String> names = new HashSet<>();
@ -156,16 +158,18 @@ public class MythicspoilerComSource implements CardImageSource {
if (cardName != null && !cardName.isEmpty()) { if (cardName != null && !cardName.isEmpty()) {
if (cardNameAliases.containsKey(cardSet + "-" + cardName)) { if (cardNameAliases.containsKey(cardSet + "-" + cardName)) {
cardName = cardNameAliases.get(cardSet + "-" + cardName); cardName = cardNameAliases.get(cardSet + "-" + cardName);
} } else {
if (cardName.endsWith("1") || cardName.endsWith("2") || cardName.endsWith("3") || cardName.endsWith("4") || cardName.endsWith("5")) { if (cardName.endsWith("1") || cardName.endsWith("2") || cardName.endsWith("3") || cardName.endsWith("4") || cardName.endsWith("5")) {
if (!cardName.startsWith("forest") if (!cardName.startsWith("forest")
&& !cardName.startsWith("swamp") && !cardName.startsWith("swamp")
&& !cardName.startsWith("mountain") && !cardName.startsWith("mountain")
&& !cardName.startsWith("island") && !cardName.startsWith("island")
&& !cardName.startsWith("plains")) { && !cardName.startsWith("plains")) {
cardName = cardName.substring(0, cardName.length() - 1); cardName = cardName.substring(0, cardName.length() - 1);
} }
} }
}
setLinks.put(cardName, baseUrl + cardLink); setLinks.put(cardName, baseUrl + cardLink);
} }
} }
@ -203,7 +207,8 @@ public class MythicspoilerComSource implements CardImageSource {
} }
@Override @Override
public String generateTokenUrl(CardDownloadData card) { public String generateTokenUrl(CardDownloadData card
) {
return null; return null;
} }

View file

@ -616,7 +616,9 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
new TFile(temporaryFile).cp_rp(outputFile); new TFile(temporaryFile).cp_rp(outputFile);
} }
} else { } else {
logger.warn("Image download for " + card.getName() + "(" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString()); logger.warn("Image download for " + card.getName()
+ (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "")
+ "(" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString());
if (logger.isDebugEnabled()) { // Shows the returned html from the request to the web server if (logger.isDebugEnabled()) { // Shows the returned html from the request to the web server
logger.debug("Return ed HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream())); logger.debug("Return ed HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
} }

View file

@ -1,6 +1,14 @@
#Generate|TOK:OGW|Elemental|| |Generate}TOK:OGW|Angel||
#Generate|TOK:OGW|Plant|| |Generate|TOK:OGW|Elemental|1|
#Generate|TOK:OGW|Zombie|| |Generate|TOK:OGW|Elemental|2|
|Generate}TOK:OGW|Eldrazi Scion|1|
|Generate}TOK:OGW|Eldrazi Scion|2|
|Generate}TOK:OGW|Eldrazi Scion|3|
|Generate}TOK:OGW|Eldrazi Scion|4|
|Generate}TOK:OGW|Eldrazi Scion|5|
|Generate}TOK:OGW|Eldrazi Scion|6|
|Generate|TOK:OGW|Plant||
|Generate|TOK:OGW|Zombie||
#|Generate|TOK:DDQ|Angel|| #|Generate|TOK:DDQ|Angel||

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-root</artifactId> <artifactId>mage-root</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-common</artifactId> <artifactId>mage-common</artifactId>

View file

@ -55,10 +55,21 @@ import mage.view.UserView;
*/ */
public interface MageServer { public interface MageServer {
// registers a user to the user DB.
boolean registerUser(String sessionId, String userName, String password, String email) throws MageException;
boolean emailAuthToken(String sessionId, String email) throws MageException;
boolean resetPassword(String sessionId, String email, String authToken, String password) throws MageException;
// connection methods // connection methods
// DEPRECATED - Use connectUser instead. This is only kept for older clients.
// This can be deleted once users transitioned to newer clients (1.4.6v1 and later).
boolean registerClient(String userName, String sessionId, MageVersion version) throws MageException; boolean registerClient(String userName, String sessionId, MageVersion version) throws MageException;
boolean registerAdmin(String password, String sessionId, MageVersion version) throws MageException; boolean connectUser(String userName, String password, String sessionId, MageVersion version) throws MageException;
boolean connectAdmin(String password, String sessionId, MageVersion version) throws MageException;
// Not used // Not used
// void deregisterClient(String sessionId) throws MageException; // void deregisterClient(String sessionId) throws MageException;

View file

@ -45,6 +45,9 @@ public class Connection {
private int port; private int port;
private String username; private String username;
private String password; private String password;
private String email;
private String authToken;
private String adminPassword;
private ProxyType proxyType; private ProxyType proxyType;
private String proxyHost; private String proxyHost;
private int proxyPort; private int proxyPort;
@ -172,6 +175,30 @@ public class Connection {
this.password = password; this.password = password;
} }
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAuthToken() {
return authToken;
}
public void setAuthToken(String authToken) {
this.authToken = authToken;
}
public String getAdminPassword() {
return adminPassword;
}
public void setAdminPassword(String adminPassword) {
this.adminPassword = adminPassword;
}
public String getProxyHost() { public String getProxyHost() {
return proxyHost; return proxyHost;
} }

View file

@ -122,14 +122,147 @@ public class SessionImpl implements Session {
return sessionId; return sessionId;
} }
@Override // RemotingTask encapsulates a task which is involved with some JBoss Remoting. This is
public synchronized boolean connect(Connection connection) { // intended to be used with handleRemotingTaskExceptions for sharing the common exception
if (isConnected()) { // handling.
disconnect(true); public interface RemotingTask {
public boolean run() throws Throwable;
} }
this.connection = connection;
this.canceled = false; // handleRemotingTaskExceptions runs the given task and handles exceptions appropriately. This
return connect(); // way we can share the common exception handling.
private boolean handleRemotingTaskExceptions(RemotingTask remoting) {
try {
return remoting.run();
} catch (MalformedURLException ex) {
logger.fatal("", ex);
client.showMessage("Unable to connect to server. " + ex.getMessage());
} catch (UndeclaredThrowableException ex) {
String addMessage = "";
Throwable cause = ex.getCause();
if (cause instanceof InvocationFailureException) {
InvocationFailureException exep = (InvocationFailureException) cause;
if (exep.getCause() instanceof IOException) {
if (exep.getCause().getMessage().startsWith("Field hash null is not available on current")) {
addMessage = "Probabaly the server version is not compatible to the client. ";
}
}
} else if (cause instanceof NoSuchMethodException) {
// NoSuchMethodException is thrown on an invocation of an unknow JBoss remoting
// method, so it's likely to be because of a version incompatibility.
addMessage = "The following method is not available in the server, probably the " +
"server version is not compatible to the client: " + cause.getMessage();
}
if (addMessage.isEmpty()) {
logger.fatal("", ex);
}
client.showMessage("Unable to connect to server. " + addMessage + (ex.getMessage() != null ? ex.getMessage() : ""));
} catch (IOException ex) {
logger.fatal("", ex);
String addMessage = "";
if (ex.getMessage() != null && ex.getMessage().startsWith("Unable to perform invocation")) {
addMessage = "Maybe the server version is not compatible. ";
}
client.showMessage("Unable to connect to server. " + addMessage + ex.getMessage() != null ? ex.getMessage() : "");
} catch (MageVersionException ex) {
if (!canceled) {
client.showMessage("Unable to connect to server. " + ex.getMessage());
}
disconnect(false);
} catch (CannotConnectException ex) {
if (!canceled) {
handleCannotConnectException(ex);
}
} catch (Throwable t) {
logger.fatal("Unable to connect to server - ", t);
if (!canceled) {
disconnect(false);
StringBuilder sb = new StringBuilder();
sb.append("Unable to connect to server.\n");
for (StackTraceElement element : t.getStackTrace()) {
sb.append(element.toString()).append("\n");
}
client.showMessage(sb.toString());
}
}
return false;
}
@Override
public synchronized boolean register(final Connection connection) {
return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() {
@Override
public boolean run() throws Throwable {
logger.info("Trying to register as " + getUserName() + " to XMAGE server at " + connection.getHost() + ":" + connection.getPort());
boolean registerResult = server.registerUser(sessionId, connection.getUsername(),
connection.getPassword(), connection.getEmail());
if (registerResult) {
logger.info("Registered as " + getUserName() + " to MAGE server at " + connection.getHost() + ":" + connection.getPort());
}
return registerResult;
}
});
}
@Override
public synchronized boolean emailAuthToken(final Connection connection) {
return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() {
@Override
public boolean run() throws Throwable {
logger.info("Trying to ask for an auth token to " + getEmail() + " to XMAGE server at " + connection.getHost() + ":" + connection.getPort());
boolean result = server.emailAuthToken(sessionId, connection.getEmail());
if (result) {
logger.info("An auth token is emailed to " + getEmail() + " from MAGE server at " + connection.getHost() + ":" + connection.getPort());
}
return result;
}
});
}
@Override
public synchronized boolean resetPassword(final Connection connection) {
return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() {
@Override
public boolean run() throws Throwable {
logger.info("Trying reset the password in XMAGE server at " + connection.getHost() + ":" + connection.getPort());
boolean result = server.resetPassword(sessionId, connection.getEmail(), connection.getAuthToken(), connection.getPassword());
if (result) {
logger.info("Password is successfully reset in MAGE server at " + connection.getHost() + ":" + connection.getPort());
}
return result;
}
});
}
@Override
public synchronized boolean connect(final Connection connection) {
return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() {
@Override
public boolean run() throws Throwable {
logger.info("Trying to log-in as " + getUserName() + " to XMAGE server at " + connection.getHost() + ":" + connection.getPort());
boolean registerResult;
if (connection.getAdminPassword() == null) {
// for backward compatibility. don't remove twice call - first one does nothing but for version checking
registerResult = server.connectUser(connection.getUsername(), connection.getPassword(), sessionId, client.getVersion());
if (registerResult) {
server.setUserData(connection.getUsername(), sessionId, connection.getUserData());
}
} else {
registerResult = server.connectAdmin(connection.getAdminPassword(), sessionId, client.getVersion());
}
if (registerResult) {
serverState = server.getServerState();
if (!connection.getUsername().equals("Admin")) {
updateDatabase(connection.isForceDBComparison(), serverState);
}
logger.info("Logged-in as " + getUserName() + " to MAGE server at " + connection.getHost() + ":" + connection.getPort());
client.connected(getUserName() + "@" + connection.getHost() + ":" + connection.getPort() + " ");
return true;
}
disconnect(false);
return false;
}
});
} }
@Override @Override
@ -138,10 +271,18 @@ public class SessionImpl implements Session {
return true; return true;
} }
@Override private boolean establishJBossRemotingConnection(final Connection connection) {
public boolean connect() { if (isConnected()) {
disconnect(true);
}
this.connection = connection;
this.canceled = false;
sessionState = SessionState.CONNECTING; sessionState = SessionState.CONNECTING;
try { boolean result = handleRemotingTaskExceptions(new RemotingTask() {
@Override
public boolean run() throws Throwable {
logger.info("Trying to connect to XMAGE server at " + connection.getHost() + ":" + connection.getPort());
System.setProperty("http.nonProxyHosts", "code.google.com"); System.setProperty("http.nonProxyHosts", "code.google.com");
System.setProperty("socksNonProxyHosts", "code.google.com"); System.setProperty("socksNonProxyHosts", "code.google.com");
@ -273,77 +414,18 @@ public class SessionImpl implements Session {
logger.warn("There should be one callback Connector (number existing = " + callbackConnectors.size() + ")"); logger.warn("There should be one callback Connector (number existing = " + callbackConnectors.size() + ")");
} }
logger.info("Trying to connect as " + (this.getUserName() == null ? "" : this.getUserName()) + " to XMAGE server at " + connection.getHost() + ":" + connection.getPort());
callbackClient.invoke(null); callbackClient.invoke(null);
this.sessionId = callbackClient.getSessionId(); sessionId = callbackClient.getSessionId();
boolean registerResult;
if (connection.getPassword() == null) {
// for backward compatibility. don't remove twice call - first one does nothing but for version checking
registerResult = server.registerClient(connection.getUsername(), sessionId, client.getVersion());
if (registerResult) {
server.setUserData(connection.getUsername(), sessionId, connection.getUserData());
}
} else {
registerResult = server.registerAdmin(connection.getPassword(), sessionId, client.getVersion());
}
if (registerResult) {
sessionState = SessionState.CONNECTED; sessionState = SessionState.CONNECTED;
serverState = server.getServerState(); logger.info("Connected to MAGE server at " + connection.getHost() + ":" + connection.getPort());
if (!connection.getUsername().equals("Admin")) { return true;
updateDatabase(connection.isForceDBComparison(), serverState);
} }
logger.info("Connected as " + (this.getUserName() == null ? "" : this.getUserName()) + " to MAGE server at " + connection.getHost() + ":" + connection.getPort()); });
client.connected(this.getUserName() == null ? "" : this.getUserName() + "@" + connection.getHost() + ":" + connection.getPort() + " "); if (result) {
return true; return true;
} }
disconnect(false); disconnect(false);
// client.showMessage("Unable to connect to server.");
} catch (MalformedURLException ex) {
logger.fatal("", ex);
client.showMessage("Unable to connect to server. " + ex.getMessage());
} catch (UndeclaredThrowableException ex) {
String addMessage = "";
if (ex.getCause() instanceof InvocationFailureException) {
InvocationFailureException exep = (InvocationFailureException) ex.getCause();
if (exep.getCause() instanceof IOException) {
if (exep.getCause().getMessage().startsWith("Field hash null is not available on current")) {
addMessage = "Probabaly the server version is not compatible to the client. ";
}
}
}
if (addMessage.isEmpty()) {
logger.fatal("", ex);
}
client.showMessage("Unable to connect to server. " + addMessage + (ex.getMessage() != null ? ex.getMessage() : ""));
} catch (IOException ex) {
logger.fatal("", ex);
String addMessage = "";
if (ex.getMessage() != null && ex.getMessage().startsWith("Unable to perform invocation")) {
addMessage = "Maybe the server version is not compatible. ";
}
client.showMessage("Unable to connect to server. " + addMessage + ex.getMessage() != null ? ex.getMessage() : "");
} catch (MageVersionException ex) {
if (!canceled) {
client.showMessage("Unable to connect to server. " + ex.getMessage());
}
disconnect(false);
} catch (CannotConnectException ex) {
if (!canceled) {
handleCannotConnectException(ex);
}
} catch (Throwable t) {
logger.fatal("Unable to connect to server - ", t);
if (!canceled) {
disconnect(false);
StringBuilder sb = new StringBuilder();
sb.append("Unable to connect to server.\n");
for (StackTraceElement element : t.getStackTrace()) {
sb.append(element.toString()).append("\n");
}
client.showMessage(sb.toString());
}
}
return false; return false;
} }
@ -1389,7 +1471,18 @@ public class SessionImpl implements Session {
@Override @Override
public String getUserName() { public String getUserName() {
return connection.getUsername(); String username = connection.getUsername();
return username == null ? "" : username;
}
private String getEmail() {
String email = connection.getEmail();
return email == null ? "" : email;
}
private String getAuthToken() {
String authToken = connection.getAuthToken();
return authToken == null ? "" : authToken;
} }
@Override @Override

View file

@ -34,12 +34,16 @@ import mage.remote.Connection;
*/ */
public interface Connect { public interface Connect {
boolean register(Connection connection);
boolean emailAuthToken(Connection connection);
boolean resetPassword(Connection connection);
boolean connect(Connection connection); boolean connect(Connection connection);
boolean stopConnecting(); boolean stopConnecting();
boolean connect();
void disconnect(boolean showMessage); void disconnect(boolean showMessage);
void reconnect(Throwable throwable); void reconnect(Throwable throwable);

View file

@ -40,7 +40,7 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
*/ */
public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MAJOR = 1;
public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_MINOR = 4;
public final static int MAGE_VERSION_PATCH = 6; public final static int MAGE_VERSION_PATCH = 8;
public final static String MAGE_VERSION_MINOR_PATCH = "v0"; public final static String MAGE_VERSION_MINOR_PATCH = "v0";
public final static String MAGE_VERSION_INFO = ""; public final static String MAGE_VERSION_INFO = "";

View file

@ -1,43 +1,42 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.view; package mage.view;
import java.io.Serializable;
import mage.ConditionalMana; import mage.ConditionalMana;
import mage.players.ManaPool; import mage.players.ManaPool;
import java.io.Serializable;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public class ManaPoolView implements Serializable { public class ManaPoolView implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private int red; private int red;

View file

@ -44,6 +44,7 @@ public class SeatView implements Serializable {
private UUID playerId; private UUID playerId;
private final String playerName; private final String playerName;
private final String playerType; private final String playerType;
private final String history;
public SeatView(Seat seat) { public SeatView(Seat seat) {
if (seat.getPlayer() != null) { if (seat.getPlayer() != null) {
@ -51,13 +52,16 @@ public class SeatView implements Serializable {
this.playerName = seat.getPlayer().getName(); this.playerName = seat.getPlayer().getName();
if (seat.getPlayer().getUserData() == null) { if (seat.getPlayer().getUserData() == null) {
this.flagName = UserData.getDefaultFlagName(); this.flagName = UserData.getDefaultFlagName();
this.history = "";
} else { } else {
this.flagName = seat.getPlayer().getUserData().getFlagName(); this.flagName = seat.getPlayer().getUserData().getFlagName();
this.history = seat.getPlayer().getUserData().getHistory();
} }
} else { } else {
// Empty seat // Empty seat
this.playerName = ""; this.playerName = "";
this.flagName = ""; this.flagName = "";
this.history = "";
} }
this.playerType = seat.getPlayerType(); this.playerType = seat.getPlayerType();
} }
@ -78,4 +82,8 @@ public class SeatView implements Serializable {
return flagName; return flagName;
} }
public String getHistory() {
return history;
}
} }

View file

@ -24,7 +24,7 @@
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.view; package mage.view;
import java.io.Serializable; import java.io.Serializable;
@ -39,14 +39,14 @@ public class UsersView implements Serializable {
private final String flagName; private final String flagName;
private final String userName; private final String userName;
private final String infoState; private final String history;
private final String infoGames; private final String infoGames;
private final String infoPing; private final String infoPing;
public UsersView(String flagName, String userName, String infoState, String infoGames, String infoPing) { public UsersView(String flagName, String userName, String history, String infoGames, String infoPing) {
this.flagName = flagName; this.flagName = flagName;
this.history = history;
this.userName = userName; this.userName = userName;
this.infoState = infoState;
this.infoGames = infoGames; this.infoGames = infoGames;
this.infoPing = infoPing; this.infoPing = infoPing;
} }
@ -59,8 +59,8 @@ public class UsersView implements Serializable {
return userName; return userName;
} }
public String getInfoState() { public String getHistory() {
return infoState; return history;
} }
public String getInfoGames() { public String getInfoGames() {

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-plugins</artifactId> <artifactId>mage-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-counter-plugin</artifactId> <artifactId>mage-counter-plugin</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-root</artifactId> <artifactId>mage-root</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-plugins</artifactId> <artifactId>mage-plugins</artifactId>

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-root</artifactId> <artifactId>mage-root</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>

View file

@ -413,7 +413,7 @@ public class ConnectDialog extends JDialog {
connection = new Connection(); connection = new Connection();
connection.setHost(this.txtServer.getText()); connection.setHost(this.txtServer.getText());
connection.setPort(Integer.valueOf(this.txtPort.getText())); connection.setPort(Integer.valueOf(this.txtPort.getText()));
connection.setPassword(new String(txtPassword.getPassword())); connection.setAdminPassword(new String(txtPassword.getPassword()));
connection.setUsername("Admin"); connection.setUsername("Admin");
connection.setProxyType((ProxyType) this.cbProxyType.getSelectedItem()); connection.setProxyType((ProxyType) this.cbProxyType.getSelectedItem());
if (!this.cbProxyType.getSelectedItem().equals(ProxyType.NONE)) { if (!this.cbProxyType.getSelectedItem().equals(ProxyType.NONE)) {

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-deck-constructed</artifactId> <artifactId>mage-deck-constructed</artifactId>

View file

@ -74,6 +74,7 @@ public class Commander extends DeckValidator {
banned.add("Painter's Servant"); banned.add("Painter's Servant");
banned.add("Panoptic Mirror"); banned.add("Panoptic Mirror");
banned.add("Primeval Titan"); banned.add("Primeval Titan");
banned.add("Prophet of Kruphix");
banned.add("Protean Hulk"); banned.add("Protean Hulk");
banned.add("Recurring Nightmare"); banned.add("Recurring Nightmare");
banned.add("Rofellos, Llanowar Emissary"); banned.add("Rofellos, Llanowar Emissary");
@ -103,7 +104,7 @@ public class Commander extends DeckValidator {
valid = false; valid = false;
} }
List<String> basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", List<String> basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes",
"Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains")); "Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains"));
Map<String, Integer> counts = new HashMap<>(); Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards()); countCards(counts, deck.getCards());
@ -130,22 +131,22 @@ public class Commander extends DeckValidator {
invalid.put("Commander", "Commander invalid "); invalid.put("Commander", "Commander invalid ");
return false; return false;
} }
if ((commander.getCardType().contains(CardType.CREATURE) && commander.getSupertype().contains("Legendary")) || if ((commander.getCardType().contains(CardType.CREATURE) && commander.getSupertype().contains("Legendary"))
(commander.getCardType().contains(CardType.PLANESWALKER) && commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) { || (commander.getCardType().contains(CardType.PLANESWALKER) && commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) {
if (!bannedCommander.contains(commander.getName())) { if (!bannedCommander.contains(commander.getName())) {
FilterMana color = CardUtil.getColorIdentity(commander); FilterMana color = CardUtil.getColorIdentity(commander);
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (!cardHasValidColor(color, card)) { if (!cardHasValidColor(color, card)) {
invalid.put(card.getName(), "Invalid color (" + commander.getName() +")"); invalid.put(card.getName(), "Invalid color (" + commander.getName() + ")");
valid = false; valid = false;
} }
} }
} else { } else {
invalid.put("Commander", "Commander banned (" + commander.getName() +")"); invalid.put("Commander", "Commander banned (" + commander.getName() + ")");
valid = false; valid = false;
} }
} else { } else {
invalid.put("Commander", "Commander invalid (" + commander.getName() +")"); invalid.put("Commander", "Commander invalid (" + commander.getName() + ")");
valid = false; valid = false;
} }
} else { } else {

View file

@ -40,7 +40,6 @@ public class DuelCommander extends Commander {
banned.add("Balance"); banned.add("Balance");
banned.add("Back to Basics"); banned.add("Back to Basics");
banned.add("Black Lotus"); banned.add("Black Lotus");
banned.add("Cataclysm");
banned.add("Channel"); banned.add("Channel");
banned.add("Entomb"); banned.add("Entomb");
banned.add("Fastbond"); banned.add("Fastbond");

View file

@ -27,21 +27,18 @@
*/ */
package mage.deck; package mage.deck;
import java.util.Date;
import java.util.GregorianCalendar;
import mage.cards.ExpansionSet; import mage.cards.ExpansionSet;
import mage.cards.Sets; import mage.cards.Sets;
import mage.cards.decks.Constructed; import mage.cards.decks.Constructed;
import mage.constants.SetType; import mage.constants.SetType;
import java.util.Date;
import java.util.GregorianCalendar;
/** /**
* *
* @author LevelX2 * @author LevelX2
*/ */
public class Modern extends Constructed { public class Modern extends Constructed {
public Modern() { public Modern() {
super("Constructed - Modern"); super("Constructed - Modern");
@ -56,14 +53,14 @@ public class Modern extends Constructed {
banned.add("Ancestral Vision"); banned.add("Ancestral Vision");
banned.add("Ancient Den"); banned.add("Ancient Den");
banned.add("Birthing Pod"); // banned effective January 23, 2015 banned.add("Birthing Pod");
banned.add("Blazing Shoal"); banned.add("Blazing Shoal");
banned.add("Bloodbraid Elf"); // (banned effective February 1, 2013) banned.add("Bloodbraid Elf");
banned.add("Chrome Mox"); banned.add("Chrome Mox");
banned.add("Cloudpost"); banned.add("Cloudpost");
banned.add("Dark Depths"); banned.add("Dark Depths");
banned.add("Deathrite Shaman"); // (banned effective February 7, 2014 banned.add("Deathrite Shaman");
banned.add("Dig Through Time"); // banned effective January 23, 2015 banned.add("Dig Through Time");
banned.add("Dread Return"); banned.add("Dread Return");
banned.add("Glimpse of Nature"); banned.add("Glimpse of Nature");
banned.add("Great Furnace"); banned.add("Great Furnace");
@ -76,16 +73,17 @@ public class Modern extends Constructed {
banned.add("Punishing Fire"); banned.add("Punishing Fire");
banned.add("Rite of Flame"); banned.add("Rite of Flame");
banned.add("Seat of the Synod"); banned.add("Seat of the Synod");
banned.add("Second Sunrise"); // (banned effective May 3, 2013) banned.add("Second Sunrise");
banned.add("Seething Song"); // (banned effective February 1, 2013) banned.add("Seething Song");
banned.add("Sensei's Divining Top"); banned.add("Sensei's Divining Top");
banned.add("Stoneforge Mystic"); banned.add("Stoneforge Mystic");
banned.add("Skullclamp"); banned.add("Skullclamp");
banned.add("Splinter Twin");
banned.add("Summer Bloom");
banned.add("Sword of the Meek"); banned.add("Sword of the Meek");
banned.add("Treasure Cruise"); // banned effective January 23, 2015 banned.add("Treasure Cruise");
banned.add("Tree of Tales"); banned.add("Tree of Tales");
banned.add("Umezawa's Jitte"); banned.add("Umezawa's Jitte");
banned.add("Vault of Whispers"); banned.add("Vault of Whispers");
} }
} }

View file

@ -27,12 +27,13 @@
*/ */
package mage.deck; package mage.deck;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.decks.Deck; import mage.cards.decks.Deck;
import mage.cards.decks.DeckValidator; import mage.cards.decks.DeckValidator;
import java.util.*;
/** /**
* *
* @author nigelzor * @author nigelzor

View file

@ -23,6 +23,7 @@ public class Pauper extends Constructed {
rarities.add(Rarity.COMMON); rarities.add(Rarity.COMMON);
rarities.add(Rarity.LAND); rarities.add(Rarity.LAND);
banned.add("Cloud of Faeries");
banned.add("Cloudpost"); banned.add("Cloudpost");
banned.add("Cranial Plating"); banned.add("Cranial Plating");
banned.add("Empty the Warrens"); banned.add("Empty the Warrens");

View file

@ -120,7 +120,7 @@ public class TinyLeaders extends DeckValidator {
valid = false; valid = false;
} }
List<String> basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", List<String> basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes",
"Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains")); "Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains"));
Map<String, Integer> counts = new HashMap<>(); Map<String, Integer> counts = new HashMap<>();
counts.put(deck.getName(), 1); // add the commander to the counts, so it can't be in the deck or sideboard again counts.put(deck.getName(), 1); // add the commander to the counts, so it can't be in the deck or sideboard again
@ -145,19 +145,20 @@ public class TinyLeaders extends DeckValidator {
if (deck.getSideboard().size() <= 10) { if (deck.getSideboard().size() <= 10) {
Card commander = GameTinyLeadersImpl.getCommanderCard(deck.getName(), null); Card commander = GameTinyLeadersImpl.getCommanderCard(deck.getName(), null);
/** /**
* 905.5b - Each card must have a converted mana cost of three of less. * 905.5b - Each card must have a converted mana cost of three of
* Cards with {X} in their mana cost count X as zero. * less. Cards with {X} in their mana cost count X as zero. Split
* Split and double-face cards are legal only if both of their halves would be legal independently. * and double-face cards are legal only if both of their halves
* would be legal independently.
*/ */
if (commander == null || commander.getManaCost().convertedManaCost() > 3) { if (commander == null || commander.getManaCost().convertedManaCost() > 3) {
if (commander == null) { if (commander == null) {
if (deck.getName() == null) { if (deck.getName() == null) {
invalid.put("Leader", "You have to save your deck with the leader card name entered to the DECK NAME field of the DECK EDITOR (top left) so that XMage knows your leader." + invalid.put("Leader", "You have to save your deck with the leader card name entered to the DECK NAME field of the DECK EDITOR (top left) so that XMage knows your leader."
"(You can use the \"Sultai\" for a UBG (2/2) default Commander.)"); + "(You can use the \"Sultai\" for a UBG (3/3) default Commander or \"Glass\" for a colorless 3/3 default Commander.)");
} else { } else {
invalid.put("Leader", "Leader [" + deck.getName() + "] not found. You have to enter the name of the leader card into the DECK NAME field of the DECK EDITOR (top left). Check your spelling " + invalid.put("Leader", "Leader [" + deck.getName() + "] not found. You have to enter the name of the leader card into the DECK NAME field of the DECK EDITOR (top left). Check your spelling "
"(use the \"Sultai\" for a UBG (2/2) default Commander)"); + "(use the \"Sultai\" for a UBG (3/3) default Commander or \"Glass\" for a colorless (3/3) default Commander)");
} }
} }
@ -208,7 +209,7 @@ public class TinyLeaders extends DeckValidator {
invalid.put(card.getName(), "Invalid cost (" + ((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() + ")"); invalid.put(card.getName(), "Invalid cost (" + ((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() + ")");
return false; return false;
} }
if (((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() > 3 ) { if (((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() > 3) {
invalid.put(card.getName(), "Invalid cost (" + ((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() + ")"); invalid.put(card.getName(), "Invalid cost (" + ((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() + ")");
return false; return false;
} }

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-deck-limited</artifactId> <artifactId>mage-deck-limited</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-game-commanderduel</artifactId> <artifactId>mage-game-commanderduel</artifactId>

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-game-commanderfreeforall</artifactId> <artifactId>mage-game-commanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-game-freeforall</artifactId> <artifactId>mage-game-freeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-game-momirduel</artifactId> <artifactId>mage-game-momirduel</artifactId>

View file

@ -27,6 +27,11 @@
*/ */
package mage.game; package mage.game;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
@ -38,7 +43,13 @@ import mage.cards.Card;
import mage.cards.repository.CardCriteria; import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo; import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository; import mage.cards.repository.CardRepository;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.MultiplayerAttackOption;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.match.MatchType; import mage.game.match.MatchType;
import mage.game.permanent.token.EmptyToken; import mage.game.permanent.token.EmptyToken;
@ -46,8 +57,6 @@ import mage.game.turn.TurnMod;
import mage.players.Player; import mage.players.Player;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.*;
/** /**
* *
* @author nigelzor * @author nigelzor
@ -89,7 +98,7 @@ public class MomirDuel extends GameImpl {
@Override @Override
public Set<UUID> getOpponents(UUID playerId) { public Set<UUID> getOpponents(UUID playerId) {
Set<UUID> opponents = new HashSet<>(); Set<UUID> opponents = new HashSet<>();
for (UUID opponentId: this.getPlayer(playerId).getInRange()) { for (UUID opponentId : this.getPlayer(playerId).getInRange()) {
if (!opponentId.equals(playerId)) { if (!opponentId.equals(playerId)) {
opponents.add(opponentId); opponents.add(opponentId);
} }
@ -114,7 +123,7 @@ class MomirEmblem extends Emblem {
public MomirEmblem() { public MomirEmblem() {
setName("Momir Vig, Simic Visionary"); setName("Momir Vig, Simic Visionary");
//TODO: setExpansionSetCodeForImage(???);
// {X}, Discard a card: Put a token into play as a copy of a random creature card with converted mana cost X. Play this ability only any time you could play a sorcery and only once each turn. // {X}, Discard a card: Put a token into play as a copy of a random creature card with converted mana cost X. Play this ability only any time you could play a sorcery and only once each turn.
LimitedTimesPerTurnActivatedAbility ability = new LimitedTimesPerTurnActivatedAbility(Zone.COMMAND, new MomirEffect(), new VariableManaCost()); LimitedTimesPerTurnActivatedAbility ability = new LimitedTimesPerTurnActivatedAbility(Zone.COMMAND, new MomirEffect(), new VariableManaCost());
ability.addCost(new DiscardCardCost()); ability.addCost(new DiscardCardCost());
@ -153,6 +162,8 @@ class MomirEffect extends OneShotEffect {
EmptyToken token = new EmptyToken(); EmptyToken token = new EmptyToken();
CardUtil.copyTo(token).from(card); CardUtil.copyTo(token).from(card);
token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId(), false, false); token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId(), false, false);
} else {
game.informPlayers("No random creature card with converted mana cost of " + value + " was found.");
} }
return true; return true;
} }

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-game-tinyleadersduel</artifactId> <artifactId>mage-game-tinyleadersduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-game-twoplayerduel</artifactId> <artifactId>mage-game-twoplayerduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-player-ai-draftbot</artifactId> <artifactId>mage-player-ai-draftbot</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-player-ai-ma</artifactId> <artifactId>mage-player-ai-ma</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-player-ai</artifactId> <artifactId>mage-player-ai</artifactId>

View file

@ -56,6 +56,7 @@ import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
import mage.abilities.costs.VariableCost; import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.costs.mana.ColoredManaCost;
import mage.abilities.costs.mana.ColorlessManaCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.HybridManaCost; import mage.abilities.costs.mana.HybridManaCost;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
@ -1007,7 +1008,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (card.getManaCost().getVariableCosts().size() > 0) { if (card.getManaCost().getVariableCosts().size() > 0) {
//don't use variable mana costs unless there is at least 3 extra mana for X //don't use variable mana costs unless there is at least 3 extra mana for X
for (Mana option : options) { for (Mana option : options) {
option.add(Mana.ColorlessMana(3)); option.add(Mana.GenericMana(3));
} }
} }
for (Mana mana : options) { for (Mana mana : options) {
@ -1041,7 +1042,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (ability.getManaCosts().getVariableCosts().size() > 0) { if (ability.getManaCosts().getVariableCosts().size() > 0) {
//don't use variable mana costs unless there is at least 3 extra mana for X //don't use variable mana costs unless there is at least 3 extra mana for X
for (Mana option : abilityOptions) { for (Mana option : abilityOptions) {
option.add(Mana.ColorlessMana(3)); option.add(Mana.GenericMana(3));
} }
} }
if (abilityOptions.size() == 0) { if (abilityOptions.size() == 0) {
@ -1167,6 +1168,18 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
} }
} }
// pay colorless
for (ManaAbility manaAbility : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) {
if (cost instanceof ColorlessManaCost) {
for (Mana netMana : manaAbility.getNetMana(game)) {
if (cost.testPay(netMana) || spendAnyMana) {
if (activateAbility(manaAbility, game)) {
return true;
}
}
}
}
}
// finally pay generic // finally pay generic
for (ManaAbility manaAbility : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { for (ManaAbility manaAbility : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) {
if (cost instanceof GenericManaCost) { if (cost instanceof GenericManaCost) {
@ -1182,7 +1195,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
// pay phyrexian life costs // pay phyrexian life costs
if (cost instanceof PhyrexianManaCost) { if (cost instanceof PhyrexianManaCost) {
if (cost.pay(null, game, null, playerId, false) || spendAnyMana) { if (cost.pay(null, game, null, playerId, false, null) || spendAnyMana) {
return true; return true;
} }
} }

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-player-ai-mcts</artifactId> <artifactId>mage-player-ai-mcts</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-player-aiminimax</artifactId> <artifactId>mage-player-aiminimax</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-player-human</artifactId> <artifactId>mage-player-human</artifactId>

View file

@ -358,8 +358,7 @@ public class HumanPlayer extends PlayerImpl {
} }
} }
} }
} else { } else if (target.canTarget(response.getUUID(), game)) {
if (target.canTarget(response.getUUID(), game)) {
if (target.getTargets().contains(response.getUUID())) { // if already included remove it with if (target.getTargets().contains(response.getUUID())) { // if already included remove it with
target.remove(response.getUUID()); target.remove(response.getUUID());
} else { } else {
@ -370,7 +369,6 @@ public class HumanPlayer extends PlayerImpl {
} }
} }
} }
}
} else { } else {
if (target.getTargets().size() >= target.getNumberOfTargets()) { if (target.getTargets().size() >= target.getNumberOfTargets()) {
return true; return true;
@ -530,14 +528,12 @@ public class HumanPlayer extends PlayerImpl {
if (response.getUUID() != null) { if (response.getUUID() != null) {
if (target.getTargets().contains(response.getUUID())) { // if already included remove it if (target.getTargets().contains(response.getUUID())) { // if already included remove it
target.remove(response.getUUID()); target.remove(response.getUUID());
} else { } else if (target.canTarget(response.getUUID(), cards, game)) {
if (target.canTarget(response.getUUID(), cards, game)) {
target.addTarget(response.getUUID(), source, game); target.addTarget(response.getUUID(), source, game);
if (target.doneChosing()) { if (target.doneChosing()) {
return true; return true;
} }
} }
}
} else { } else {
if (target.getTargets().size() >= target.getNumberOfTargets()) { if (target.getTargets().size() >= target.getNumberOfTargets()) {
return true; return true;
@ -805,7 +801,7 @@ public class HumanPlayer extends PlayerImpl {
if (cost instanceof PhyrexianManaCost) { if (cost instanceof PhyrexianManaCost) {
PhyrexianManaCost ph = (PhyrexianManaCost) cost; PhyrexianManaCost ph = (PhyrexianManaCost) cost;
if (ph.canPay(null, null, playerId, game)) { if (ph.canPay(null, null, playerId, game)) {
((PhyrexianManaCost) cost).pay(null, game, null, playerId, false); ((PhyrexianManaCost) cost).pay(null, game, null, playerId, false, null);
} }
break; break;
} }
@ -1065,11 +1061,9 @@ public class HumanPlayer extends PlayerImpl {
// does not block yet and can block or can block more attackers // does not block yet and can block or can block more attackers
if (filter.match(blocker, null, playerId, game)) { if (filter.match(blocker, null, playerId, game)) {
selectCombatGroup(defendingPlayerId, blocker.getId(), game); selectCombatGroup(defendingPlayerId, blocker.getId(), game);
} else { } else if (filterBlock.match(blocker, null, playerId, game) && game.getStack().isEmpty()) {
if (filterBlock.match(blocker, null, playerId, game) && game.getStack().isEmpty()) {
removeBlocker = true; removeBlocker = true;
} }
}
if (removeBlocker) { if (removeBlocker) {
game.getCombat().removeBlocker(blocker.getId(), game); game.getCombat().removeBlocker(blocker.getId(), game);
@ -1546,4 +1540,9 @@ public class HumanPlayer extends PlayerImpl {
pass(game); pass(game);
return true; return true;
} }
@Override
public String getHistory() {
return "no available";
}
} }

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-tournament-boosterdraft</artifactId> <artifactId>mage-tournament-boosterdraft</artifactId>

View file

@ -34,9 +34,9 @@ import mage.game.draft.DraftCube;
* @author LevelX2 * @author LevelX2
*/ */
public class MTGOLegacyCube extends DraftCube { public class LegacyCube extends DraftCube {
public MTGOLegacyCube() { public LegacyCube() {
super("MTGO Legacy Cube (600 cards)"); super("MTGO Legacy Cube (600 cards)");
cubeCards.add(new CardIdentity("Accorder Paladin","")); cubeCards.add(new CardIdentity("Accorder Paladin",""));
cubeCards.add(new CardIdentity("Abrupt Decay","")); cubeCards.add(new CardIdentity("Abrupt Decay",""));

View file

@ -0,0 +1,642 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.tournament.cubes;
import mage.game.draft.DraftCube;
/**
*
* @author fireshoes
*/
public class LegacyCubeJanuary2016 extends DraftCube {
public LegacyCubeJanuary2016() {
super("MTGO Legacy Cube January 2016 (600 cards)");
cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep",""));
cubeCards.add(new DraftCube.CardIdentity("Abhorrent Overlord",""));
cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay",""));
cubeCards.add(new DraftCube.CardIdentity("Abyssal Persecutor",""));
cubeCards.add(new DraftCube.CardIdentity("Accorder Paladin",""));
cubeCards.add(new DraftCube.CardIdentity("Acidic Slime",""));
cubeCards.add(new DraftCube.CardIdentity("Act of Aggression",""));
cubeCards.add(new DraftCube.CardIdentity("Adarkar Wastes",""));
cubeCards.add(new DraftCube.CardIdentity("Ainok Survivalist",""));
cubeCards.add(new DraftCube.CardIdentity("Ajani Goldmane",""));
cubeCards.add(new DraftCube.CardIdentity("Ajani Vengeant",""));
cubeCards.add(new DraftCube.CardIdentity("Ajani, Caller of the Pride",""));
cubeCards.add(new DraftCube.CardIdentity("Anafenza, Kin-Tree Spirit",""));
cubeCards.add(new DraftCube.CardIdentity("Ancestral Vision",""));
cubeCards.add(new DraftCube.CardIdentity("Ancient Tomb",""));
cubeCards.add(new DraftCube.CardIdentity("Angel of Serenity",""));
cubeCards.add(new DraftCube.CardIdentity("Anger of the Gods",""));
cubeCards.add(new DraftCube.CardIdentity("Animate Dead",""));
cubeCards.add(new DraftCube.CardIdentity("Arbor Elf",""));
cubeCards.add(new DraftCube.CardIdentity("Arc Trail",""));
cubeCards.add(new DraftCube.CardIdentity("Archangel of Thune",""));
cubeCards.add(new DraftCube.CardIdentity("Arid Mesa",""));
cubeCards.add(new DraftCube.CardIdentity("Armageddon",""));
cubeCards.add(new DraftCube.CardIdentity("Ashcloud Phoenix",""));
cubeCards.add(new DraftCube.CardIdentity("Ashen Rider",""));
cubeCards.add(new DraftCube.CardIdentity("Ashenmoor Gouger",""));
cubeCards.add(new DraftCube.CardIdentity("Ashiok, Nightmare Weaver",""));
cubeCards.add(new DraftCube.CardIdentity("Assemble the Legion",""));
cubeCards.add(new DraftCube.CardIdentity("Attrition",""));
cubeCards.add(new DraftCube.CardIdentity("Augur of Bolas",""));
cubeCards.add(new DraftCube.CardIdentity("Avacyn's Pilgrim",""));
cubeCards.add(new DraftCube.CardIdentity("Avalanche Riders",""));
cubeCards.add(new DraftCube.CardIdentity("Avenger of Zendikar",""));
cubeCards.add(new DraftCube.CardIdentity("Badlands",""));
cubeCards.add(new DraftCube.CardIdentity("Baleful Strix",""));
cubeCards.add(new DraftCube.CardIdentity("Banefire",""));
cubeCards.add(new DraftCube.CardIdentity("Baneslayer Angel",""));
cubeCards.add(new DraftCube.CardIdentity("Banisher Priest",""));
cubeCards.add(new DraftCube.CardIdentity("Banishing Light",""));
cubeCards.add(new DraftCube.CardIdentity("Batterskull",""));
cubeCards.add(new DraftCube.CardIdentity("Battlefield Forge",""));
cubeCards.add(new DraftCube.CardIdentity("Bayou",""));
cubeCards.add(new DraftCube.CardIdentity("Beast Within",""));
cubeCards.add(new DraftCube.CardIdentity("Beetleback Chief",""));
cubeCards.add(new DraftCube.CardIdentity("Birds of Paradise",""));
cubeCards.add(new DraftCube.CardIdentity("Birthing Pod",""));
cubeCards.add(new DraftCube.CardIdentity("Bitterblossom",""));
cubeCards.add(new DraftCube.CardIdentity("Blade Splicer",""));
cubeCards.add(new DraftCube.CardIdentity("Blood Artist",""));
cubeCards.add(new DraftCube.CardIdentity("Blood Crypt",""));
cubeCards.add(new DraftCube.CardIdentity("Bloodbraid Elf",""));
cubeCards.add(new DraftCube.CardIdentity("Bloodghast",""));
cubeCards.add(new DraftCube.CardIdentity("Bloodsoaked Champion",""));
cubeCards.add(new DraftCube.CardIdentity("Bloodstained Mire",""));
cubeCards.add(new DraftCube.CardIdentity("Bloodthrone Vampire",""));
cubeCards.add(new DraftCube.CardIdentity("Bogardan Hellkite",""));
cubeCards.add(new DraftCube.CardIdentity("Bone Shredder",""));
cubeCards.add(new DraftCube.CardIdentity("Bonesplitter",""));
cubeCards.add(new DraftCube.CardIdentity("Bonfire of the Damned",""));
cubeCards.add(new DraftCube.CardIdentity("Boros Charm",""));
cubeCards.add(new DraftCube.CardIdentity("Boros Reckoner",""));
cubeCards.add(new DraftCube.CardIdentity("Brago, King Eternal",""));
cubeCards.add(new DraftCube.CardIdentity("Brainstorm",""));
cubeCards.add(new DraftCube.CardIdentity("Breeding Pool",""));
cubeCards.add(new DraftCube.CardIdentity("Brimaz, King of Oreskos",""));
cubeCards.add(new DraftCube.CardIdentity("Brimstone Volley",""));
cubeCards.add(new DraftCube.CardIdentity("Brushland",""));
cubeCards.add(new DraftCube.CardIdentity("Brutal Expulsion",""));
cubeCards.add(new DraftCube.CardIdentity("Buried Alive",""));
cubeCards.add(new DraftCube.CardIdentity("Burst Lightning",""));
cubeCards.add(new DraftCube.CardIdentity("Careful Study",""));
cubeCards.add(new DraftCube.CardIdentity("Carrier Thrall",""));
cubeCards.add(new DraftCube.CardIdentity("Carrion Feeder",""));
cubeCards.add(new DraftCube.CardIdentity("Catacomb Sifter",""));
cubeCards.add(new DraftCube.CardIdentity("Caves of Koilos",""));
cubeCards.add(new DraftCube.CardIdentity("Chain Lightning",""));
cubeCards.add(new DraftCube.CardIdentity("Chainer's Edict",""));
cubeCards.add(new DraftCube.CardIdentity("Chameleon Colossus",""));
cubeCards.add(new DraftCube.CardIdentity("Champion of the Parish",""));
cubeCards.add(new DraftCube.CardIdentity("Chandra Nalaar",""));
cubeCards.add(new DraftCube.CardIdentity("Chandra, Fire of Kaladesh",""));
cubeCards.add(new DraftCube.CardIdentity("Chandra, Pyromaster",""));
cubeCards.add(new DraftCube.CardIdentity("Chandra's Phoenix",""));
cubeCards.add(new DraftCube.CardIdentity("Char",""));
cubeCards.add(new DraftCube.CardIdentity("Chasm Skulker",""));
cubeCards.add(new DraftCube.CardIdentity("Chord of Calling",""));
cubeCards.add(new DraftCube.CardIdentity("Chromatic Lantern",""));
cubeCards.add(new DraftCube.CardIdentity("City of Brass",""));
cubeCards.add(new DraftCube.CardIdentity("Clifftop Retreat",""));
cubeCards.add(new DraftCube.CardIdentity("Cloudgoat Ranger",""));
cubeCards.add(new DraftCube.CardIdentity("Collected Company",""));
cubeCards.add(new DraftCube.CardIdentity("Compulsive Research",""));
cubeCards.add(new DraftCube.CardIdentity("Condemn",""));
cubeCards.add(new DraftCube.CardIdentity("Consecrated Sphinx",""));
cubeCards.add(new DraftCube.CardIdentity("Control Magic",""));
cubeCards.add(new DraftCube.CardIdentity("Coralhelm Commander",""));
cubeCards.add(new DraftCube.CardIdentity("Council's Judgment",""));
cubeCards.add(new DraftCube.CardIdentity("Counterspell",""));
cubeCards.add(new DraftCube.CardIdentity("Courser of Kruphix",""));
cubeCards.add(new DraftCube.CardIdentity("Crater's Claws",""));
cubeCards.add(new DraftCube.CardIdentity("Craterhoof Behemoth",""));
cubeCards.add(new DraftCube.CardIdentity("Crusade",""));
cubeCards.add(new DraftCube.CardIdentity("Crux of Fate",""));
cubeCards.add(new DraftCube.CardIdentity("Cryptic Command",""));
cubeCards.add(new DraftCube.CardIdentity("Cultivate",""));
cubeCards.add(new DraftCube.CardIdentity("Cunning Sparkmage",""));
cubeCards.add(new DraftCube.CardIdentity("Cursed Scroll",""));
cubeCards.add(new DraftCube.CardIdentity("Cyclonic Rift",""));
cubeCards.add(new DraftCube.CardIdentity("Damnation",""));
cubeCards.add(new DraftCube.CardIdentity("Dance of the Dead",""));
cubeCards.add(new DraftCube.CardIdentity("Dark Confidant",""));
cubeCards.add(new DraftCube.CardIdentity("Dark Depths",""));
cubeCards.add(new DraftCube.CardIdentity("Dark Petition",""));
cubeCards.add(new DraftCube.CardIdentity("Dark Ritual",""));
cubeCards.add(new DraftCube.CardIdentity("Day of Judgment",""));
cubeCards.add(new DraftCube.CardIdentity("Daze",""));
cubeCards.add(new DraftCube.CardIdentity("Deathrite Shaman",""));
cubeCards.add(new DraftCube.CardIdentity("Deceiver Exarch",""));
cubeCards.add(new DraftCube.CardIdentity("Deep Analysis",""));
cubeCards.add(new DraftCube.CardIdentity("Delver of Secrets",""));
cubeCards.add(new DraftCube.CardIdentity("Den Protector",""));
cubeCards.add(new DraftCube.CardIdentity("Deranged Hermit",""));
cubeCards.add(new DraftCube.CardIdentity("Desecration Demon",""));
cubeCards.add(new DraftCube.CardIdentity("Devil's Play",""));
cubeCards.add(new DraftCube.CardIdentity("Diabolic Servitude",""));
cubeCards.add(new DraftCube.CardIdentity("Dictate of Heliod",""));
cubeCards.add(new DraftCube.CardIdentity("Disciple of Bolas",""));
cubeCards.add(new DraftCube.CardIdentity("Disfigure",""));
cubeCards.add(new DraftCube.CardIdentity("Dismember",""));
cubeCards.add(new DraftCube.CardIdentity("Dismiss",""));
cubeCards.add(new DraftCube.CardIdentity("Dissipate",""));
cubeCards.add(new DraftCube.CardIdentity("Dissolve",""));
cubeCards.add(new DraftCube.CardIdentity("Divinity of Pride",""));
cubeCards.add(new DraftCube.CardIdentity("Domri Rade",""));
cubeCards.add(new DraftCube.CardIdentity("Doom Blade",""));
cubeCards.add(new DraftCube.CardIdentity("Dragon Fodder",""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Atarka",""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Dromoka",""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Ojutai",""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Silumgar",""));
cubeCards.add(new DraftCube.CardIdentity("Dragonskull Summit",""));
cubeCards.add(new DraftCube.CardIdentity("Drana, Liberator of Malakir",""));
cubeCards.add(new DraftCube.CardIdentity("Dread Return",""));
cubeCards.add(new DraftCube.CardIdentity("Dreadbore",""));
cubeCards.add(new DraftCube.CardIdentity("Dromoka's Command",""));
cubeCards.add(new DraftCube.CardIdentity("Drowned Catacomb",""));
cubeCards.add(new DraftCube.CardIdentity("Dualcaster Mage",""));
cubeCards.add(new DraftCube.CardIdentity("Dungeon Geists",""));
cubeCards.add(new DraftCube.CardIdentity("Duplicant",""));
cubeCards.add(new DraftCube.CardIdentity("Duress",""));
cubeCards.add(new DraftCube.CardIdentity("Eldrazi Monument",""));
cubeCards.add(new DraftCube.CardIdentity("Edric, Spymaster of Trest",""));
cubeCards.add(new DraftCube.CardIdentity("Electrolyze",""));
cubeCards.add(new DraftCube.CardIdentity("Elesh Norn, Grand Cenobite",""));
cubeCards.add(new DraftCube.CardIdentity("Elite Vanguard",""));
cubeCards.add(new DraftCube.CardIdentity("Elixir of Immortality",""));
cubeCards.add(new DraftCube.CardIdentity("Elspeth Tirel",""));
cubeCards.add(new DraftCube.CardIdentity("Elspeth, Knight-Errant",""));
cubeCards.add(new DraftCube.CardIdentity("Elspeth, Sun's Champion",""));
cubeCards.add(new DraftCube.CardIdentity("Elves of Deep Shadow",""));
cubeCards.add(new DraftCube.CardIdentity("Elvish Mystic",""));
cubeCards.add(new DraftCube.CardIdentity("Emeria Angel",""));
cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Aeons Torn",""));
cubeCards.add(new DraftCube.CardIdentity("Entomb",""));
cubeCards.add(new DraftCube.CardIdentity("Entreat the Angels",""));
cubeCards.add(new DraftCube.CardIdentity("Erebos, God of the Dead",""));
cubeCards.add(new DraftCube.CardIdentity("Eternal Dragon",""));
cubeCards.add(new DraftCube.CardIdentity("Eternal Witness",""));
cubeCards.add(new DraftCube.CardIdentity("Eureka",""));
cubeCards.add(new DraftCube.CardIdentity("Evolutionary Leap",""));
cubeCards.add(new DraftCube.CardIdentity("Exalted Angel",""));
cubeCards.add(new DraftCube.CardIdentity("Exclude",""));
cubeCards.add(new DraftCube.CardIdentity("Exhume",""));
cubeCards.add(new DraftCube.CardIdentity("Explore",""));
cubeCards.add(new DraftCube.CardIdentity("Exquisite Firecraft",""));
cubeCards.add(new DraftCube.CardIdentity("Fact or Fiction",""));
cubeCards.add(new DraftCube.CardIdentity("Faith's Fetters",""));
cubeCards.add(new DraftCube.CardIdentity("Falkenrath Aristocrat",""));
cubeCards.add(new DraftCube.CardIdentity("Farseek",""));
cubeCards.add(new DraftCube.CardIdentity("Fauna Shaman",""));
cubeCards.add(new DraftCube.CardIdentity("Fertile Ground",""));
cubeCards.add(new DraftCube.CardIdentity("Fiend Hunter",""));
cubeCards.add(new DraftCube.CardIdentity("Fiery Confluence",""));
cubeCards.add(new DraftCube.CardIdentity("Fire // Ice",""));
cubeCards.add(new DraftCube.CardIdentity("Firebolt",""));
cubeCards.add(new DraftCube.CardIdentity("Firefist Striker",""));
cubeCards.add(new DraftCube.CardIdentity("Flame Slash",""));
cubeCards.add(new DraftCube.CardIdentity("Flametongue Kavu",""));
cubeCards.add(new DraftCube.CardIdentity("Flamewake Phoenix",""));
cubeCards.add(new DraftCube.CardIdentity("Flickerwisp",""));
cubeCards.add(new DraftCube.CardIdentity("Flooded Strand",""));
cubeCards.add(new DraftCube.CardIdentity("Forbid",""));
cubeCards.add(new DraftCube.CardIdentity("Forbidden Alchemy",""));
cubeCards.add(new DraftCube.CardIdentity("Force of Will",""));
cubeCards.add(new DraftCube.CardIdentity("Force Spike",""));
cubeCards.add(new DraftCube.CardIdentity("Forked Bolt",""));
cubeCards.add(new DraftCube.CardIdentity("Frenzied Goblin",""));
cubeCards.add(new DraftCube.CardIdentity("Freyalise, Llanowar's Fury",""));
cubeCards.add(new DraftCube.CardIdentity("From Beyond",""));
cubeCards.add(new DraftCube.CardIdentity("Frontline Medic",""));
cubeCards.add(new DraftCube.CardIdentity("Frost Titan",""));
cubeCards.add(new DraftCube.CardIdentity("Future Sight",""));
cubeCards.add(new DraftCube.CardIdentity("Fyndhorn Elves",""));
cubeCards.add(new DraftCube.CardIdentity("Gaddock Teeg",""));
cubeCards.add(new DraftCube.CardIdentity("Gaea's Cradle",""));
cubeCards.add(new DraftCube.CardIdentity("Garruk Relentless",""));
cubeCards.add(new DraftCube.CardIdentity("Garruk Wildspeaker",""));
cubeCards.add(new DraftCube.CardIdentity("Garruk, Apex Predator",""));
cubeCards.add(new DraftCube.CardIdentity("Garruk, Caller of Beasts",""));
cubeCards.add(new DraftCube.CardIdentity("Garruk, Primal Hunter",""));
cubeCards.add(new DraftCube.CardIdentity("Gatekeeper of Malakir",""));
cubeCards.add(new DraftCube.CardIdentity("Gather the Townsfolk",""));
cubeCards.add(new DraftCube.CardIdentity("Geist of Saint Traft",""));
cubeCards.add(new DraftCube.CardIdentity("Genesis Hydra",""));
cubeCards.add(new DraftCube.CardIdentity("Genesis Wave",""));
cubeCards.add(new DraftCube.CardIdentity("Geralf's Messenger",""));
cubeCards.add(new DraftCube.CardIdentity("Gideon, Ally of Zendikar",""));
cubeCards.add(new DraftCube.CardIdentity("Gideon Jura",""));
cubeCards.add(new DraftCube.CardIdentity("Gifts Ungiven",""));
cubeCards.add(new DraftCube.CardIdentity("Gilded Lotus",""));
cubeCards.add(new DraftCube.CardIdentity("Gilt-Leaf Winnower",""));
cubeCards.add(new DraftCube.CardIdentity("Gitaxian Probe",""));
cubeCards.add(new DraftCube.CardIdentity("Glacial Fortress",""));
cubeCards.add(new DraftCube.CardIdentity("Glen Elendra Archmage",""));
cubeCards.add(new DraftCube.CardIdentity("Glorious Anthem",""));
cubeCards.add(new DraftCube.CardIdentity("Go for the Throat",""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Bombardment",""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Bushwhacker",""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Glory Chaser",""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Guide",""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Rabblemaster",""));
cubeCards.add(new DraftCube.CardIdentity("Godless Shrine",""));
cubeCards.add(new DraftCube.CardIdentity("Gore-House Chainwalker",""));
cubeCards.add(new DraftCube.CardIdentity("Grafted Wargear",""));
cubeCards.add(new DraftCube.CardIdentity("Grave Titan",""));
cubeCards.add(new DraftCube.CardIdentity("Gravecrawler",""));
cubeCards.add(new DraftCube.CardIdentity("Gray Merchant of Asphodel",""));
cubeCards.add(new DraftCube.CardIdentity("Greater Gargadon",""));
cubeCards.add(new DraftCube.CardIdentity("Green Sun's Zenith",""));
cubeCards.add(new DraftCube.CardIdentity("Greenwarden of Murasa",""));
cubeCards.add(new DraftCube.CardIdentity("Grim Lavamancer",""));
cubeCards.add(new DraftCube.CardIdentity("Griselbrand",""));
cubeCards.add(new DraftCube.CardIdentity("Hall of Triumph",""));
cubeCards.add(new DraftCube.CardIdentity("Hallowed Fountain",""));
cubeCards.add(new DraftCube.CardIdentity("Hallowed Spiritkeeper",""));
cubeCards.add(new DraftCube.CardIdentity("Hangarback Walker",""));
cubeCards.add(new DraftCube.CardIdentity("Harbinger of the Tides",""));
cubeCards.add(new DraftCube.CardIdentity("Harmonize",""));
cubeCards.add(new DraftCube.CardIdentity("Hellrider",""));
cubeCards.add(new DraftCube.CardIdentity("Hero of Bladehold",""));
cubeCards.add(new DraftCube.CardIdentity("Hero's Downfall",""));
cubeCards.add(new DraftCube.CardIdentity("Hidden Dragonslayer",""));
cubeCards.add(new DraftCube.CardIdentity("High Market",""));
cubeCards.add(new DraftCube.CardIdentity("Hinterland Harbor",""));
cubeCards.add(new DraftCube.CardIdentity("Honor of the Pure",""));
cubeCards.add(new DraftCube.CardIdentity("Hordeling Outburst",""));
cubeCards.add(new DraftCube.CardIdentity("Hornet Queen",""));
cubeCards.add(new DraftCube.CardIdentity("Huntmaster of the Fells",""));
cubeCards.add(new DraftCube.CardIdentity("Hymn to Tourach",""));
cubeCards.add(new DraftCube.CardIdentity("Hypnotic Specter",""));
cubeCards.add(new DraftCube.CardIdentity("Imperial Recruiter",""));
cubeCards.add(new DraftCube.CardIdentity("Impulse",""));
cubeCards.add(new DraftCube.CardIdentity("Incinerate",""));
cubeCards.add(new DraftCube.CardIdentity("Indrik Stomphowler",""));
cubeCards.add(new DraftCube.CardIdentity("Inferno Titan",""));
cubeCards.add(new DraftCube.CardIdentity("Inquisition of Kozilek",""));
cubeCards.add(new DraftCube.CardIdentity("Into the Roil",""));
cubeCards.add(new DraftCube.CardIdentity("Ire Shaman",""));
cubeCards.add(new DraftCube.CardIdentity("Isamaru, Hound of Konda",""));
cubeCards.add(new DraftCube.CardIdentity("Isochron Scepter",""));
cubeCards.add(new DraftCube.CardIdentity("Isolated Chapel",""));
cubeCards.add(new DraftCube.CardIdentity("Izzet Charm",""));
cubeCards.add(new DraftCube.CardIdentity("Jace Beleren",""));
cubeCards.add(new DraftCube.CardIdentity("Jace, Architect of Thought",""));
cubeCards.add(new DraftCube.CardIdentity("Jace, the Mind Sculptor",""));
cubeCards.add(new DraftCube.CardIdentity("Jace, Vryn's Prodigy",""));
cubeCards.add(new DraftCube.CardIdentity("Jackal Pup",""));
cubeCards.add(new DraftCube.CardIdentity("Joraga Treespeaker",""));
cubeCards.add(new DraftCube.CardIdentity("Journey to Nowhere",""));
cubeCards.add(new DraftCube.CardIdentity("Kami of Ancient Law",""));
cubeCards.add(new DraftCube.CardIdentity("Karmic Guide",""));
cubeCards.add(new DraftCube.CardIdentity("Karn Liberated",""));
cubeCards.add(new DraftCube.CardIdentity("Karplusan Forest",""));
cubeCards.add(new DraftCube.CardIdentity("Keiga, the Tide Star",""));
cubeCards.add(new DraftCube.CardIdentity("Keranos, God of Storms",""));
cubeCards.add(new DraftCube.CardIdentity("Kiki-Jiki, Mirror Breaker",""));
cubeCards.add(new DraftCube.CardIdentity("Kiln Fiend",""));
cubeCards.add(new DraftCube.CardIdentity("Kiora, the Crashing Wave",""));
cubeCards.add(new DraftCube.CardIdentity("Kiora's Follower",""));
cubeCards.add(new DraftCube.CardIdentity("Kira, Great Glass-Spinner",""));
cubeCards.add(new DraftCube.CardIdentity("Kitchen Finks",""));
cubeCards.add(new DraftCube.CardIdentity("Kodama's Reach",""));
cubeCards.add(new DraftCube.CardIdentity("Kokusho, the Evening Star",""));
cubeCards.add(new DraftCube.CardIdentity("Kor Skyfisher",""));
cubeCards.add(new DraftCube.CardIdentity("Koth of the Hammer",""));
cubeCards.add(new DraftCube.CardIdentity("Kozilek, Butcher of Truth",""));
cubeCards.add(new DraftCube.CardIdentity("Krenko's Command",""));
cubeCards.add(new DraftCube.CardIdentity("Kytheon, Hero of Akros",""));
cubeCards.add(new DraftCube.CardIdentity("Land Tax",""));
cubeCards.add(new DraftCube.CardIdentity("Legacy's Allure",""));
cubeCards.add(new DraftCube.CardIdentity("Leonin Relic-Warder",""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Bolt",""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Greaves",""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Helix",""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Mauler",""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Strike",""));
cubeCards.add(new DraftCube.CardIdentity("Liliana of the Veil",""));
cubeCards.add(new DraftCube.CardIdentity("Liliana Vess",""));
cubeCards.add(new DraftCube.CardIdentity("Liliana, Heretical Healer",""));
cubeCards.add(new DraftCube.CardIdentity("Lingering Souls",""));
cubeCards.add(new DraftCube.CardIdentity("Linvala, Keeper of Silence",""));
cubeCards.add(new DraftCube.CardIdentity("Living Death",""));
cubeCards.add(new DraftCube.CardIdentity("Llanowar Elves",""));
cubeCards.add(new DraftCube.CardIdentity("Llanowar Wastes",""));
cubeCards.add(new DraftCube.CardIdentity("Looter il-Kor",""));
cubeCards.add(new DraftCube.CardIdentity("Lotus Cobra",""));
cubeCards.add(new DraftCube.CardIdentity("Loxodon Warhammer",""));
cubeCards.add(new DraftCube.CardIdentity("Maelstrom Pulse",""));
cubeCards.add(new DraftCube.CardIdentity("Magma Jet",""));
cubeCards.add(new DraftCube.CardIdentity("Makeshift Mannequin",""));
cubeCards.add(new DraftCube.CardIdentity("Malicious Affliction",""));
cubeCards.add(new DraftCube.CardIdentity("Man-o'-War",""));
cubeCards.add(new DraftCube.CardIdentity("Mana Confluence",""));
cubeCards.add(new DraftCube.CardIdentity("Mana Tithe",""));
cubeCards.add(new DraftCube.CardIdentity("Managorger Hydra",""));
cubeCards.add(new DraftCube.CardIdentity("Manic Vandal",""));
cubeCards.add(new DraftCube.CardIdentity("Marsh Flats",""));
cubeCards.add(new DraftCube.CardIdentity("Martial Coup",""));
cubeCards.add(new DraftCube.CardIdentity("Massacre Wurm",""));
cubeCards.add(new DraftCube.CardIdentity("Master of the Wild Hunt",""));
cubeCards.add(new DraftCube.CardIdentity("Master of Waves",""));
cubeCards.add(new DraftCube.CardIdentity("Meloku the Clouded Mirror",""));
cubeCards.add(new DraftCube.CardIdentity("Mentor of the Meek",""));
cubeCards.add(new DraftCube.CardIdentity("Merfolk Looter",""));
cubeCards.add(new DraftCube.CardIdentity("Meteor Blast",""));
cubeCards.add(new DraftCube.CardIdentity("Mimic Vat",""));
cubeCards.add(new DraftCube.CardIdentity("Mirari's Wake",""));
cubeCards.add(new DraftCube.CardIdentity("Mirran Crusader",""));
cubeCards.add(new DraftCube.CardIdentity("Miscalculation",""));
cubeCards.add(new DraftCube.CardIdentity("Mishra's Factory",""));
cubeCards.add(new DraftCube.CardIdentity("Misty Rainforest",""));
cubeCards.add(new DraftCube.CardIdentity("Mizzium Mortars",""));
cubeCards.add(new DraftCube.CardIdentity("Mogg War Marshal",""));
cubeCards.add(new DraftCube.CardIdentity("Mogis's Marauder",""));
cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor",""));
cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear",""));
cubeCards.add(new DraftCube.CardIdentity("Mother of Runes",""));
cubeCards.add(new DraftCube.CardIdentity("Mulldrifter",""));
cubeCards.add(new DraftCube.CardIdentity("Murderous Cut",""));
cubeCards.add(new DraftCube.CardIdentity("Mutavault",""));
cubeCards.add(new DraftCube.CardIdentity("Myr Battlesphere",""));
cubeCards.add(new DraftCube.CardIdentity("Mystic Confluence",""));
cubeCards.add(new DraftCube.CardIdentity("Mystic Snake",""));
cubeCards.add(new DraftCube.CardIdentity("Nantuko Husk",""));
cubeCards.add(new DraftCube.CardIdentity("Natural Order",""));
cubeCards.add(new DraftCube.CardIdentity("Nature's Lore",""));
cubeCards.add(new DraftCube.CardIdentity("Necromancy",""));
cubeCards.add(new DraftCube.CardIdentity("Negate",""));
cubeCards.add(new DraftCube.CardIdentity("Nekrataal",""));
cubeCards.add(new DraftCube.CardIdentity("Nicol Bolas, Planeswalker",""));
cubeCards.add(new DraftCube.CardIdentity("Nightveil Specter",""));
cubeCards.add(new DraftCube.CardIdentity("Nissa, Vastwood Seer",""));
cubeCards.add(new DraftCube.CardIdentity("Nissa, Worldwaker",""));
cubeCards.add(new DraftCube.CardIdentity("Noble Hierarch",""));
cubeCards.add(new DraftCube.CardIdentity("Nykthos, Shrine to Nyx",""));
cubeCards.add(new DraftCube.CardIdentity("Ob Nixilis Reignited",""));
cubeCards.add(new DraftCube.CardIdentity("Oblivion Ring",""));
cubeCards.add(new DraftCube.CardIdentity("Obstinate Baloth",""));
cubeCards.add(new DraftCube.CardIdentity("Ohran Viper",""));
cubeCards.add(new DraftCube.CardIdentity("Old Man of the Sea",""));
cubeCards.add(new DraftCube.CardIdentity("Olivia Voldaren",""));
cubeCards.add(new DraftCube.CardIdentity("Omnath, Locus of Rage",""));
cubeCards.add(new DraftCube.CardIdentity("Oona's Prowler",""));
cubeCards.add(new DraftCube.CardIdentity("Ophiomancer",""));
cubeCards.add(new DraftCube.CardIdentity("Opposition",""));
cubeCards.add(new DraftCube.CardIdentity("Oracle of Mul Daya",""));
cubeCards.add(new DraftCube.CardIdentity("Oust",""));
cubeCards.add(new DraftCube.CardIdentity("Outpost Siege",""));
cubeCards.add(new DraftCube.CardIdentity("Overgrown Battlement",""));
cubeCards.add(new DraftCube.CardIdentity("Overgrown Tomb",""));
cubeCards.add(new DraftCube.CardIdentity("Pack Rat",""));
cubeCards.add(new DraftCube.CardIdentity("Pact of Negation",""));
cubeCards.add(new DraftCube.CardIdentity("Parallax Wave",""));
cubeCards.add(new DraftCube.CardIdentity("Part the Waterveil",""));
cubeCards.add(new DraftCube.CardIdentity("Path to Exile",""));
cubeCards.add(new DraftCube.CardIdentity("Pestermite",""));
cubeCards.add(new DraftCube.CardIdentity("Phantasmal Image",""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Arena",""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Metamorph",""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Obliterator",""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Revoker",""));
cubeCards.add(new DraftCube.CardIdentity("Pia and Kiran Nalaar",""));
cubeCards.add(new DraftCube.CardIdentity("Pillar of Flame",""));
cubeCards.add(new DraftCube.CardIdentity("Plateau",""));
cubeCards.add(new DraftCube.CardIdentity("Polluted Delta",""));
cubeCards.add(new DraftCube.CardIdentity("Polukranos, World Eater",""));
cubeCards.add(new DraftCube.CardIdentity("Ponder",""));
cubeCards.add(new DraftCube.CardIdentity("Porcelain Legionnaire",""));
cubeCards.add(new DraftCube.CardIdentity("Precinct Captain",""));
cubeCards.add(new DraftCube.CardIdentity("Precursor Golem",""));
cubeCards.add(new DraftCube.CardIdentity("Preordain",""));
cubeCards.add(new DraftCube.CardIdentity("Primal Command",""));
cubeCards.add(new DraftCube.CardIdentity("Primeval Titan",""));
cubeCards.add(new DraftCube.CardIdentity("Profane Command",""));
cubeCards.add(new DraftCube.CardIdentity("Progenitus",""));
cubeCards.add(new DraftCube.CardIdentity("Prophetic Flamespeaker",""));
cubeCards.add(new DraftCube.CardIdentity("Psychatog",""));
cubeCards.add(new DraftCube.CardIdentity("Purphoros, God of the Forge",""));
cubeCards.add(new DraftCube.CardIdentity("Qasali Pridemage",""));
cubeCards.add(new DraftCube.CardIdentity("Quarantine Field",""));
cubeCards.add(new DraftCube.CardIdentity("Raise the Alarm",""));
cubeCards.add(new DraftCube.CardIdentity("Rakdos's Return",""));
cubeCards.add(new DraftCube.CardIdentity("Ral Zarek",""));
cubeCards.add(new DraftCube.CardIdentity("Rampaging Baloths",""));
cubeCards.add(new DraftCube.CardIdentity("Rampant Growth",""));
cubeCards.add(new DraftCube.CardIdentity("Ranger of Eos",""));
cubeCards.add(new DraftCube.CardIdentity("Ratchet Bomb",""));
cubeCards.add(new DraftCube.CardIdentity("Ravages of War",""));
cubeCards.add(new DraftCube.CardIdentity("Read the Bones",""));
cubeCards.add(new DraftCube.CardIdentity("Reanimate",""));
cubeCards.add(new DraftCube.CardIdentity("Reclamation Sage",""));
cubeCards.add(new DraftCube.CardIdentity("Recurring Nightmare",""));
cubeCards.add(new DraftCube.CardIdentity("Reflecting Pool",""));
cubeCards.add(new DraftCube.CardIdentity("Regrowth",""));
cubeCards.add(new DraftCube.CardIdentity("Relic of Progenitus",""));
cubeCards.add(new DraftCube.CardIdentity("Remand",""));
cubeCards.add(new DraftCube.CardIdentity("Remove Soul",""));
cubeCards.add(new DraftCube.CardIdentity("Repeal",""));
cubeCards.add(new DraftCube.CardIdentity("Restoration Angel",""));
cubeCards.add(new DraftCube.CardIdentity("Reveillark",""));
cubeCards.add(new DraftCube.CardIdentity("Rift Bolt",""));
cubeCards.add(new DraftCube.CardIdentity("Riftwing Cloudskate",""));
cubeCards.add(new DraftCube.CardIdentity("Righteous Confluence",""));
cubeCards.add(new DraftCube.CardIdentity("Rishadan Port",""));
cubeCards.add(new DraftCube.CardIdentity("Roast",""));
cubeCards.add(new DraftCube.CardIdentity("Rofellos, Llanowar Emissary",""));
cubeCards.add(new DraftCube.CardIdentity("Rootbound Crag",""));
cubeCards.add(new DraftCube.CardIdentity("Rune-Scarred Demon",""));
cubeCards.add(new DraftCube.CardIdentity("Sacred Foundry",""));
cubeCards.add(new DraftCube.CardIdentity("Sakura-Tribe Elder",""));
cubeCards.add(new DraftCube.CardIdentity("Sarkhan, the Dragonspeaker",""));
cubeCards.add(new DraftCube.CardIdentity("Savannah",""));
cubeCards.add(new DraftCube.CardIdentity("Scalding Tarn",""));
cubeCards.add(new DraftCube.CardIdentity("Scavenging Ooze",""));
cubeCards.add(new DraftCube.CardIdentity("Scroll Rack",""));
cubeCards.add(new DraftCube.CardIdentity("Scrubland",""));
cubeCards.add(new DraftCube.CardIdentity("Sea Gate Oracle",""));
cubeCards.add(new DraftCube.CardIdentity("Seal of Fire",""));
cubeCards.add(new DraftCube.CardIdentity("Search for Tomorrow",""));
cubeCards.add(new DraftCube.CardIdentity("Searing Spear",""));
cubeCards.add(new DraftCube.CardIdentity("Secure the Wastes",""));
cubeCards.add(new DraftCube.CardIdentity("Seeker of the Way",""));
cubeCards.add(new DraftCube.CardIdentity("Sensei's Divining Top",""));
cubeCards.add(new DraftCube.CardIdentity("Serendib Efreet",""));
cubeCards.add(new DraftCube.CardIdentity("Serum Visions",""));
cubeCards.add(new DraftCube.CardIdentity("Shadowmage Infiltrator",""));
cubeCards.add(new DraftCube.CardIdentity("Shaman of Forgotten Ways",""));
cubeCards.add(new DraftCube.CardIdentity("Shardless Agent",""));
cubeCards.add(new DraftCube.CardIdentity("Sheoldred, Whispering One",""));
cubeCards.add(new DraftCube.CardIdentity("Shivan Reef",""));
cubeCards.add(new DraftCube.CardIdentity("Show and Tell",""));
cubeCards.add(new DraftCube.CardIdentity("Shriekmaw",""));
cubeCards.add(new DraftCube.CardIdentity("Sidisi, Undead Vizier",""));
cubeCards.add(new DraftCube.CardIdentity("Siege-Gang Commander",""));
cubeCards.add(new DraftCube.CardIdentity("Silverblade Paladin",""));
cubeCards.add(new DraftCube.CardIdentity("Sin Collector",""));
cubeCards.add(new DraftCube.CardIdentity("Skinrender",""));
cubeCards.add(new DraftCube.CardIdentity("Skullcrack",""));
cubeCards.add(new DraftCube.CardIdentity("Slagstorm",""));
cubeCards.add(new DraftCube.CardIdentity("Slaughter Pact",""));
cubeCards.add(new DraftCube.CardIdentity("Snapcaster Mage",""));
cubeCards.add(new DraftCube.CardIdentity("Sneak Attack",""));
cubeCards.add(new DraftCube.CardIdentity("Soldier of the Pantheon",""));
cubeCards.add(new DraftCube.CardIdentity("Solemn Simulacrum",""));
cubeCards.add(new DraftCube.CardIdentity("Song of the Dryads",""));
cubeCards.add(new DraftCube.CardIdentity("Sorin Markov",""));
cubeCards.add(new DraftCube.CardIdentity("Sorin, Solemn Visitor",""));
cubeCards.add(new DraftCube.CardIdentity("Soulfire Grand Master",""));
cubeCards.add(new DraftCube.CardIdentity("Sower of Temptation",""));
cubeCards.add(new DraftCube.CardIdentity("Spear of Heliod",""));
cubeCards.add(new DraftCube.CardIdentity("Spectral Procession",""));
cubeCards.add(new DraftCube.CardIdentity("Spellskite",""));
cubeCards.add(new DraftCube.CardIdentity("Spell Pierce",""));
cubeCards.add(new DraftCube.CardIdentity("Sphinx's Revelation",""));
cubeCards.add(new DraftCube.CardIdentity("Spikeshot Elder",""));
cubeCards.add(new DraftCube.CardIdentity("Splinter Twin",""));
cubeCards.add(new DraftCube.CardIdentity("Staggershock",""));
cubeCards.add(new DraftCube.CardIdentity("Steam Vents",""));
cubeCards.add(new DraftCube.CardIdentity("Stoke the Flames",""));
cubeCards.add(new DraftCube.CardIdentity("Stomping Ground",""));
cubeCards.add(new DraftCube.CardIdentity("Stormbreath Dragon",""));
cubeCards.add(new DraftCube.CardIdentity("Stormtide Leviathan",""));
cubeCards.add(new DraftCube.CardIdentity("Stratus Dancer",""));
cubeCards.add(new DraftCube.CardIdentity("Stroke of Genius",""));
cubeCards.add(new DraftCube.CardIdentity("Stromkirk Noble",""));
cubeCards.add(new DraftCube.CardIdentity("Student of Warfare",""));
cubeCards.add(new DraftCube.CardIdentity("Sublime Archangel",""));
cubeCards.add(new DraftCube.CardIdentity("Sulfur Falls",""));
cubeCards.add(new DraftCube.CardIdentity("Sulfurous Springs",""));
cubeCards.add(new DraftCube.CardIdentity("Summoning Trap",""));
cubeCards.add(new DraftCube.CardIdentity("Sun Titan",""));
cubeCards.add(new DraftCube.CardIdentity("Sundering Titan",""));
cubeCards.add(new DraftCube.CardIdentity("Sunpetal Grove",""));
cubeCards.add(new DraftCube.CardIdentity("Supreme Verdict",""));
cubeCards.add(new DraftCube.CardIdentity("Surrak, the Hunt Caller",""));
cubeCards.add(new DraftCube.CardIdentity("Swords to Plowshares",""));
cubeCards.add(new DraftCube.CardIdentity("Sylvan Caryatid",""));
cubeCards.add(new DraftCube.CardIdentity("Sylvan Library",""));
cubeCards.add(new DraftCube.CardIdentity("Taiga",""));
cubeCards.add(new DraftCube.CardIdentity("Talrand, Sky Summoner",""));
cubeCards.add(new DraftCube.CardIdentity("Tamiyo, the Moon Sage",""));
cubeCards.add(new DraftCube.CardIdentity("Tangle Wire",""));
cubeCards.add(new DraftCube.CardIdentity("Tarmogoyf",""));
cubeCards.add(new DraftCube.CardIdentity("Tasigur, the Golden Fang",""));
cubeCards.add(new DraftCube.CardIdentity("Tectonic Edge",""));
cubeCards.add(new DraftCube.CardIdentity("Teferi, Mage of Zhalfir",""));
cubeCards.add(new DraftCube.CardIdentity("Temple Garden",""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Abandon",""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Deceit",""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Enlightenment",""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Epiphany",""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Malady",""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Malice",""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Mystery",""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Plenty",""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Silence",""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Triumph",""));
cubeCards.add(new DraftCube.CardIdentity("Terastodon",""));
cubeCards.add(new DraftCube.CardIdentity("Terminate",""));
cubeCards.add(new DraftCube.CardIdentity("Terminus",""));
cubeCards.add(new DraftCube.CardIdentity("Thalia, Guardian of Thraben",""));
cubeCards.add(new DraftCube.CardIdentity("Thassa, God of the Sea",""));
cubeCards.add(new DraftCube.CardIdentity("Thespian's Stage",""));
cubeCards.add(new DraftCube.CardIdentity("Thoughtseize",""));
cubeCards.add(new DraftCube.CardIdentity("Thragtusk",""));
cubeCards.add(new DraftCube.CardIdentity("Threads of Disloyalty",""));
cubeCards.add(new DraftCube.CardIdentity("Through the Breach",""));
cubeCards.add(new DraftCube.CardIdentity("Thrun, the Last Troll",""));
cubeCards.add(new DraftCube.CardIdentity("Thunderbreak Regent",""));
cubeCards.add(new DraftCube.CardIdentity("Thundermaw Hellkite",""));
cubeCards.add(new DraftCube.CardIdentity("Tidehollow Sculler",""));
cubeCards.add(new DraftCube.CardIdentity("Time Warp",""));
cubeCards.add(new DraftCube.CardIdentity("Tooth and Nail",""));
cubeCards.add(new DraftCube.CardIdentity("Toxic Deluge",""));
cubeCards.add(new DraftCube.CardIdentity("Treachery",""));
cubeCards.add(new DraftCube.CardIdentity("Tropical Island",""));
cubeCards.add(new DraftCube.CardIdentity("Trygon Predator",""));
cubeCards.add(new DraftCube.CardIdentity("Tundra",""));
cubeCards.add(new DraftCube.CardIdentity("Ugin, the Spirit Dragon",""));
cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Ceaseless Hunger",""));
cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Infinite Gyre",""));
cubeCards.add(new DraftCube.CardIdentity("Ultimate Price",""));
cubeCards.add(new DraftCube.CardIdentity("Unburial Rites",""));
cubeCards.add(new DraftCube.CardIdentity("Underground River",""));
cubeCards.add(new DraftCube.CardIdentity("Underground Sea",""));
cubeCards.add(new DraftCube.CardIdentity("Underworld Connections",""));
cubeCards.add(new DraftCube.CardIdentity("Unexpectedly Absent",""));
cubeCards.add(new DraftCube.CardIdentity("Upheaval",""));
cubeCards.add(new DraftCube.CardIdentity("Utopia Sprawl",""));
cubeCards.add(new DraftCube.CardIdentity("Vampire Hexmage",""));
cubeCards.add(new DraftCube.CardIdentity("Vampire Nighthawk",""));
cubeCards.add(new DraftCube.CardIdentity("Vendilion Clique",""));
cubeCards.add(new DraftCube.CardIdentity("Vengevine",""));
cubeCards.add(new DraftCube.CardIdentity("Venser, Shaper Savant",""));
cubeCards.add(new DraftCube.CardIdentity("Venser, the Sojourner",""));
cubeCards.add(new DraftCube.CardIdentity("Verdant Catacombs",""));
cubeCards.add(new DraftCube.CardIdentity("Vindicate",""));
cubeCards.add(new DraftCube.CardIdentity("Viscera Seer",""));
cubeCards.add(new DraftCube.CardIdentity("Volcanic Island",""));
cubeCards.add(new DraftCube.CardIdentity("Volrath's Stronghold",""));
cubeCards.add(new DraftCube.CardIdentity("Voyaging Satyr",""));
cubeCards.add(new DraftCube.CardIdentity("Vraska the Unseen",""));
cubeCards.add(new DraftCube.CardIdentity("Wake Thrasher",""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Blossoms",""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Omens",""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Roots",""));
cubeCards.add(new DraftCube.CardIdentity("Warleader's Helix",""));
cubeCards.add(new DraftCube.CardIdentity("Waterfront Bouncer",""));
cubeCards.add(new DraftCube.CardIdentity("Watery Grave",""));
cubeCards.add(new DraftCube.CardIdentity("Whip of Erebos",""));
cubeCards.add(new DraftCube.CardIdentity("Whirler Rogue",""));
cubeCards.add(new DraftCube.CardIdentity("Whisperwood Elemental",""));
cubeCards.add(new DraftCube.CardIdentity("Windbrisk Heights",""));
cubeCards.add(new DraftCube.CardIdentity("Windswept Heath",""));
cubeCards.add(new DraftCube.CardIdentity("Winter Orb",""));
cubeCards.add(new DraftCube.CardIdentity("Wolfir Silverheart",""));
cubeCards.add(new DraftCube.CardIdentity("Wood Elves",""));
cubeCards.add(new DraftCube.CardIdentity("Wooded Foothills",""));
cubeCards.add(new DraftCube.CardIdentity("Woodfall Primus",""));
cubeCards.add(new DraftCube.CardIdentity("Woodland Cemetery",""));
cubeCards.add(new DraftCube.CardIdentity("Wrath of God",""));
cubeCards.add(new DraftCube.CardIdentity("Wretched Confluence",""));
cubeCards.add(new DraftCube.CardIdentity("Wurmcoil Engine",""));
cubeCards.add(new DraftCube.CardIdentity("Xenagos, the Reveler",""));
cubeCards.add(new DraftCube.CardIdentity("Yavimaya Coast",""));
cubeCards.add(new DraftCube.CardIdentity("Yavimaya Elder",""));
cubeCards.add(new DraftCube.CardIdentity("Yosei, the Morning Star",""));
cubeCards.add(new DraftCube.CardIdentity("Young Pyromancer",""));
cubeCards.add(new DraftCube.CardIdentity("Zealous Conscripts",""));
cubeCards.add(new DraftCube.CardIdentity("Zulaport Cutthroat",""));
}
}

View file

@ -34,9 +34,9 @@ import mage.game.draft.DraftCube;
* @author fireshoes * @author fireshoes
*/ */
public class MTGOLegacyCubeMarch2015 extends DraftCube { public class LegacyCubeMarch2015 extends DraftCube {
public MTGOLegacyCubeMarch2015() { public LegacyCubeMarch2015() {
super("MTGO Legacy Cube March 2015 (600 cards)"); super("MTGO Legacy Cube March 2015 (600 cards)");
cubeCards.add(new DraftCube.CardIdentity("Accorder Paladin","")); cubeCards.add(new DraftCube.CardIdentity("Accorder Paladin",""));
cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay","")); cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay",""));

View file

@ -34,9 +34,9 @@ import mage.game.draft.DraftCube;
* @author fireshoes * @author fireshoes
*/ */
public class MTGOLegacyCubeSeptember2015 extends DraftCube { public class LegacyCubeSeptember2015 extends DraftCube {
public MTGOLegacyCubeSeptember2015() { public LegacyCubeSeptember2015() {
super("MTGO Legacy Cube September 2015 (600 cards)"); super("MTGO Legacy Cube September 2015 (600 cards)");
cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep","")); cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep",""));
cubeCards.add(new DraftCube.CardIdentity("Abhorrent Overlord","")); cubeCards.add(new DraftCube.CardIdentity("Abhorrent Overlord",""));

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-tournament-constructed</artifactId> <artifactId>mage-tournament-constructed</artifactId>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-tournament-sealed</artifactId> <artifactId>mage-tournament-sealed</artifactId>

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-root</artifactId> <artifactId>mage-root</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>

View file

@ -19,6 +19,17 @@
userNamePattern - pattern for user name validity check userNamePattern - pattern for user name validity check
maxAiOpponents - number of allowed AI opponents on the server maxAiOpponents - number of allowed AI opponents on the server
saveGameActivated - allow game save and replay options (not working correctly yet) saveGameActivated - allow game save and replay options (not working correctly yet)
authenticationActivated - "true" = user have to register to signon "false" = user need not to register
* mail configs only needed if authentication is activated:
* if mailUser = "" mailgun is used otherwise nativ mail server on the system
googleAccount - not supported currently
mailgunApiKey - key from the mailgun domain e.g. = "key-12121111..."
mailgunDomain - domain for the mailgun message sending
mailSmtpHost - hostname to send the mail
mailSmtpPort - port to send the mail
mailUser - username used to send the mail
mailPassword - passworf of the used user to send the mail
mailFromAddress - sender address
--> -->
<server serverAddress="0.0.0.0" <server serverAddress="0.0.0.0"
serverName="mage-server" serverName="mage-server"
@ -32,9 +43,20 @@
maxSecondsIdle="600" maxSecondsIdle="600"
minUserNameLength="3" minUserNameLength="3"
maxUserNameLength="14" maxUserNameLength="14"
userNamePattern="[^a-z0-9_]" invalidUserNamePattern="[^a-z0-9_]"
minPasswordLength="8"
maxPasswordLength="100"
maxAiOpponents="15" maxAiOpponents="15"
saveGameActivated="false" saveGameActivated="false"
authenticationActivated="true"
googleAccount=""
mailgunApiKey="key-d93e81f19a9c9ed243ebb7cc9381385c"
mailgunDomain="sandbox401a433f30d445309a5e86b6c53f7812.mailgun.org"
mailSmtpHost="smtp.1und1.de"
mailSmtpPort="465"
mailUser="xmageserver@online.de"
mailPassword="24wrsfxv"
mailFromAddress="xmageserver@online.de"
/> />
<playerTypes> <playerTypes>
<playerType name="Human" jar="mage-player-human.jar" className="mage.player.human.HumanPlayer"/> <playerType name="Human" jar="mage-player-human.jar" className="mage.player.human.HumanPlayer"/>
@ -73,9 +95,10 @@
<draftCube name="Jim Davis's Cube (469 cards)" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.JimDavisCube"/> <draftCube name="Jim Davis's Cube (469 cards)" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.JimDavisCube"/>
<draftCube name="Mono Blue Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MonoBlueCube"/> <draftCube name="Mono Blue Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MonoBlueCube"/>
<draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOMarchCube2014"/> <draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOMarchCube2014"/>
<draftCube name="MTGO Legacy Cube (600 cards)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOLegacyCube"/> <draftCube name="MTGO Legacy Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCube"/>
<draftCube name="MTGO Legacy Cube March 2015 (600 cards)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOLegacyCubeMarch2015"/> <draftCube name="MTGO Legacy Cube March 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
<draftCube name="MTGO Legacy Cube September 2015 (600 cards)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOLegacyCubeSeptember2015"/> <draftCube name="MTGO Legacy Cube September 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/>
<draftCube name="MTGO Legacy Cube January 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/>
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/> <draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/>
<draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2013"/> <draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2013"/>
<draftCube name="MTGO Vintage Cube 2014" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2014"/> <draftCube name="MTGO Vintage Cube 2014" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2014"/>

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-root</artifactId> <artifactId>mage-root</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<artifactId>mage-server</artifactId> <artifactId>mage-server</artifactId>
@ -148,6 +148,62 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.4</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.21.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-gmail</artifactId>
<version>v1-rev35-1.21.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client-java6</artifactId>
<version>1.19.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client-jetty</artifactId>
<version>1.19.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.7.2</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -1,6 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Config.xsd"> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Config.xsd">
<!--
serverAddress - ip of the XMage server. Set it to "0.0.0.0" for local host or to the IP the server should use
port - the port the primary server socket is bound to
secondaryBindPort - the port to which the secondary server socket is to be bound. if "-1" is set , an arbitrary port is selected.
backlogSize - the preferred number of unaccepted incoming connections allowed at a given time. The actual number may be greater
than the specified backlog. When the queue is full, further connection requests are rejected. The JBoss default value is 200
numAcceptThreads - the number of threads listening on the ServerSocket. The JBoss default value is 1
maxPoolSize - the maximum number of ServerThreads that can exist at any given time. The JBoss default value is 300
leasePeriod - To turn on server side connection failure detection of remoting clients, it is necessary to satisfy two criteria.
The first is that the client lease period is set and is a value greater than 0. The value is represented in milliseconds.
The client lease period can be set by either the 'clientLeasePeriod' attribute within the Connector configuration or by calling the Connector method
maxGameThreads - Number of games that can be started simultanously on the server
maxSecondsIdle - Number of seconds after that a game is auto conceded by the player that was idle for such a time
minUserNameLength - minmal allowed length of a user name to connect to the server
maxUserNameLength - maximal allowed length of a user name to connect to the server
userNamePattern - pattern for user name validity check
maxAiOpponents - number of allowed AI opponents on the server
saveGameActivated - allow game save and replay options (not working correctly yet)
authenticationActivated - "true" = user have to register to signon "false" = user need not to register
* mail configs only needed if authentication is activated:
* if mailUser = "" mailgun is used otherwise nativ mail server on the system
googleAccount - not supported currently
mailgunApiKey - key from the mailgun domain e.g. = "key-12121111..."
mailgunDomain - domain for the mailgun message sending
mailSmtpHost - hostname to send the mail
mailSmtpPort - port to send the mail
mailUser - username used to send the mail
mailPassword - passworf of the used user to send the mail
mailFromAddress - sender address
-->
<server serverAddress="0.0.0.0" <server serverAddress="0.0.0.0"
serverName="mage-server" serverName="mage-server"
port="17171" port="17171"
@ -13,9 +43,20 @@
maxSecondsIdle="600" maxSecondsIdle="600"
minUserNameLength="3" minUserNameLength="3"
maxUserNameLength="14" maxUserNameLength="14"
userNamePattern="[^a-z0-9_]" invalidUserNamePattern="[^a-z0-9_]"
minPasswordLength="8"
maxPasswordLength="100"
maxAiOpponents="15" maxAiOpponents="15"
saveGameActivated="false" saveGameActivated="false"
authenticationActivated="false"
googleAccount=""
mailgunApiKey=""
mailgunDomain=""
mailSmtpHost=""
mailSmtpPort=""
mailUser=""
mailPassword=""
mailFromAddress=""
/> />
<playerTypes> <playerTypes>
<playerType name="Human" jar="mage-player-human-${project.version}.jar" className="mage.player.human.HumanPlayer"/> <playerType name="Human" jar="mage-player-human-${project.version}.jar" className="mage.player.human.HumanPlayer"/>
@ -52,9 +93,10 @@
<draftCube name="Jim Davis's Cube (469 cards)" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.JimDavisCube"/> <draftCube name="Jim Davis's Cube (469 cards)" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.JimDavisCube"/>
<draftCube name="Mono Blue Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MonoBlueCube"/> <draftCube name="Mono Blue Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MonoBlueCube"/>
<draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOMarchCube2014"/> <draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOMarchCube2014"/>
<draftCube name="MTGO Legacy Cube (600 cards)" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOLegacyCube"/> <draftCube name="MTGO Legacy Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCube"/>
<draftCube name="MTGO Legacy Cube March 2015 (600 cards)" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOLegacyCubeMarch2015"/> <draftCube name="MTGO Legacy Cube March 2015" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
<draftCube name="MTGO Legacy Cube September 2015 (600 cards)" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOLegacyCubeSeptember2015"/> <draftCube name="MTGO Legacy Cube September 2015" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/>
<draftCube name="MTGO Legacy Cube January 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/>
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/> <draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/>
<draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2013"/> <draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2013"/>
<draftCube name="MTGO Vintage Cube 2014" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2014"/> <draftCube name="MTGO Vintage Cube 2014" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2014"/>

View file

@ -0,0 +1,60 @@
package mage.server;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.hash.Hash;
@DatabaseTable(tableName = "authorized_user")
public class AuthorizedUser {
@DatabaseField(indexName = "name_index", unique = true)
protected String name;
@DatabaseField
protected String password;
@DatabaseField
protected String salt;
@DatabaseField
protected String hashAlgorithm;
@DatabaseField
protected int hashIterations;
@DatabaseField(indexName = "email_index", unique = true)
protected String email;
public AuthorizedUser() {
}
public AuthorizedUser(String name, Hash hash, String email) {
this.name = name;
this.password = hash.toBase64();
this.salt = hash.getSalt().toBase64();
this.hashAlgorithm = hash.getAlgorithmName();
this.hashIterations = hash.getIterations();
this.email = email;
}
public boolean doCredentialsMatch(String name, String password) {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(this.hashAlgorithm);
matcher.setHashIterations(this.hashIterations);
AuthenticationToken token = new UsernamePasswordToken(name, password);
AuthenticationInfo info = new SimpleAuthenticationInfo(this.name,
ByteSource.Util.bytes(Base64.decode(this.password)),
ByteSource.Util.bytes(Base64.decode(this.salt)), "");
return matcher.doCredentialsMatch(token, info);
}
public String getName() {
return this.name;
}
}

View file

@ -0,0 +1,115 @@
package mage.server;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.stmt.DeleteBuilder;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.SelectArg;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.support.DatabaseConnection;
import com.j256.ormlite.table.TableUtils;
import java.io.File;
import java.sql.SQLException;
import java.util.List;
import mage.cards.repository.RepositoryUtil;
import org.apache.log4j.Logger;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
public enum AuthorizedUserRepository {
instance;
private static final String JDBC_URL = "jdbc:h2:file:./db/authorized_user.h2;AUTO_SERVER=TRUE";
private static final String VERSION_ENTITY_NAME = "authorized_user";
// raise this if db structure was changed
private static final long DB_VERSION = 1;
private static final RandomNumberGenerator rng = new SecureRandomNumberGenerator();
private Dao<AuthorizedUser, Object> dao;
private AuthorizedUserRepository() {
File file = new File("db");
if (!file.exists()) {
file.mkdirs();
}
try {
ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL);
boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, DB_VERSION);
if (obsolete) {
TableUtils.dropTable(connectionSource, AuthorizedUser.class, true);
}
TableUtils.createTableIfNotExists(connectionSource, AuthorizedUser.class);
dao = DaoManager.createDao(connectionSource, AuthorizedUser.class);
} catch (SQLException ex) {
Logger.getLogger(AuthorizedUserRepository.class).error("Error creating authorized_user repository - ", ex);
}
}
public void add(final String userName, final String password, final String email) {
try {
Hash hash = new SimpleHash(Sha256Hash.ALGORITHM_NAME, password, rng.nextBytes(), 1024);
AuthorizedUser user = new AuthorizedUser(userName, hash, email);
dao.create(user);
} catch (SQLException ex) {
Logger.getLogger(AuthorizedUserRepository.class).error("Error adding a user to DB - ", ex);
}
}
public void remove(final String userName) {
try {
DeleteBuilder<AuthorizedUser, Object> db = dao.deleteBuilder();
db.where().eq("name", new SelectArg(userName));
db.delete();
} catch (SQLException ex) {
Logger.getLogger(AuthorizedUserRepository.class).error("Error removing a user from DB - ", ex);
}
}
public AuthorizedUser getByName(String userName) {
try {
QueryBuilder<AuthorizedUser, Object> qb = dao.queryBuilder();
qb.where().eq("name", new SelectArg(userName));
List<AuthorizedUser> results = dao.query(qb.prepare());
if (results.size() == 1) {
return results.get(0);
}
return null;
} catch (SQLException ex) {
Logger.getLogger(AuthorizedUserRepository.class).error("Error getting a authorized_user - ", ex);
}
return null;
}
public AuthorizedUser getByEmail(String userName) {
try {
QueryBuilder<AuthorizedUser, Object> qb = dao.queryBuilder();
qb.where().eq("email", new SelectArg(userName));
List<AuthorizedUser> results = dao.query(qb.prepare());
if (results.size() == 1) {
return results.get(0);
}
return null;
} catch (SQLException ex) {
Logger.getLogger(AuthorizedUserRepository.class).error("Error getting a authorized_user - ", ex);
}
return null;
}
public void closeDB() {
try {
if (dao != null && dao.getConnectionSource() != null) {
DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection();
conn.executeStatement("shutdown compact", 0);
}
} catch (SQLException ex) {
Logger.getLogger(AuthorizedUserRepository.class).error("Error closing authorized_user repository - ", ex);
}
}
}

View file

@ -24,8 +24,7 @@
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.server; package mage.server;
import java.util.ArrayList; import java.util.ArrayList;
@ -51,7 +50,8 @@ public class ChatManager {
return INSTANCE; return INSTANCE;
} }
private ChatManager() {} private ChatManager() {
}
private final ConcurrentHashMap<UUID, ChatSession> chatSessions = new ConcurrentHashMap<>(); private final ConcurrentHashMap<UUID, ChatSession> chatSessions = new ConcurrentHashMap<>();
@ -66,7 +66,7 @@ public class ChatManager {
if (chatSession != null) { if (chatSession != null) {
chatSession.join(userId); chatSession.join(userId);
} else { } else {
logger.trace("Chat to join not found - chatId: " + chatId +" userId: " + userId); logger.trace("Chat to join not found - chatId: " + chatId + " userId: " + userId);
} }
} }
@ -110,7 +110,7 @@ public class ChatManager {
ChatSession chatSession = chatSessions.get(chatId); ChatSession chatSession = chatSessions.get(chatId);
if (chatSession != null) { if (chatSession != null) {
if (message.startsWith("\\") || message.startsWith("/")) { if (message.startsWith("\\") || message.startsWith("/")) {
User user = UserManager.getInstance().findUser(userName); User user = UserManager.getInstance().getUserByName(userName);
if (user != null && performUserCommand(user, message, chatId)) { if (user != null && performUserCommand(user, message, chatId)) {
return; return;
} }
@ -119,54 +119,47 @@ public class ChatManager {
} }
} }
private boolean performUserCommand(User user, String message, UUID chatId) { private boolean performUserCommand(User user, String message, UUID chatId) {
String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH); String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH);
if (command.equals("I") || command.equals("INFO")) { if (command.startsWith("H ") || command.startsWith("HISTORY ")) {
user.setInfo(""); message = UserManager.getInstance().getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9));
chatSessions.get(chatId).broadcastInfoToUser(user,message); chatSessions.get(chatId).broadcastInfoToUser(user, message);
return true;
}
if (command.startsWith("I ") || command.startsWith("INFO ")) {
user.setInfo(message.substring(command.startsWith("I ") ? 3 : 6));
chatSessions.get(chatId).broadcastInfoToUser(user,message);
return true; return true;
} }
if (command.startsWith("W ") || command.startsWith("WHISPER ")) { if (command.startsWith("W ") || command.startsWith("WHISPER ")) {
String rest = message.substring(command.startsWith("W ")? 3 : 9); String rest = message.substring(command.startsWith("W ") ? 3 : 9);
int first = rest.indexOf(" "); int first = rest.indexOf(" ");
if (first > 1) { if (first > 1) {
String userToName = rest.substring(0,first); String userToName = rest.substring(0, first);
rest = rest.substring(first + 1).trim(); rest = rest.substring(first + 1).trim();
User userTo = UserManager.getInstance().findUser(userToName); User userTo = UserManager.getInstance().getUserByName(userToName);
if (userTo != null) { if (userTo != null) {
if (!chatSessions.get(chatId).broadcastWhisperToUser(user, userTo, rest)) { if (!chatSessions.get(chatId).broadcastWhisperToUser(user, userTo, rest)) {
message += new StringBuilder("<br/>User ").append(userToName).append(" not found").toString(); message += new StringBuilder("<br/>User ").append(userToName).append(" not found").toString();
chatSessions.get(chatId).broadcastInfoToUser(user,message); chatSessions.get(chatId).broadcastInfoToUser(user, message);
} }
} else { } else {
message += new StringBuilder("<br/>User ").append(userToName).append(" not found").toString(); message += new StringBuilder("<br/>User ").append(userToName).append(" not found").toString();
chatSessions.get(chatId).broadcastInfoToUser(user,message); chatSessions.get(chatId).broadcastInfoToUser(user, message);
} }
return true; return true;
} }
} }
if (command.equals("L") || command.equals("LIST")) { if (command.equals("L") || command.equals("LIST")) {
message += new StringBuilder("<br/>List of commands:") message += new StringBuilder("<br/>List of commands:")
.append("<br/>\\info [text] - set a info text to your player") .append("<br/>\\history or \\h [username] - shows the history of a player")
.append("<br/>\\list - Show a list of commands") .append("<br/>\\list or \\l - Show a list of commands")
.append("<br/>\\whisper [player name] [text] - whisper to the player with the given name").toString(); .append("<br/>\\whisper or \\w [player name] [text] - whisper to the player with the given name").toString();
chatSessions.get(chatId).broadcastInfoToUser(user,message); chatSessions.get(chatId).broadcastInfoToUser(user, message);
return true; return true;
} }
return false; return false;
} }
/** /**
* *
* use mainly for announcing that a user connection was lost or that a user has reconnected * use mainly for announcing that a user connection was lost or that a user
* has reconnected
* *
* @param userId * @param userId
* @param message * @param message
@ -175,7 +168,7 @@ public class ChatManager {
public void broadcast(UUID userId, String message, MessageColor color) { public void broadcast(UUID userId, String message, MessageColor color) {
User user = UserManager.getInstance().getUser(userId); User user = UserManager.getInstance().getUser(userId);
if (user != null) { if (user != null) {
for (ChatSession chat: chatSessions.values()) { for (ChatSession chat : chatSessions.values()) {
if (chat.hasUser(userId)) { if (chat.hasUser(userId)) {
chat.broadcast(user.getName(), message, color); chat.broadcast(user.getName(), message, color);
} }
@ -186,7 +179,7 @@ public class ChatManager {
public void sendReconnectMessage(UUID userId) { public void sendReconnectMessage(UUID userId) {
User user = UserManager.getInstance().getUser(userId); User user = UserManager.getInstance().getUser(userId);
if (user != null) { if (user != null) {
for (ChatSession chat: chatSessions.values()) { for (ChatSession chat : chatSessions.values()) {
if (chat.hasUser(userId)) { if (chat.hasUser(userId)) {
chat.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS); chat.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS);
} }
@ -195,7 +188,7 @@ public class ChatManager {
} }
public void removeUser(UUID userId, DisconnectReason reason) { public void removeUser(UUID userId, DisconnectReason reason) {
for (ChatSession chatSession: chatSessions.values()) { for (ChatSession chatSession : chatSessions.values()) {
if (chatSession.hasUser(userId)) { if (chatSession.hasUser(userId)) {
chatSession.kill(userId, reason); chatSession.kill(userId, reason);
} }

View file

@ -0,0 +1,91 @@
package mage.server;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.Base64;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.Gmail.Builder;
import com.google.api.services.gmail.GmailScopes;
import com.google.api.services.gmail.model.Message;
import java.io.ByteArrayOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;
import java.util.Properties;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import mage.server.util.ConfigSettings;
import org.apache.log4j.Logger;
public class GmailClient {
private static final Logger logger = Logger.getLogger(Main.class);
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".store/xmage");
private static FileDataStoreFactory dataStoreFactory;
private static HttpTransport httpTransport;
private static Credential credential;
public static boolean initilize() {
try {
dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new FileReader("client_secrets.json"));
if (clientSecrets.getDetails().getClientId().startsWith("Enter")
|| clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
logger.error("client_secrets.json not found");
return false;
}
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets,
Collections.singleton(GmailScopes.GMAIL_COMPOSE)).setDataStoreFactory(
dataStoreFactory).build();
credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
return true;
} catch (IOException | GeneralSecurityException ex) {
logger.error("Error initializing GmailClient", ex);
}
return false;
}
public static boolean sendMessage(String email, String subject, String text) {
if (email.length() == 0) {
logger.info("Email is not sent because the address is empty");
return false;
}
try {
Gmail gmail = new Builder(httpTransport, JSON_FACTORY, credential).setApplicationName("XMage Server").build();
MimeMessage mimeMessage = new MimeMessage(Session.getDefaultInstance(new Properties()));
mimeMessage.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(email));
mimeMessage.setSubject(subject);
mimeMessage.setText(text);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mimeMessage.writeTo(baos);
Message message = new Message();
message.setRaw(Base64.encodeBase64URLSafeString(baos.toByteArray()));
gmail.users().messages().send(ConfigSettings.getInstance().getGoogleAccount()
+ (ConfigSettings.getInstance().getGoogleAccount().endsWith("@gmail.com") ? "" : "@gmail.com"), message).execute();
return true;
} catch (MessagingException | IOException ex) {
logger.error("Error sending message", ex);
}
return false;
}
}

View file

@ -27,9 +27,12 @@
*/ */
package mage.server; package mage.server;
import java.security.SecureRandom;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -95,25 +98,105 @@ public class MageServerImpl implements MageServer {
private static final Logger logger = Logger.getLogger(MageServerImpl.class); private static final Logger logger = Logger.getLogger(MageServerImpl.class);
private static final ExecutorService callExecutor = ThreadExecutor.getInstance().getCallExecutor(); private static final ExecutorService callExecutor = ThreadExecutor.getInstance().getCallExecutor();
private static final SecureRandom RANDOM = new SecureRandom();
private final String password; private final String adminPassword;
private final boolean testMode; private final boolean testMode;
private final LinkedHashMap<String, String> activeAuthTokens = new LinkedHashMap<String, String>() {
@Override
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
// Keep the latest 1024 auth tokens in memory.
return size() > 1024;
}
};
public MageServerImpl(String password, boolean testMode) { public MageServerImpl(String adminPassword, boolean testMode) {
this.password = password; this.adminPassword = adminPassword;
this.testMode = testMode; this.testMode = testMode;
ServerMessagesUtil.getInstance().getMessages(); ServerMessagesUtil.getInstance().getMessages();
} }
@Override
public boolean registerUser(String sessionId, String userName, String password, String email) throws MageException {
return SessionManager.getInstance().registerUser(sessionId, userName, password, email);
}
// generateAuthToken returns a uniformly distributed 6-digits string.
static private String generateAuthToken() {
return String.format("%06d", RANDOM.nextInt(1000000));
}
@Override
public boolean emailAuthToken(String sessionId, String email) throws MageException {
if (!ConfigSettings.getInstance().isAuthenticationActivated()) {
sendErrorMessageToClient(sessionId, "Registration is disabled by the server config");
return false;
}
AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByEmail(email);
if (authorizedUser == null) {
sendErrorMessageToClient(sessionId, "No user was found with the email address " + email);
logger.info("Auth token is requested for " + email + " but there's no such user in DB");
return false;
}
String authToken = generateAuthToken();
activeAuthTokens.put(email, authToken);
String subject = "XMage Password Reset Auth Token";
String text = "Use this auth token to reset your password: " + authToken + "\n"
+ "It's valid until the next server restart.";
boolean success;
if (!ConfigSettings.getInstance().getMailUser().isEmpty()) {
success = MailClient.sendMessage(email, subject, text);
} else {
success = MailgunClient.sendMessage(email, subject, text);
}
if (!success) {
sendErrorMessageToClient(sessionId, "There was an error inside the server while emailing an auth token");
return false;
}
return true;
}
@Override
public boolean resetPassword(String sessionId, String email, String authToken, String password) throws MageException {
if (!ConfigSettings.getInstance().isAuthenticationActivated()) {
sendErrorMessageToClient(sessionId, "Registration is disabled by the server config");
return false;
}
String storedAuthToken = activeAuthTokens.get(email);
if (storedAuthToken == null || !storedAuthToken.equals(authToken)) {
sendErrorMessageToClient(sessionId, "Invalid auth token");
logger.info("Invalid auth token " + authToken + " is sent for " + email);
return false;
}
AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByEmail(email);
if (authorizedUser == null) {
sendErrorMessageToClient(sessionId, "The user is no longer in the DB");
logger.info("Auth token is valid, but the user with email address " + email + " is no longer in the DB");
return false;
}
AuthorizedUserRepository.instance.remove(authorizedUser.getName());
AuthorizedUserRepository.instance.add(authorizedUser.getName(), password, email);
activeAuthTokens.remove(email);
return true;
}
@Override @Override
public boolean registerClient(String userName, String sessionId, MageVersion version) throws MageException { public boolean registerClient(String userName, String sessionId, MageVersion version) throws MageException {
// This method is deprecated, so just inform the server version.
logger.info("MageVersionException: userName=" + userName + ", version=" + version);
LogServiceImpl.instance.log(LogKeys.KEY_WRONG_VERSION, userName, version.toString(), Main.getVersion().toString(), sessionId);
throw new MageVersionException(version, Main.getVersion());
}
@Override
public boolean connectUser(String userName, String password, String sessionId, MageVersion version) throws MageException {
try { try {
if (version.compareTo(Main.getVersion()) != 0) { if (version.compareTo(Main.getVersion()) != 0) {
logger.info("MageVersionException: userName=" + userName + ", version=" + version); logger.info("MageVersionException: userName=" + userName + ", version=" + version);
LogServiceImpl.instance.log(LogKeys.KEY_WRONG_VERSION, userName, version.toString(), Main.getVersion().toString(), sessionId); LogServiceImpl.instance.log(LogKeys.KEY_WRONG_VERSION, userName, version.toString(), Main.getVersion().toString(), sessionId);
throw new MageVersionException(version, Main.getVersion()); throw new MageVersionException(version, Main.getVersion());
} }
return SessionManager.getInstance().registerUser(sessionId, userName); return SessionManager.getInstance().connectUser(sessionId, userName, password);
} catch (MageException ex) { } catch (MageException ex) {
if (ex instanceof MageVersionException) { if (ex instanceof MageVersionException) {
throw (MageVersionException) ex; throw (MageVersionException) ex;
@ -134,15 +217,15 @@ public class MageServerImpl implements MageServer {
} }
@Override @Override
public boolean registerAdmin(String password, String sessionId, MageVersion version) throws MageException { public boolean connectAdmin(String adminPassword, String sessionId, MageVersion version) throws MageException {
try { try {
if (version.compareTo(Main.getVersion()) != 0) { if (version.compareTo(Main.getVersion()) != 0) {
throw new MageException("Wrong client version " + version + ", expecting version " + Main.getVersion()); throw new MageException("Wrong client version " + version + ", expecting version " + Main.getVersion());
} }
if (!password.equals(this.password)) { if (!adminPassword.equals(this.adminPassword)) {
throw new MageException("Wrong password"); throw new MageException("Wrong password");
} }
return SessionManager.getInstance().registerAdmin(sessionId); return SessionManager.getInstance().connectAdmin(sessionId);
} catch (Exception ex) { } catch (Exception ex) {
handleException(ex); handleException(ex);
} }
@ -362,7 +445,7 @@ public class MageServerImpl implements MageServer {
// } // }
@Override @Override
public boolean startMatch(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { public boolean startMatch(final String sessionId, final UUID roomId, final UUID tableId) throws MageException {
if (!TableManager.getInstance().getController(tableId).changeTableState(TableState.STARTING)) { if (!TableManager.getInstance().getController(tableId).changeTableStateToStarting()) {
return false; return false;
} }
execute("startMatch", sessionId, new Action() { execute("startMatch", sessionId, new Action() {
@ -387,7 +470,7 @@ public class MageServerImpl implements MageServer {
// } // }
@Override @Override
public boolean startTournament(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { public boolean startTournament(final String sessionId, final UUID roomId, final UUID tableId) throws MageException {
if (!TableManager.getInstance().getController(tableId).changeTableState(TableState.STARTING)) { if (!TableManager.getInstance().getController(tableId).changeTableStateToStarting()) {
return false; return false;
} }
execute("startTournament", sessionId, new Action() { execute("startTournament", sessionId, new Action() {
@ -1032,6 +1115,15 @@ public class MageServerImpl implements MageServer {
} }
} }
private void sendErrorMessageToClient(final String sessionId, final String message) throws MageException {
execute("sendErrorMessageToClient", sessionId, new Action() {
@Override
public void execute() {
SessionManager.getInstance().sendErrorMessageToClient(sessionId, message);
}
});
}
protected void execute(final String actionName, final String sessionId, final Action action, boolean checkAdminRights) throws MageException { protected void execute(final String actionName, final String sessionId, final Action action, boolean checkAdminRights) throws MageException {
if (checkAdminRights) { if (checkAdminRights) {
if (!SessionManager.getInstance().isAdmin(sessionId)) { if (!SessionManager.getInstance().isAdmin(sessionId)) {

View file

@ -0,0 +1,53 @@
package mage.server;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import mage.server.util.ConfigSettings;
import org.apache.log4j.Logger;
public class MailClient {
private static final Logger logger = Logger.getLogger(Main.class);
public static boolean sendMessage(String email, String subject, String text) {
if (email.length() == 0) {
logger.info("Email is not sent because the address is empty");
return false;
}
ConfigSettings config = ConfigSettings.getInstance();
Properties properties = System.getProperties();
properties.setProperty("mail.smtps.host", config.getMailSmtpHost());
properties.setProperty("mail.smtps.port", config.getMailSmtpPort());
properties.setProperty("mail.smtps.auth", "true");
properties.setProperty("mail.user", config.getMailUser());
properties.setProperty("mail.password", config.getMailPassword());
Session session = Session.getDefaultInstance(properties);
try{
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(config.getMailFromAddress()));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(email));
message.setSubject(subject);
message.setText(text);
Transport trnsport;
trnsport = session.getTransport("smtps");
trnsport.connect(null, properties.getProperty("mail.password"));
message.saveChanges();
trnsport.sendMessage(message, message.getAllRecipients());
trnsport.close();
return true;
}catch (MessagingException ex) {
logger.error("Error sending message to " + email, ex);
}
return false;
}
}

View file

@ -0,0 +1,37 @@
package mage.server;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.core.util.MultivaluedMapImpl;
import javax.ws.rs.core.MediaType;
import mage.server.util.ConfigSettings;
import org.apache.log4j.Logger;
public class MailgunClient {
private static final Logger logger = Logger.getLogger(Main.class);
public static boolean sendMessage(String email, String subject, String text) {
if (email.length() == 0) {
logger.info("Email is not sent because the address is empty");
return false;
}
Client client = Client.create();
client.addFilter(new HTTPBasicAuthFilter("api", ConfigSettings.getInstance().getMailgunApiKey()));
String domain = ConfigSettings.getInstance().getMailgunDomain();
WebResource webResource = client.resource("https://api.mailgun.net/v3/" + domain + "/messages");
MultivaluedMapImpl formData = new MultivaluedMapImpl();
formData.add("from", "XMage <postmaster@" + domain + ">");
formData.add("to", email);
formData.add("subject", subject);
formData.add("text", text);
ClientResponse response = webResource.type(MediaType.APPLICATION_FORM_URLENCODED).post(ClientResponse.class, formData);
boolean succeeded = response.getStatus() == 200;
if (!succeeded) {
logger.error("Error sending message to " + email + ". Status code: " + response.getStatus());
}
return succeeded;
}
}

View file

@ -1,33 +1,39 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.server; package mage.server;
import java.io.File;
import java.io.FilenameFilter;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import javax.management.MBeanServer;
import mage.cards.repository.CardScanner; import mage.cards.repository.CardScanner;
import mage.game.match.MatchType; import mage.game.match.MatchType;
import mage.game.tournament.TournamentType; import mage.game.tournament.TournamentType;
@ -37,6 +43,7 @@ import mage.server.draft.CubeFactory;
import mage.server.game.DeckValidatorFactory; import mage.server.game.DeckValidatorFactory;
import mage.server.game.GameFactory; import mage.server.game.GameFactory;
import mage.server.game.PlayerFactory; import mage.server.game.PlayerFactory;
import mage.server.record.UserStatsRepository;
import mage.server.tournament.TournamentFactory; import mage.server.tournament.TournamentFactory;
import mage.server.util.ConfigSettings; import mage.server.util.ConfigSettings;
import mage.server.util.PluginClassLoader; import mage.server.util.PluginClassLoader;
@ -46,26 +53,23 @@ import mage.server.util.config.GamePlugin;
import mage.server.util.config.Plugin; import mage.server.util.config.Plugin;
import mage.utils.MageVersion; import mage.utils.MageVersion;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.jboss.remoting.*; import org.jboss.remoting.Client;
import org.jboss.remoting.ClientDisconnectedException;
import org.jboss.remoting.ConnectionListener;
import org.jboss.remoting.InvocationRequest;
import org.jboss.remoting.InvokerLocator;
import org.jboss.remoting.Remoting;
import org.jboss.remoting.ServerInvocationHandler;
import org.jboss.remoting.ServerInvoker;
import org.jboss.remoting.callback.InvokerCallbackHandler; import org.jboss.remoting.callback.InvokerCallbackHandler;
import org.jboss.remoting.callback.ServerInvokerCallbackHandler; import org.jboss.remoting.callback.ServerInvokerCallbackHandler;
import org.jboss.remoting.transport.Connector; import org.jboss.remoting.transport.Connector;
import org.jboss.remoting.transport.bisocket.BisocketServerInvoker;
import org.jboss.remoting.transport.socket.SocketWrapper; import org.jboss.remoting.transport.socket.SocketWrapper;
import org.jboss.remoting.transporter.TransporterClient; import org.jboss.remoting.transporter.TransporterClient;
import org.jboss.remoting.transporter.TransporterServer; import org.jboss.remoting.transporter.TransporterServer;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import javax.management.MBeanServer;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import org.jboss.remoting.transport.bisocket.BisocketServerInvoker;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -80,7 +84,6 @@ public class Main {
private static final String adminPasswordArg = "-adminPassword="; private static final String adminPasswordArg = "-adminPassword=";
private static final String pluginFolder = "plugins"; private static final String pluginFolder = "plugins";
public static PluginClassLoader classLoader = new PluginClassLoader(); public static PluginClassLoader classLoader = new PluginClassLoader();
public static TransporterServer server; public static TransporterServer server;
protected static boolean testMode; protected static boolean testMode;
@ -95,15 +98,13 @@ public class Main {
logger.info("Logging level: " + logger.getEffectiveLevel()); logger.info("Logging level: " + logger.getEffectiveLevel());
String adminPassword = ""; String adminPassword = "";
for (String arg: args) { for (String arg : args) {
if (arg.startsWith(testModeArg)) { if (arg.startsWith(testModeArg)) {
testMode = Boolean.valueOf(arg.replace(testModeArg, "")); testMode = Boolean.valueOf(arg.replace(testModeArg, ""));
} } else if (arg.startsWith(adminPasswordArg)) {
else if (arg.startsWith(adminPasswordArg)) {
adminPassword = arg.replace(adminPasswordArg, ""); adminPassword = arg.replace(adminPasswordArg, "");
adminPassword = SystemUtil.sanitize(adminPassword); adminPassword = SystemUtil.sanitize(adminPassword);
} } else if (arg.startsWith(fastDBModeArg)) {
else if (arg.startsWith(fastDBModeArg)) {
fastDbMode = Boolean.valueOf(arg.replace(fastDBModeArg, "")); fastDbMode = Boolean.valueOf(arg.replace(fastDBModeArg, ""));
} }
} }
@ -116,36 +117,51 @@ public class Main {
} }
logger.info("Done."); logger.info("Done.");
logger.info("Updating user stats DB...");
UserStatsRepository.instance.updateUserStats();
logger.info("Done.");
deleteSavedGames(); deleteSavedGames();
ConfigSettings config = ConfigSettings.getInstance(); ConfigSettings config = ConfigSettings.getInstance();
for (GamePlugin plugin: config.getGameTypes()) { for (GamePlugin plugin : config.getGameTypes()) {
GameFactory.getInstance().addGameType(plugin.getName(), loadGameType(plugin), loadPlugin(plugin)); GameFactory.getInstance().addGameType(plugin.getName(), loadGameType(plugin), loadPlugin(plugin));
} }
for (GamePlugin plugin: config.getTournamentTypes()) { for (GamePlugin plugin : config.getTournamentTypes()) {
TournamentFactory.getInstance().addTournamentType(plugin.getName(), loadTournamentType(plugin), loadPlugin(plugin)); TournamentFactory.getInstance().addTournamentType(plugin.getName(), loadTournamentType(plugin), loadPlugin(plugin));
} }
for (Plugin plugin: config.getPlayerTypes()) { for (Plugin plugin : config.getPlayerTypes()) {
PlayerFactory.getInstance().addPlayerType(plugin.getName(), loadPlugin(plugin)); PlayerFactory.getInstance().addPlayerType(plugin.getName(), loadPlugin(plugin));
} }
for (Plugin plugin: config.getDraftCubes()) { for (Plugin plugin : config.getDraftCubes()) {
CubeFactory.getInstance().addDraftCube(plugin.getName(), loadPlugin(plugin)); CubeFactory.getInstance().addDraftCube(plugin.getName(), loadPlugin(plugin));
} }
for (Plugin plugin: config.getDeckTypes()) { for (Plugin plugin : config.getDeckTypes()) {
DeckValidatorFactory.getInstance().addDeckType(plugin.getName(), loadPlugin(plugin)); DeckValidatorFactory.getInstance().addDeckType(plugin.getName(), loadPlugin(plugin));
} }
logger.info("Config - max seconds idle: " + config.getMaxSecondsIdle()); logger.info("Config - max seconds idle: " + config.getMaxSecondsIdle());
logger.info("Config - max game threads: " + config.getMaxGameThreads()); logger.info("Config - max game threads: " + config.getMaxGameThreads());
logger.info("Config - max AI opponents: " + config.getMaxAiOpponents()); logger.info("Config - max AI opponents: " + config.getMaxAiOpponents());
logger.info("Config - min user name l.: " + config.getMinUserNameLength()); logger.info("Config - min usr name le.: " + config.getMinUserNameLength());
logger.info("Config - max user name l.: " + config.getMaxUserNameLength()); logger.info("Config - max usr name le.: " + config.getMaxUserNameLength());
logger.info("Config - save game active: " + (config.isSaveGameActivated() ? "True":"false")); logger.info("Config - min pswrd length: " + config.getMinPasswordLength());
logger.info("Config - max pswrd length: " + config.getMaxPasswordLength());
logger.info("Config - inv.usr name pat: " + config.getInvalidUserNamePattern());
logger.info("Config - save game active: " + (config.isSaveGameActivated() ? "true" : "false"));
logger.info("Config - backlog size : " + config.getBacklogSize()); logger.info("Config - backlog size : " + config.getBacklogSize());
logger.info("Config - lease period : " + config.getLeasePeriod()); logger.info("Config - lease period : " + config.getLeasePeriod());
logger.info("Config - max pool size : " + config.getMaxPoolSize()); logger.info("Config - max pool size : " + config.getMaxPoolSize());
logger.info("Config - num accp.threads: " + config.getNumAcceptThreads()); logger.info("Config - num accp.threads: " + config.getNumAcceptThreads());
logger.info("Config - second.bind port: " + config.getSecondaryBindPort()); logger.info("Config - second.bind port: " + config.getSecondaryBindPort());
logger.info("Config - auth. activated : " + (config.isAuthenticationActivated() ? "true" : "false"));
logger.info("Config - mailgun api key : " + config.getMailgunApiKey());
logger.info("Config - mailgun domain : " + config.getMailgunDomain());
logger.info("Config - mail smtp Host : " + config.getMailSmtpHost());
logger.info("Config - mail smtpPort : " + config.getMailSmtpPort());
logger.info("Config - mail user : " + config.getMailUser());
logger.info("Config - mail passw. len.: " + config.getMailPassword().length());
logger.info("Config - mail from addre.: " + config.getMailFromAddress());
logger.info("Config - google account : " + config.getGoogleAccount());
Connection connection = new Connection("&maxPoolSize=" + config.getMaxPoolSize()); Connection connection = new Connection("&maxPoolSize=" + config.getMaxPoolSize());
connection.setHost(config.getServerAddress()); connection.setHost(config.getServerAddress());
@ -162,8 +178,7 @@ public class Main {
logger.info("MAGE server running in test mode"); logger.info("MAGE server running in test mode");
} }
initStatistics(); initStatistics();
} } else {
else {
logger.fatal("Unable to start MAGE server - another server is already started"); logger.fatal("Unable to start MAGE server - another server is already started");
} }
} catch (Exception ex) { } catch (Exception ex) {
@ -192,6 +207,7 @@ public class Main {
} }
static class ClientConnectionListener implements ConnectionListener { static class ClientConnectionListener implements ConnectionListener {
@Override @Override
public void handleConnectionException(Throwable throwable, Client client) { public void handleConnectionException(Throwable throwable, Client client) {
Session session = SessionManager.getInstance().getSession(client.getSessionId()); Session session = SessionManager.getInstance().getSession(client.getSessionId());
@ -330,7 +346,7 @@ public class Main {
logger.debug("Loading tournament type: " + plugin.getClassName()); logger.debug("Loading tournament type: " + plugin.getClassName());
return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance();
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
logger.warn("Tournament type not found:" + plugin.getName() + " / "+ plugin.getJar() + " - check plugin folder", ex); logger.warn("Tournament type not found:" + plugin.getName() + " / " + plugin.getJar() + " - check plugin folder", ex);
} catch (Exception ex) { } catch (Exception ex) {
logger.fatal("Error loading game type " + plugin.getJar(), ex); logger.fatal("Error loading game type " + plugin.getJar(), ex);
} }
@ -350,8 +366,7 @@ public class Main {
} }
} }
); );
for (File file : files) for (File file : files) {
{
file.delete(); file.delete();
} }
} }

View file

@ -55,6 +55,8 @@ import org.jboss.remoting.callback.InvokerCallbackHandler;
public class Session { public class Session {
private static final Logger logger = Logger.getLogger(Session.class); private static final Logger logger = Logger.getLogger(Session.class);
private final static Pattern alphabetsPattern = Pattern.compile("[a-zA-Z]");
private final static Pattern digitsPattern = Pattern.compile("[0-9]");
private final String sessionId; private final String sessionId;
private UUID userId; private UUID userId;
@ -74,8 +76,98 @@ public class Session {
this.lock = new ReentrantLock(); this.lock = new ReentrantLock();
} }
public String registerUser(String userName) throws MageException { public String registerUser(String userName, String password, String email) throws MageException {
String returnMessage = registerUserHandling(userName); if (!ConfigSettings.getInstance().isAuthenticationActivated()) {
String returnMessage = "Registration is disabled by the server config";
sendErrorMessageToClient(returnMessage);
return returnMessage;
}
synchronized (AuthorizedUserRepository.instance) {
String returnMessage = validateUserName(userName);
if (returnMessage != null) {
sendErrorMessageToClient(returnMessage);
return returnMessage;
}
returnMessage = validatePassword(password, userName);
if (returnMessage != null) {
sendErrorMessageToClient(returnMessage);
return returnMessage;
}
returnMessage = validateEmail(email);
if (returnMessage != null) {
sendErrorMessageToClient(returnMessage);
return returnMessage;
}
AuthorizedUserRepository.instance.add(userName, password, email);
String subject = "XMage Registration Completed";
String text = "You are successfully registered as " + userName + ".";
boolean success;
if (!ConfigSettings.getInstance().getMailUser().isEmpty()) {
success = MailClient.sendMessage(email, subject, text);
} else {
success = MailgunClient.sendMessage(email, subject, text);
}
if (success) {
logger.info("Sent a registration confirmation email to " + email + " for " + userName);
} else {
logger.error("Failed sending a registration confirmation email to " + email + " for " + userName);
}
return null;
}
}
static private String validateUserName(String userName) {
if (userName.equals("Admin")) {
return "User name Admin already in use";
}
ConfigSettings config = ConfigSettings.getInstance();
if (userName.length() < config.getMinUserNameLength()) {
return "User name may not be shorter than " + config.getMinUserNameLength() + " characters";
}
if (userName.length() > config.getMaxUserNameLength()) {
return "User name may not be longer than " + config.getMaxUserNameLength() + " characters";
}
Pattern invalidUserNamePattern = Pattern.compile(ConfigSettings.getInstance().getInvalidUserNamePattern(), Pattern.CASE_INSENSITIVE);
Matcher m = invalidUserNamePattern.matcher(userName);
if (m.find()) {
return "User name '" + userName + "' includes not allowed characters: use a-z, A-Z and 0-9";
}
AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByName(userName);
if (authorizedUser != null) {
return "User name '" + userName + "' already in use";
}
return null;
}
static private String validatePassword(String password, String userName) {
ConfigSettings config = ConfigSettings.getInstance();
if (password.length() < config.getMinPasswordLength()) {
return "Password may not be shorter than " + config.getMinPasswordLength() + " characters";
}
if (password.length() > config.getMaxPasswordLength()) {
return "Password may not be longer than " + config.getMaxPasswordLength() + " characters";
}
if (password.equals(userName)) {
return "Password may not be the same as your username";
}
Matcher alphabetsMatcher = alphabetsPattern.matcher(password);
Matcher digitsMatcher = digitsPattern.matcher(password);
if (!alphabetsMatcher.find() || !digitsMatcher.find()) {
return "Password has to include at least one alphabet (a-zA-Z) and also at least one digit (0-9)";
}
return null;
}
static private String validateEmail(String email) {
AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByEmail(email);
if (authorizedUser != null) {
return "Email address '" + email + "' is associated with another user";
}
return null;
}
public String connectUser(String userName, String password) throws MageException {
String returnMessage = connectUserHandling(userName, password);
if (returnMessage != null) { if (returnMessage != null) {
sendErrorMessageToClient(returnMessage); sendErrorMessageToClient(returnMessage);
} }
@ -86,27 +178,21 @@ public class Session {
return lock.isLocked(); return lock.isLocked();
} }
public String registerUserHandling(String userName) throws MageException { public String connectUserHandling(String userName, String password) throws MageException {
this.isAdmin = false; this.isAdmin = false;
if (userName.equals("Admin")) { if (ConfigSettings.getInstance().isAuthenticationActivated()) {
return "User name Admin already in use"; AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByName(userName);
if (authorizedUser == null || !authorizedUser.doCredentialsMatch(userName, password)) {
return "Wrong username or password. In case you haven't, please register your account first.";
} }
if (userName.length() > ConfigSettings.getInstance().getMaxUserNameLength()) {
return "User name may not be longer than " + ConfigSettings.getInstance().getMaxUserNameLength() + " characters";
}
if (userName.length() < ConfigSettings.getInstance().getMinUserNameLength()) {
return "User name may not be shorter than " + ConfigSettings.getInstance().getMinUserNameLength() + " characters";
}
Pattern p = Pattern.compile(ConfigSettings.getInstance().getUserNamePattern(), Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(userName);
if (m.find()) {
return "User name '" + userName + "' includes not allowed characters: use a-z, A-Z and 0-9";
} }
User user = UserManager.getInstance().createUser(userName, host); User user = UserManager.getInstance().createUser(userName, host);
boolean reconnect = false; boolean reconnect = false;
if (user == null) { // user already exists if (user == null) { // user already exists
user = UserManager.getInstance().findUser(userName); user = UserManager.getInstance().getUserByName(userName);
if (user.getHost().equals(host)) { // If authentication is not activated, check the identity using IP address.
if (ConfigSettings.getInstance().isAuthenticationActivated() || user.getHost().equals(host)) {
user.updateLastActivity(null); // minimizes possible expiration user.updateLastActivity(null); // minimizes possible expiration
this.userId = user.getId(); this.userId = user.getId();
if (user.getSessionId().isEmpty()) { if (user.getSessionId().isEmpty()) {
@ -135,11 +221,11 @@ public class Session {
return null; return null;
} }
public void registerAdmin() { public void connectAdmin() {
this.isAdmin = true; this.isAdmin = true;
User user = UserManager.getInstance().createUser("Admin", host); User user = UserManager.getInstance().createUser("Admin", host);
if (user == null) { if (user == null) {
user = UserManager.getInstance().findUser("Admin"); user = UserManager.getInstance().getUserByName("Admin");
} }
UserData adminUserData = UserData.getDefaultUserDataView(); UserData adminUserData = UserData.getDefaultUserDataView();
adminUserData.setGroupId(UserGroup.ADMIN.getGroupId()); adminUserData.setGroupId(UserGroup.ADMIN.getGroupId());
@ -151,7 +237,7 @@ public class Session {
} }
public boolean setUserData(String userName, UserData userData) { public boolean setUserData(String userName, UserData userData) {
User user = UserManager.getInstance().findUser(userName); User user = UserManager.getInstance().getUserByName(userName);
if (user != null) { if (user != null) {
if (user.getUserData() == null || user.getUserData().getGroupId() == UserGroup.DEFAULT.getGroupId()) { if (user.getUserData() == null || user.getUserData().getGroupId() == UserGroup.DEFAULT.getGroupId()) {
user.setUserData(userData); user.setUserData(userData);
@ -279,7 +365,7 @@ public class Session {
this.host = hostAddress; this.host = hostAddress;
} }
void sendErrorMessageToClient(String message) { public void sendErrorMessageToClient(String message) {
List<String> messageData = new LinkedList<>(); List<String> messageData = new LinkedList<>();
messageData.add("Error while connecting to server"); messageData.add("Error while connecting to server");
messageData.add(message); messageData.add(message);

View file

@ -70,31 +70,51 @@ public class SessionManager {
sessions.put(sessionId, session); sessions.put(sessionId, session);
} }
public boolean registerUser(String sessionId, String userName) throws MageException { public boolean registerUser(String sessionId, String userName, String password, String email) throws MageException {
Session session = sessions.get(sessionId);
if (session == null) {
logger.error(userName + " tried to register with no sessionId");
return false;
}
String returnMessage = session.registerUser(userName, password, email);
if (returnMessage != null) {
logger.debug(userName + " not registered: " + returnMessage);
return false;
}
LogServiceImpl.instance.log(LogKeys.KEY_USER_REGISTERED, userName, session.getHost(), sessionId);
logger.info(userName + " registered");
logger.debug("- userId: " + session.getUserId());
logger.debug("- sessionId: " + sessionId);
logger.debug("- host: " + session.getHost());
return true;
}
public boolean connectUser(String sessionId, String userName, String password) throws MageException {
Session session = sessions.get(sessionId); Session session = sessions.get(sessionId);
if (session != null) { if (session != null) {
String returnMessage = session.registerUser(userName); String returnMessage = session.connectUser(userName, password);
if (returnMessage == null) { if (returnMessage == null) {
LogServiceImpl.instance.log(LogKeys.KEY_USER_CONNECTED, userName, session.getHost(), sessionId); LogServiceImpl.instance.log(LogKeys.KEY_USER_CONNECTED, userName, session.getHost(), sessionId);
logger.info(userName + " joined server"); logger.info(userName + " connected to server");
logger.debug("- userId: " + session.getUserId()); logger.debug("- userId: " + session.getUserId());
logger.debug("- sessionId: " + sessionId); logger.debug("- sessionId: " + sessionId);
logger.debug("- host: " + session.getHost()); logger.debug("- host: " + session.getHost());
return true; return true;
} else { } else {
logger.debug(userName + " not registered: " + returnMessage); logger.debug(userName + " not connected: " + returnMessage);
} }
} else { } else {
logger.error(userName + " tried to join with no sessionId"); logger.error(userName + " tried to connect with no sessionId");
} }
return false; return false;
} }
public boolean registerAdmin(String sessionId) { public boolean connectAdmin(String sessionId) {
Session session = sessions.get(sessionId); Session session = sessions.get(sessionId);
if (session != null) { if (session != null) {
session.registerAdmin(); session.connectAdmin();
LogServiceImpl.instance.log(LogKeys.KEY_ADMIN_CONNECTED, "Admin", session.getHost(), sessionId); LogServiceImpl.instance.log(LogKeys.KEY_ADMIN_CONNECTED, "Admin", session.getHost(), sessionId);
logger.info("Admin connected from " + session.getHost()); logger.info("Admin connected from " + session.getHost());
return true; return true;
@ -217,4 +237,13 @@ public class SessionManager {
} }
return false; return false;
} }
public void sendErrorMessageToClient(String sessionId, String message) {
Session session = sessions.get(sessionId);
if (session == null) {
logger.error("Following error message is not delivered because session " + sessionId + " is not found: " + message);
return;
}
session.sendErrorMessageToClient(message);
}
} }

View file

@ -62,6 +62,7 @@ import mage.server.game.DeckValidatorFactory;
import mage.server.game.GameFactory; import mage.server.game.GameFactory;
import mage.server.game.GameManager; import mage.server.game.GameManager;
import mage.server.game.PlayerFactory; import mage.server.game.PlayerFactory;
import mage.server.record.TableRecorderImpl;
import mage.server.services.LogKeys; import mage.server.services.LogKeys;
import mage.server.services.impl.LogServiceImpl; import mage.server.services.impl.LogServiceImpl;
import mage.server.tournament.TournamentController; import mage.server.tournament.TournamentController;
@ -105,7 +106,7 @@ public class TableController {
} else { } else {
controllerName = "System"; controllerName = "System";
} }
table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), match); table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), match);
chatId = ChatManager.getInstance().createChatSession("Match Table " + table.getId()); chatId = ChatManager.getInstance().createChatSession("Match Table " + table.getId());
init(); init();
} }
@ -124,7 +125,7 @@ public class TableController {
} else { } else {
controllerName = "System"; controllerName = "System";
} }
table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), tournament); table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), tournament);
chatId = ChatManager.getInstance().createChatSession("Tourn. table " + table.getId()); chatId = ChatManager.getInstance().createChatSession("Tourn. table " + table.getId());
} }
@ -237,6 +238,7 @@ public class TableController {
TournamentPlayer newTournamentPlayer = tournament.getPlayer(newPlayer.getId()); TournamentPlayer newTournamentPlayer = tournament.getPlayer(newPlayer.getId());
newTournamentPlayer.setState(oldTournamentPlayer.getState()); newTournamentPlayer.setState(oldTournamentPlayer.getState());
newTournamentPlayer.setReplacedTournamentPlayer(oldTournamentPlayer);
DraftManager.getInstance().getController(table.getId()).replacePlayer(oldPlayer, newPlayer); DraftManager.getInstance().getController(table.getId()).replacePlayer(oldPlayer, newPlayer);
return true; return true;
@ -957,15 +959,7 @@ public class TableController {
return getTable().getState(); return getTable().getState();
} }
public synchronized boolean changeTableState(TableState newTableState) { public synchronized boolean changeTableStateToStarting() {
switch (newTableState) {
case WAITING:
if (getTable().getState().equals(TableState.STARTING)) {
// tournament already started
return false;
}
break;
case STARTING:
if (!getTable().getState().equals(TableState.READY_TO_START)) { if (!getTable().getState().equals(TableState.READY_TO_START)) {
// tournament is not ready, can't start // tournament is not ready, can't start
return false; return false;
@ -974,9 +968,7 @@ public class TableController {
logger.debug("Not alle Seats are occupied: stop start tableId:" + table.getId()); logger.debug("Not alle Seats are occupied: stop start tableId:" + table.getId());
return false; return false;
} }
break; getTable().setState(TableState.STARTING);
}
getTable().setState(newTableState);
return true; return true;
} }
} }

View file

@ -40,12 +40,15 @@ import java.util.concurrent.TimeUnit;
import mage.cards.decks.Deck; import mage.cards.decks.Deck;
import mage.constants.ManaType; import mage.constants.ManaType;
import mage.game.Table; import mage.game.Table;
import mage.game.result.ResultProtos;
import mage.game.tournament.TournamentPlayer; import mage.game.tournament.TournamentPlayer;
import mage.interfaces.callback.ClientCallback; import mage.interfaces.callback.ClientCallback;
import mage.players.net.UserData; import mage.players.net.UserData;
import mage.server.draft.DraftSession; import mage.server.draft.DraftSession;
import mage.server.game.GameManager; import mage.server.game.GameManager;
import mage.server.game.GameSessionPlayer; import mage.server.game.GameSessionPlayer;
import mage.server.record.UserStats;
import mage.server.record.UserStatsRepository;
import mage.server.tournament.TournamentController; import mage.server.tournament.TournamentController;
import mage.server.tournament.TournamentManager; import mage.server.tournament.TournamentManager;
import mage.server.tournament.TournamentSession; import mage.server.tournament.TournamentSession;
@ -59,7 +62,7 @@ import org.apache.log4j.Logger;
*/ */
public class User { public class User {
private static final Logger logger = Logger.getLogger(User.class); private static final Logger LOGGER = Logger.getLogger(User.class);
public enum UserState { public enum UserState {
@ -79,11 +82,11 @@ public class User {
private final Map<UUID, Deck> sideboarding; private final Map<UUID, Deck> sideboarding;
private final List<UUID> watchedGames; private final List<UUID> watchedGames;
private String sessionId; private String sessionId;
private String info = "";
private String pingInfo = ""; private String pingInfo = "";
private Date lastActivity; private Date lastActivity;
private UserState userState; private UserState userState;
private UserData userData; private UserData userData;
private UserStats userStats;
public User(String userName, String host) { public User(String userName, String host) {
this.userId = UUID.randomUUID(); this.userId = UUID.randomUUID();
@ -103,6 +106,7 @@ public class User {
this.watchedGames = new ArrayList<>(); this.watchedGames = new ArrayList<>();
this.tablesToDelete = new ArrayList<>(); this.tablesToDelete = new ArrayList<>();
this.sessionId = ""; this.sessionId = "";
this.userStats = null;
} }
public String getName() { public String getName() {
@ -126,15 +130,15 @@ public class User {
if (sessionId.isEmpty()) { if (sessionId.isEmpty()) {
userState = UserState.Disconnected; userState = UserState.Disconnected;
lostConnection(); lostConnection();
logger.trace("USER - lost connection: " + userName + " id: " + userId); LOGGER.trace("USER - lost connection: " + userName + " id: " + userId);
} else if (userState == UserState.Created) { } else if (userState == UserState.Created) {
userState = UserState.Connected; userState = UserState.Connected;
logger.trace("USER - created: " + userName + " id: " + userId); LOGGER.trace("USER - created: " + userName + " id: " + userId);
} else { } else {
userState = UserState.Reconnected; userState = UserState.Reconnected;
reconnect(); reconnect();
logger.trace("USER - reconnected: " + userName + " id: " + userId); LOGGER.trace("USER - reconnected: " + userName + " id: " + userId);
} }
} }
@ -270,12 +274,13 @@ public class User {
public boolean isExpired(Date expired) { public boolean isExpired(Date expired) {
if (lastActivity.before(expired)) { if (lastActivity.before(expired)) {
logger.trace(userName + " is expired!"); LOGGER.trace(userName + " is expired!");
userState = UserState.Expired; userState = UserState.Expired;
return true; return true;
} }
logger.trace(new StringBuilder("isExpired: User ").append(userName).append(" lastActivity: ").append(lastActivity).append(" expired: ").append(expired).toString()); LOGGER.trace(new StringBuilder("isExpired: User ").append(userName).append(" lastActivity: ").append(lastActivity).append(" expired: ").append(expired).toString());
return false; /*userState == UserState.Disconnected && */ return false;
/*userState == UserState.Disconnected && */
} }
@ -357,35 +362,35 @@ public class User {
} }
public void remove(DisconnectReason reason) { public void remove(DisconnectReason reason) {
logger.trace("REMOVE " + getName() + " Draft sessions " + draftSessions.size()); LOGGER.trace("REMOVE " + getName() + " Draft sessions " + draftSessions.size());
for (DraftSession draftSession : draftSessions.values()) { for (DraftSession draftSession : draftSessions.values()) {
draftSession.setKilled(); draftSession.setKilled();
} }
draftSessions.clear(); draftSessions.clear();
logger.trace("REMOVE " + getName() + " Tournament sessions " + userTournaments.size()); LOGGER.trace("REMOVE " + getName() + " Tournament sessions " + userTournaments.size());
for (UUID tournamentId : userTournaments.values()) { for (UUID tournamentId : userTournaments.values()) {
TournamentManager.getInstance().quit(tournamentId, getId()); TournamentManager.getInstance().quit(tournamentId, getId());
} }
userTournaments.clear(); userTournaments.clear();
logger.trace("REMOVE " + getName() + " Tables " + tables.size()); LOGGER.trace("REMOVE " + getName() + " Tables " + tables.size());
for (Entry<UUID, Table> entry : tables.entrySet()) { for (Entry<UUID, Table> entry : tables.entrySet()) {
logger.debug("-- leave tableId: " + entry.getValue().getId()); LOGGER.debug("-- leave tableId: " + entry.getValue().getId());
TableManager.getInstance().leaveTable(userId, entry.getValue().getId()); TableManager.getInstance().leaveTable(userId, entry.getValue().getId());
} }
tables.clear(); tables.clear();
logger.trace("REMOVE " + getName() + " Game sessions: " + gameSessions.size()); LOGGER.trace("REMOVE " + getName() + " Game sessions: " + gameSessions.size());
for (GameSessionPlayer gameSessionPlayer : gameSessions.values()) { for (GameSessionPlayer gameSessionPlayer : gameSessions.values()) {
logger.debug("-- kill game session of gameId: " + gameSessionPlayer.getGameId()); LOGGER.debug("-- kill game session of gameId: " + gameSessionPlayer.getGameId());
GameManager.getInstance().quitMatch(gameSessionPlayer.getGameId(), userId); GameManager.getInstance().quitMatch(gameSessionPlayer.getGameId(), userId);
gameSessionPlayer.quitGame(); gameSessionPlayer.quitGame();
} }
gameSessions.clear(); gameSessions.clear();
logger.trace("REMOVE " + getName() + " watched Games " + watchedGames.size()); LOGGER.trace("REMOVE " + getName() + " watched Games " + watchedGames.size());
for (UUID gameId : watchedGames) { for (UUID gameId : watchedGames) {
GameManager.getInstance().stopWatching(gameId, userId); GameManager.getInstance().stopWatching(gameId, userId);
} }
watchedGames.clear(); watchedGames.clear();
logger.trace("REMOVE " + getName() + " Chats "); LOGGER.trace("REMOVE " + getName() + " Chats ");
ChatManager.getInstance().removeUser(userId, reason); ChatManager.getInstance().removeUser(userId, reason);
} }
@ -394,6 +399,12 @@ public class User {
this.userData.update(userData); this.userData.update(userData);
} else { } else {
this.userData = userData; this.userData = userData;
this.userStats = UserStatsRepository.instance.getUser(this.userName);
if (userStats != null) {
this.userData.setHistory(userStatsToString(userStats.getProto()));
} else {
this.userData.setHistory("<new player>");
}
} }
} }
@ -443,11 +454,11 @@ public class User {
} }
} else { } else {
// can happen if tournamet has just ended // can happen if tournamet has just ended
logger.debug(getName() + " tournament player missing - tableId:" + table.getId(), null); LOGGER.debug(getName() + " tournament player missing - tableId:" + table.getId(), null);
tablesToDelete.add(tableEntry.getKey()); tablesToDelete.add(tableEntry.getKey());
} }
} else { } else {
logger.error(getName() + " tournament key missing - tableId: " + table.getId(), null); LOGGER.error(getName() + " tournament key missing - tableId: " + table.getId(), null);
} }
} else { } else {
switch (table.getState()) { switch (table.getState()) {
@ -497,14 +508,6 @@ public class User {
return sb.toString(); return sb.toString();
} }
public String getInfo() {
return info;
}
public void setInfo(String Info) {
this.info = Info;
}
public void addGameWatchInfo(UUID gameId) { public void addGameWatchInfo(UUID gameId) {
watchedGames.add(gameId); watchedGames.add(gameId);
} }
@ -525,4 +528,96 @@ public class User {
} }
} }
// getUserStats returns the UserStats for this user. This caches the result, so if the stats is
// updated call resetUserStats to refresh it.
public UserStats getUserStats() {
if (this.userStats == null) {
resetUserStats();
}
return this.userStats;
}
// resetUserStats loads UserStats from DB.
public void resetUserStats() {
this.userStats = UserStatsRepository.instance.getUser(this.userName);
if (userData != null) {
userData.setHistory(userStatsToString(userStats.getProto()));
}
}
public String getHistory() {
if (userData != null) {
return userData.getHistory();
}
return "<not available>";
}
public static String userStatsToString(ResultProtos.UserStatsProto proto) {
List<StringBuilder> builders = new ArrayList<>();
if (proto.getMatches() > 0) {
StringBuilder builder = new StringBuilder();
builder.append("Matches:");
builder.append(proto.getMatches());
List<String> quit = new ArrayList<>();
if (proto.getMatchesIdleTimeout() > 0) {
quit.add("I:" + Integer.toString(proto.getMatchesIdleTimeout()));
}
if (proto.getMatchesTimerTimeout() > 0) {
quit.add("T:" + Integer.toString(proto.getMatchesTimerTimeout()));
}
if (proto.getMatchesQuit() > 0) {
quit.add("Q:" + Integer.toString(proto.getMatchesQuit()));
}
if (quit.size() > 0) {
builder.append(" (");
joinStrings(builder, quit, " ");
builder.append(")");
}
builders.add(builder);
}
if (proto.getTourneys() > 0) {
StringBuilder builder = new StringBuilder();
builder.append("Tourneys:");
builder.append(proto.getTourneys());
List<String> quit = new ArrayList<>();
if (proto.getTourneysQuitDuringDrafting() > 0) {
quit.add("D:" + Integer.toString(proto.getTourneysQuitDuringDrafting()));
}
if (proto.getTourneysQuitDuringConstruction() > 0) {
quit.add("C:" + Integer.toString(proto.getTourneysQuitDuringConstruction()));
}
if (proto.getTourneysQuitDuringRound() > 0) {
quit.add("R:" + Integer.toString(proto.getTourneysQuitDuringRound()));
}
if (quit.size() > 0) {
builder.append(" (");
joinStrings(builder, quit, " ");
builder.append(")");
}
builders.add(builder);
}
return joinBuilders(builders);
}
private static String joinBuilders(List<StringBuilder> builders) {
if (builders.isEmpty()) {
return null;
}
StringBuilder builder = builders.get(0);
for (int i = 1; i < builders.size(); ++i) {
builder.append(" ");
builder.append(builders.get(i));
}
return builder.toString();
}
private static void joinStrings(StringBuilder joined, List<String> strings, String separator) {
for (int i = 0; i < strings.size(); ++i) {
if (i > 0) {
joined.append(separator);
}
joined.append(strings.get(i));
}
}
} }

View file

@ -38,6 +38,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import mage.server.User.UserState; import mage.server.User.UserState;
import mage.server.record.UserStats;
import mage.server.record.UserStatsRepository;
import mage.server.util.ThreadExecutor; import mage.server.util.ThreadExecutor;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -55,6 +57,7 @@ public class UserManager {
private static final Logger logger = Logger.getLogger(UserManager.class); private static final Logger logger = Logger.getLogger(UserManager.class);
private final ConcurrentHashMap<UUID, User> users = new ConcurrentHashMap<>(); private final ConcurrentHashMap<UUID, User> users = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, User> usersByName = new ConcurrentHashMap<>();
private static final ExecutorService callExecutor = ThreadExecutor.getInstance().getCallExecutor(); private static final ExecutorService callExecutor = ThreadExecutor.getInstance().getCallExecutor();
@ -74,11 +77,12 @@ public class UserManager {
} }
public User createUser(String userName, String host) { public User createUser(String userName, String host) {
if (findUser(userName) != null) { if (getUserByName(userName) != null) {
return null; //user already exists return null; //user already exists
} }
User user = new User(userName, host); User user = new User(userName, host);
users.put(user.getId(), user); users.put(user.getId(), user);
usersByName.put(userName, user);
return user; return user;
} }
@ -89,13 +93,8 @@ public class UserManager {
return null; return null;
} }
public User findUser(String userName) { public User getUserByName(String userName) {
for (User user: users.values()) { return usersByName.get(userName);
if (user.getName().equals(userName)) {
return user;
}
}
return null;
} }
public Collection<User> getUsers() { public Collection<User> getUsers() {
@ -149,6 +148,7 @@ public class UserManager {
handleException(ex); handleException(ex);
} finally { } finally {
users.remove(userId); users.remove(userId);
usersByName.remove(user.getName());
} }
} }
} }
@ -171,7 +171,8 @@ public class UserManager {
} }
/** /**
* Is the connection lost for more than 3 minutes, the user will be removed (within 3 minutes the user can reconnect) * Is the connection lost for more than 3 minutes, the user will be removed
* (within 3 minutes the user can reconnect)
*/ */
private void checkExpired() { private void checkExpired() {
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
@ -187,13 +188,39 @@ public class UserManager {
public void handleException(Exception ex) { public void handleException(Exception ex) {
if (ex != null) { if (ex != null) {
logger.fatal("User manager exception " + (ex.getMessage() == null ? "null":ex.getMessage())); logger.fatal("User manager exception " + (ex.getMessage() == null ? "null" : ex.getMessage()));
if (ex.getCause() != null) { if (ex.getCause() != null) {
logger.debug("- Cause: " + (ex.getCause().getMessage() == null ? "null":ex.getCause().getMessage())); logger.debug("- Cause: " + (ex.getCause().getMessage() == null ? "null" : ex.getCause().getMessage()));
} }
ex.printStackTrace(); ex.printStackTrace();
}else { } else {
logger.fatal("User manager exception - null"); logger.fatal("User manager exception - null");
} }
} }
public String getUserHistory(String userName) {
User user = getUserByName(userName);
if (user == null) {
UserStats userStats = UserStatsRepository.instance.getUser(userName);
if (userStats == null) {
return "User " + userName + " not found";
}
return User.userStatsToString(userStats.getProto());
}
return "History of user " + userName + ": " + user.getUserData().getHistory();
}
public void updateUserHistory() {
callExecutor.execute(new Runnable() {
@Override
public void run() {
for (String updatedUser : UserStatsRepository.instance.updateUserStats()) {
User user = getUserByName(updatedUser);
if (user != null) {
user.resetUserStats();
}
}
}
});
}
} }

View file

@ -100,11 +100,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
if (table.getState() != TableState.FINISHED) { if (table.getState() != TableState.FINISHED) {
tableList.add(new TableView(table)); tableList.add(new TableView(table));
} else if (matchList.size() < 50) { } else if (matchList.size() < 50) {
if (table.isTournament()) {
matchList.add(new MatchView(table)); matchList.add(new MatchView(table));
} else {
matchList.add(new MatchView(table));
}
} else { } else {
// more since 50 matches finished since this match so remove it // more since 50 matches finished since this match so remove it
if (table.isTournament()) { if (table.isTournament()) {
@ -118,13 +114,13 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
List<UsersView> users = new ArrayList<>(); List<UsersView> users = new ArrayList<>();
for (User user : UserManager.getInstance().getUsers()) { for (User user : UserManager.getInstance().getUsers()) {
try { try {
users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), user.getInfo(), user.getGameInfo(), user.getPingInfo())); users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), user.getHistory(), user.getGameInfo(), user.getPingInfo()));
} catch (Exception ex) { } catch (Exception ex) {
logger.fatal("User update exception: " + user.getName() + " - " + ex.toString(), ex); logger.fatal("User update exception: " + user.getName() + " - " + ex.toString(), ex);
users.add(new UsersView( users.add(new UsersView(
(user.getUserData() != null && user.getUserData().getFlagName() != null) ? user.getUserData().getFlagName() : "world", (user.getUserData() != null && user.getUserData().getFlagName() != null) ? user.getUserData().getFlagName() : "world",
user.getName() != null ? user.getName() : "<no name>", user.getName() != null ? user.getName() : "<no name>",
user.getInfo() != null ? user.getInfo() : "<no info>", user.getHistory() != null ? user.getHistory() : "<no history>",
"[exception]", "[exception]",
user.getPingInfo() != null ? user.getPingInfo() : "<no ping>")); user.getPingInfo() != null ? user.getPingInfo() : "<no ping>"));
} }

View file

@ -0,0 +1,37 @@
package mage.server.record;
import com.j256.ormlite.field.DataType;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import mage.game.result.ResultProtos.TableProto;
import org.mage.mage.shaded.protobuf.InvalidProtocolBufferException;
import org.apache.log4j.Logger;
@DatabaseTable(tableName = "table_history")
public class TableRecord {
private static final Logger logger = Logger.getLogger(TableRecord.class);
@DatabaseField(dataType = DataType.BYTE_ARRAY, indexName = "proto_index", unique = true)
protected byte[] proto;
@DatabaseField(indexName = "end_time_ms")
protected long endTimeMs;
public TableRecord() {
}
public TableRecord(TableProto proto, long endTimeMs) {
this.proto = proto.toByteArray();
this.endTimeMs = endTimeMs;
}
public TableProto getProto() {
try {
return TableProto.parseFrom(this.proto);
} catch (InvalidProtocolBufferException ex) {
logger.error("Failed to parse serialized proto", ex);
}
return null;
}
}

View file

@ -0,0 +1,77 @@
package mage.server.record;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.support.DatabaseConnection;
import com.j256.ormlite.table.TableUtils;
import java.io.File;
import java.sql.SQLException;
import java.util.List;
import mage.cards.repository.RepositoryUtil;
import org.apache.log4j.Logger;
public enum TableRecordRepository {
instance;
private static final String JDBC_URL = "jdbc:sqlite:./db/table_record.db";
private static final String VERSION_ENTITY_NAME = "table_record";
// raise this if db structure was changed
private static final long DB_VERSION = 0;
private Dao<TableRecord, Object> dao;
private TableRecordRepository() {
File file = new File("db");
if (!file.exists()) {
file.mkdirs();
}
try {
ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL);
boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, DB_VERSION);
if (obsolete) {
TableUtils.dropTable(connectionSource, TableRecord.class, true);
}
TableUtils.createTableIfNotExists(connectionSource, TableRecord.class);
dao = DaoManager.createDao(connectionSource, TableRecord.class);
} catch (SQLException ex) {
Logger.getLogger(TableRecordRepository.class).error("Error creating table_record repository - ", ex);
}
}
public void add(TableRecord tableHistory) {
try {
dao.create(tableHistory);
} catch (SQLException ex) {
Logger.getLogger(TableRecordRepository.class).error("Error adding a table_record to DB - ", ex);
}
}
public List<TableRecord> getAfter(long endTimeMs) {
try {
QueryBuilder<TableRecord, Object> qb = dao.queryBuilder();
qb.where().gt("endTimeMs", endTimeMs);
qb.orderBy("endTimeMs", true);
return dao.query(qb.prepare());
} catch (SQLException ex) {
Logger.getLogger(TableRecordRepository.class).error("Error getting table_records from DB - ", ex);
}
return null;
}
public void closeDB() {
try {
if (dao != null && dao.getConnectionSource() != null) {
DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection();
conn.executeStatement("shutdown compact", 0);
}
} catch (SQLException ex) {
Logger.getLogger(TableRecordRepository.class).error("Error closing table_record repository - ", ex);
}
}
}

View file

@ -0,0 +1,23 @@
package mage.server.record;
import mage.game.Table;
import mage.game.Table.TableRecorder;
import mage.game.result.ResultProtos.TableProto;
import mage.server.UserManager;
import org.apache.log4j.Logger;
public class TableRecorderImpl implements TableRecorder {
private static TableRecorderImpl INSTANCE = new TableRecorderImpl();
private static final Logger logger = Logger.getLogger(TableRecorderImpl.class);
public static TableRecorderImpl getInstance() {
return INSTANCE;
}
public void record(Table table) {
TableProto proto = table.toProto();
TableRecordRepository.instance.add(new TableRecord(proto, proto.getEndTimeMs()));
UserManager.getInstance().updateUserHistory();
}
}

View file

@ -0,0 +1,45 @@
package mage.server.record;
import com.j256.ormlite.field.DataType;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import mage.game.result.ResultProtos.UserStatsProto;
import org.mage.mage.shaded.protobuf.InvalidProtocolBufferException;
import org.apache.log4j.Logger;
@DatabaseTable(tableName = "user_stats")
public class UserStats {
private static final Logger logger = Logger.getLogger(TableRecord.class);
@DatabaseField(indexName = "user_name_index", unique = true, id = true)
protected String userName;
@DatabaseField(dataType = DataType.BYTE_ARRAY)
protected byte[] proto;
@DatabaseField(indexName = "end_time_ms_index")
protected long endTimeMs;
public UserStats() {
}
public UserStats(UserStatsProto proto, long endTimeMs) {
this.userName = proto.getName();
this.proto = proto.toByteArray();
this.endTimeMs = endTimeMs;
}
public UserStatsProto getProto() {
try {
return UserStatsProto.parseFrom(this.proto);
} catch (InvalidProtocolBufferException ex) {
logger.error("Failed to parse serialized proto", ex);
}
return null;
}
public long getEndTimeMs() {
return this.endTimeMs;
}
}

View file

@ -0,0 +1,187 @@
package mage.server.record;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.support.DatabaseConnection;
import com.j256.ormlite.table.TableUtils;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import mage.cards.repository.RepositoryUtil;
import mage.game.result.ResultProtos;
import org.apache.log4j.Logger;
public enum UserStatsRepository {
instance;
private static final String JDBC_URL = "jdbc:sqlite:./db/user_stats.db";
private static final String VERSION_ENTITY_NAME = "user_stats";
// raise this if db structure was changed
private static final long DB_VERSION = 0;
private Dao<UserStats, Object> dao;
private UserStatsRepository() {
File file = new File("db");
if (!file.exists()) {
file.mkdirs();
}
try {
ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL);
boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, DB_VERSION);
if (obsolete) {
TableUtils.dropTable(connectionSource, UserStats.class, true);
}
TableUtils.createTableIfNotExists(connectionSource, UserStats.class);
dao = DaoManager.createDao(connectionSource, UserStats.class);
} catch (SQLException ex) {
Logger.getLogger(UserStatsRepository.class).error("Error creating user_stats repository - ", ex);
}
}
public void add(UserStats userStats) {
try {
dao.create(userStats);
} catch (SQLException ex) {
Logger.getLogger(UserStatsRepository.class).error("Error adding a user_stats to DB - ", ex);
}
}
public void update(UserStats userStats) {
try {
dao.update(userStats);
} catch (SQLException ex) {
Logger.getLogger(UserStatsRepository.class).error("Error updating a user_stats in DB - ", ex);
}
}
public UserStats getUser(String userName) {
try {
QueryBuilder<UserStats, Object> qb = dao.queryBuilder();
qb.where().eq("userName", userName);
List<UserStats> users = dao.query(qb.prepare());
if (users.size() == 1) {
return users.get(0);
}
} catch (SQLException ex) {
Logger.getLogger(UserStatsRepository.class).error("Error getting a user from DB - ", ex);
}
return null;
}
public List<UserStats> getAllUsers() {
try {
QueryBuilder<UserStats, Object> qb = dao.queryBuilder();
return dao.query(qb.prepare());
} catch (SQLException ex) {
Logger.getLogger(UserStatsRepository.class).error("Error getting all users from DB - ", ex);
}
return null;
}
public long getLatestEndTimeMs() {
try {
QueryBuilder<UserStats, Object> qb = dao.queryBuilder();
qb.orderBy("endTimeMs", false).limit(1);
List<UserStats> users = dao.query(qb.prepare());
if (users.size() == 1) {
return users.get(0).getEndTimeMs();
}
} catch (SQLException ex) {
Logger.getLogger(UserStatsRepository.class).error("Error getting the latest end time from DB - ", ex);
}
return 0;
}
// updateUserStats reads tables finished after the last DB update and reflects it to the DB.
// It returns the list of user names that are upated.
public List<String> updateUserStats() {
HashSet<String> updatedUsers = new HashSet();
// Lock the DB so that no other updateUserStats runs at the same time.
synchronized(this) {
long latestEndTimeMs = this.getLatestEndTimeMs();
List<TableRecord> records = TableRecordRepository.instance.getAfter(latestEndTimeMs);
for (TableRecord record : records) {
ResultProtos.TableProto table = record.getProto();
if (table.getControllerName().equals("System")) {
// This is a sub table within a tournament, so it's already handled by the main
// tournament table.
continue;
}
if (table.hasMatch()) {
ResultProtos.MatchProto match = table.getMatch();
for (ResultProtos.MatchPlayerProto player : match.getPlayersList()) {
UserStats userStats = this.getUser(player.getName());
ResultProtos.UserStatsProto proto = userStats != null ? userStats.getProto()
: ResultProtos.UserStatsProto.newBuilder().setName(player.getName()).build();
ResultProtos.UserStatsProto.Builder builder = ResultProtos.UserStatsProto.newBuilder(proto)
.setMatches(proto.getMatches() + 1);
switch (player.getQuit()) {
case IDLE_TIMEOUT:
builder.setMatchesIdleTimeout(proto.getMatchesIdleTimeout() + 1);
break;
case TIMER_TIMEOUT:
builder.setMatchesTimerTimeout(proto.getMatchesTimerTimeout() + 1);
break;
case QUIT:
builder.setMatchesQuit(proto.getMatchesQuit() + 1);
break;
}
if (userStats == null) {
this.add(new UserStats(builder.build(), table.getEndTimeMs()));
} else {
this.update(new UserStats(builder.build(), table.getEndTimeMs()));
}
updatedUsers.add(player.getName());
}
} else if (table.hasTourney()) {
ResultProtos.TourneyProto tourney = table.getTourney();
for (ResultProtos.TourneyPlayerProto player : tourney.getPlayersList()) {
UserStats userStats = this.getUser(player.getName());
ResultProtos.UserStatsProto proto = userStats != null ? userStats.getProto()
: ResultProtos.UserStatsProto.newBuilder().setName(player.getName()).build();
ResultProtos.UserStatsProto.Builder builder = ResultProtos.UserStatsProto.newBuilder(proto)
.setTourneys(proto.getTourneys() + 1);
switch (player.getQuit()) {
case DURING_ROUND:
builder.setTourneysQuitDuringRound(proto.getTourneysQuitDuringRound() + 1);
break;
case DURING_DRAFTING:
builder.setTourneysQuitDuringDrafting(proto.getTourneysQuitDuringDrafting() + 1);
break;
case DURING_CONSTRUCTION:
builder.setTourneysQuitDuringConstruction(proto.getTourneysQuitDuringConstruction() + 1);
break;
}
if (userStats == null) {
this.add(new UserStats(builder.build(), table.getEndTimeMs()));
} else {
this.update(new UserStats(builder.build(), table.getEndTimeMs()));
}
updatedUsers.add(player.getName());
}
}
}
}
return new ArrayList(updatedUsers);
}
public void closeDB() {
try {
if (dao != null && dao.getConnectionSource() != null) {
DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection();
conn.executeStatement("shutdown compact", 0);
}
} catch (SQLException ex) {
Logger.getLogger(UserStatsRepository.class).error("Error closing user_stats repository - ", ex);
}
}
}

View file

@ -7,6 +7,8 @@ public interface LogKeys {
String KEY_GAME_STARTED = "gameStarted"; String KEY_GAME_STARTED = "gameStarted";
String KEY_USER_REGISTERED = "userRegistered";
String KEY_USER_CONNECTED = "userConnected"; String KEY_USER_CONNECTED = "userConnected";
String KEY_ADMIN_CONNECTED = "adminConnected"; String KEY_ADMIN_CONNECTED = "adminConnected";

View file

@ -43,6 +43,7 @@ import mage.game.events.TableEvent;
import static mage.game.events.TableEvent.EventType.CONSTRUCT; import static mage.game.events.TableEvent.EventType.CONSTRUCT;
import mage.game.match.Match; import mage.game.match.Match;
import mage.game.match.MatchOptions; import mage.game.match.MatchOptions;
import mage.game.result.ResultProtos.TourneyQuitStatus;
import mage.game.tournament.Tournament; import mage.game.tournament.Tournament;
import mage.game.tournament.TournamentPairing; import mage.game.tournament.TournamentPairing;
import mage.game.tournament.TournamentPlayer; import mage.game.tournament.TournamentPlayer;
@ -351,12 +352,13 @@ public class TournamentController {
tournamentSession.setKilled(); tournamentSession.setKilled();
if (tournamentPlayer.isInTournament()) { if (tournamentPlayer.isInTournament()) {
String info; String info;
TourneyQuitStatus status;
if (tournament.isDoneConstructing()) { if (tournament.isDoneConstructing()) {
info = new StringBuilder("during round ").append(tournament.getRounds().size()).toString(); info = new StringBuilder("during round ").append(tournament.getRounds().size()).toString();
// quit active matches of that tournament // quit active matches of that tournament
TableManager.getInstance().userQuitTournamentSubTables(tournament.getId(), userId); TableManager.getInstance().userQuitTournamentSubTables(tournament.getId(), userId);
} else { status = TourneyQuitStatus.DURING_ROUND;
if (tournamentPlayer.getState().equals(TournamentPlayerState.DRAFTING)) { } else if (tournamentPlayer.getState().equals(TournamentPlayerState.DRAFTING)) {
info = "during Draft phase"; info = "during Draft phase";
if (!checkToReplaceDraftPlayerByAi(userId, tournamentPlayer)) { if (!checkToReplaceDraftPlayerByAi(userId, tournamentPlayer)) {
this.abortDraftTournament(); this.abortDraftTournament();
@ -369,13 +371,15 @@ public class TournamentController {
} }
} }
} }
status = TourneyQuitStatus.DURING_DRAFTING;
} else if (tournamentPlayer.getState().equals(TournamentPlayerState.CONSTRUCTING)) { } else if (tournamentPlayer.getState().equals(TournamentPlayerState.CONSTRUCTING)) {
info = "during Construction phase"; info = "during Construction phase";
status = TourneyQuitStatus.DURING_CONSTRUCTION;
} else { } else {
info = ""; info = "";
status = TourneyQuitStatus.NO_TOURNEY_QUIT;
} }
} tournamentPlayer.setQuit(info, status);
tournamentPlayer.setQuit(info);
tournament.quit(playerId); tournament.quit(playerId);
tournamentSession.quit(); tournamentSession.quit();
ChatManager.getInstance().broadcast(chatId, "", tournamentPlayer.getPlayer().getLogName() + " has quit the tournament", MessageColor.BLACK, true, MessageType.STATUS, SoundToPlay.PlayerQuitTournament); ChatManager.getInstance().broadcast(chatId, "", tournamentPlayer.getPlayer().getLogName() + " has quit the tournament", MessageColor.BLACK, true, MessageType.STATUS, SoundToPlay.PlayerQuitTournament);

View file

@ -111,8 +111,16 @@ public class ConfigSettings {
return config.getServer().getMaxUserNameLength().intValue(); return config.getServer().getMaxUserNameLength().intValue();
} }
public String getUserNamePattern() { public String getInvalidUserNamePattern() {
return config.getServer().getUserNamePattern(); return config.getServer().getInvalidUserNamePattern();
}
public int getMinPasswordLength() {
return config.getServer().getMinPasswordLength().intValue();
}
public int getMaxPasswordLength() {
return config.getServer().getMaxPasswordLength().intValue();
} }
public String getMaxAiOpponents() { public String getMaxAiOpponents() {
@ -121,7 +129,43 @@ public class ConfigSettings {
public Boolean isSaveGameActivated() { public Boolean isSaveGameActivated() {
return config.getServer().isSaveGameActivated(); return config.getServer().isSaveGameActivated();
} }
public Boolean isAuthenticationActivated() {
return config.getServer().isAuthenticationActivated();
}
public String getGoogleAccount() {
return config.getServer().getGoogleAccount();
}
public String getMailgunApiKey() {
return config.getServer().getMailgunApiKey();
}
public String getMailgunDomain() {
return config.getServer().getMailgunDomain();
}
public String getMailSmtpHost() {
return config.getServer().getMailSmtpHost();
}
public String getMailSmtpPort() {
return config.getServer().getMailSmtpPort();
}
public String getMailUser() {
return config.getServer().getMailUser();
}
public String getMailPassword() {
return config.getServer().getMailPassword();
}
public String getMailFromAddress() {
return config.getServer().getMailFromAddress();
}
public List<Plugin> getPlayerTypes() { public List<Plugin> getPlayerTypes() {
return config.getPlayerTypes().getPlayerType(); return config.getPlayerTypes().getPlayerType();

View file

@ -16,6 +16,8 @@
userNamePattern="[^a-z0-9_]" userNamePattern="[^a-z0-9_]"
maxAiOpponents="15" maxAiOpponents="15"
saveGameActivated="false" saveGameActivated="false"
authenticationActivated="false"
googleAccount=""
/> />
<playerTypes> <playerTypes>
<playerType name="Human" jar="Mage.Player.Human.jar" className="mage.player.human.HumanPlayer"/> <playerType name="Human" jar="Mage.Player.Human.jar" className="mage.player.human.HumanPlayer"/>

View file

@ -29,9 +29,20 @@
<xs:attribute name="leasePeriod" type="xs:positiveInteger" use="required"/> <xs:attribute name="leasePeriod" type="xs:positiveInteger" use="required"/>
<xs:attribute name="minUserNameLength" type="xs:positiveInteger" use="required"/> <xs:attribute name="minUserNameLength" type="xs:positiveInteger" use="required"/>
<xs:attribute name="maxUserNameLength" type="xs:positiveInteger" use="required"/> <xs:attribute name="maxUserNameLength" type="xs:positiveInteger" use="required"/>
<xs:attribute name="userNamePattern" type="xs:string" use="required"/> <xs:attribute name="invalidUserNamePattern" type="xs:string" use="required"/>
<xs:attribute name="minPasswordLength" type="xs:positiveInteger" use="required"/>
<xs:attribute name="maxPasswordLength" type="xs:positiveInteger" use="required"/>
<xs:attribute name="maxAiOpponents" type="xs:string" use="optional"/> <xs:attribute name="maxAiOpponents" type="xs:string" use="optional"/>
<xs:attribute name="saveGameActivated" type="xs:boolean" use="optional"/> <xs:attribute name="saveGameActivated" type="xs:boolean" use="optional"/>
<xs:attribute name="authenticationActivated" type="xs:boolean" use="optional"/>
<xs:attribute name="googleAccount" type="xs:string" use="optional"/>
<xs:attribute name="mailgunApiKey" type="xs:string" use="optional"/>
<xs:attribute name="mailgunDomain" type="xs:string" use="optional"/>
<xs:attribute name="mailSmtpHost" type="xs:string" use="optional"/>
<xs:attribute name="mailSmtpPort" type="xs:string" use="optional"/>
<xs:attribute name="mailUser" type="xs:string" use="optional"/>
<xs:attribute name="mailPassword" type="xs:string" use="optional"/>
<xs:attribute name="mailFromAddress" type="xs:string" use="optional"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-root</artifactId> <artifactId>mage-root</artifactId>
<version>1.4.6</version> <version>1.4.8</version>
</parent> </parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>

View file

@ -48,7 +48,7 @@ public class BattleForZendikar extends ExpansionSet {
return fINSTANCE; return fINSTANCE;
} }
List<CardInfo> savedSpecialLand = new ArrayList<>(); protected final List<CardInfo> savedSpecialLand = new ArrayList<>();
private BattleForZendikar() { private BattleForZendikar() {
super("Battle for Zendikar", "BFZ", "mage.sets.battleforzendikar", new GregorianCalendar(2015, 10, 2).getTime(), SetType.EXPANSION); super("Battle for Zendikar", "BFZ", "mage.sets.battleforzendikar", new GregorianCalendar(2015, 10, 2).getTime(), SetType.EXPANSION);
@ -56,25 +56,28 @@ public class BattleForZendikar extends ExpansionSet {
this.hasBoosters = true; this.hasBoosters = true;
this.hasBasicLands = true; this.hasBasicLands = true;
this.numBoosterLands = 1; this.numBoosterLands = 1;
this.ratioBoosterSpecialLand = 20; // Approximately as rare as opening a foil mythic = 8 * 6 = ~every 48th booster includes one
// I set it to 20 to get it more often
this.numBoosterCommon = 10; this.numBoosterCommon = 10;
this.numBoosterUncommon = 3; this.numBoosterUncommon = 3;
this.numBoosterRare = 1; this.numBoosterRare = 1;
this.ratioBoosterMythic = 8; this.ratioBoosterMythic = 8;
this.numBoosterSpecial = 0; this.numBoosterSpecial = 0;
// Zendikar Expeditions 1-25
// Approximately as rare as opening a foil mythic = 8 * 6 = ~every 48th booster includes one.
// I set it to 20 to get it more often
this.ratioBoosterSpecialLand = 20;
} }
@Override @Override
public List<CardInfo> getSpecialLand() { public List<CardInfo> getSpecialLand() {
List<CardInfo> specialLand = new ArrayList<>();
if (savedSpecialLand.isEmpty()) { if (savedSpecialLand.isEmpty()) {
CardCriteria criteria = new CardCriteria(); CardCriteria criteria = new CardCriteria();
criteria.setCodes("EXP"); criteria.setCodes("EXP");
specialLand.addAll(CardRepository.instance.findCards(criteria)); criteria.minCardNumber(1);
criteria.maxCardNumber(25);
savedSpecialLand.addAll(CardRepository.instance.findCards(criteria));
} }
specialLand.addAll(savedSpecialLand); return new ArrayList<>(savedSpecialLand);
return specialLand;
} }
} }

View file

@ -5,8 +5,14 @@
*/ */
package mage.sets; package mage.sets;
import java.util.ArrayList;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.List;
import mage.cards.ExpansionSet; import mage.cards.ExpansionSet;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.constants.SetType; import mage.constants.SetType;
/** /**
@ -21,9 +27,12 @@ public class OathOfTheGatewatch extends ExpansionSet {
return fINSTANCE; return fINSTANCE;
} }
protected final List<CardInfo> savedSpecialLand = new ArrayList<>();
private OathOfTheGatewatch() { private OathOfTheGatewatch() {
super("Oath of the Gatewatch", "OGW", "mage.sets.oathofthegatewatch", new GregorianCalendar(2016, 1, 22).getTime(), SetType.EXPANSION); super("Oath of the Gatewatch", "OGW", "mage.sets.oathofthegatewatch", new GregorianCalendar(2016, 1, 22).getTime(), SetType.EXPANSION);
this.blockName = "Battle for Zendikar"; this.blockName = "Battle for Zendikar";
this.parentSet = BattleForZendikar.getInstance();
this.hasBoosters = true; this.hasBoosters = true;
this.hasBasicLands = false; this.hasBasicLands = false;
this.numBoosterLands = 1; this.numBoosterLands = 1;
@ -31,5 +40,21 @@ public class OathOfTheGatewatch extends ExpansionSet {
this.numBoosterUncommon = 3; this.numBoosterUncommon = 3;
this.numBoosterRare = 1; this.numBoosterRare = 1;
this.ratioBoosterMythic = 8; this.ratioBoosterMythic = 8;
// Zendikar Expeditions 26-45
this.ratioBoosterSpecialLand = 20;
}
@Override
public List<CardInfo> getSpecialLand() {
if (savedSpecialLand.isEmpty()) {
CardCriteria criteria = new CardCriteria();
criteria.setCodes("EXP");
criteria.minCardNumber(26);
criteria.maxCardNumber(45);
savedSpecialLand.addAll(CardRepository.instance.findCards(criteria));
}
return new ArrayList<>(savedSpecialLand);
} }
} }

View file

@ -60,10 +60,6 @@ public class Crystallization extends CardImpl {
this.expansionSetCode = "ARB"; this.expansionSetCode = "ARB";
this.subtype.add("Aura"); this.subtype.add("Aura");
// Enchant creature // Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent(); TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addTarget(auraTarget);

View file

@ -98,10 +98,7 @@ class SlaveOfBolasEffect extends OneShotEffect {
SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this", source.getControllerId()); SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this", source.getControllerId());
sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game));
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect);
delayedAbility.setSourceId(source.getSourceId()); game.addDelayedTriggeredAbility(delayedAbility, source);
delayedAbility.setControllerId(source.getControllerId());
delayedAbility.setSourceObject(source.getSourceObject(game), game);
game.addDelayedTriggeredAbility(delayedAbility);
return true; return true;
} }
return false; return false;

View file

@ -105,7 +105,7 @@ class VectisDominatorEffect extends OneShotEffect {
cost.clearPaid(); cost.clearPaid();
final StringBuilder sb = new StringBuilder("Pay 2 life? (Otherwise ").append(targetCreature.getName()).append(" will be tapped)"); final StringBuilder sb = new StringBuilder("Pay 2 life? (Otherwise ").append(targetCreature.getName()).append(" will be tapped)");
if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) {
cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), true); cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), true, null);
} }
if (!cost.isPaid()) { if (!cost.isPaid()) {
return targetCreature.tap(game); return targetCreature.tap(game);

Some files were not shown because too many files have changed in this diff Show more