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

7
.gitignore vendored
View file

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

View file

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

View file

@ -1,6 +1,6 @@
XMage.de 1 (Europe/Germany) fast :xmage.de: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
Seedds Server (Asia) :115.29.203.80: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.GamePanel;
import mage.client.plugins.impl.Plugins;
import mage.client.preference.MagePreferences;
import mage.client.remote.CallbackClientImpl;
import mage.client.table.TablesPane;
import mage.client.tournament.TournamentPane;
@ -745,9 +746,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
private boolean performConnect() {
String userName = prefs.get("userName", "");
String server = prefs.get("serverAddress", "");
int port = Integer.parseInt(prefs.get("serverPort", ""));
String server = MagePreferences.getServerAddress();
int port = MagePreferences.getServerPort();
String userName = MagePreferences.getUserName(server);
String password = MagePreferences.getPassword(server);
String proxyServer = prefs.get("proxyAddress", "");
int proxyPort = Integer.parseInt(prefs.get("proxyPort", "0"));
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));
Connection connection = new Connection();
connection.setUsername(userName);
connection.setPassword(password);
connection.setHost(server);
connection.setPort(port);
connection.setProxyType(proxyType);

View file

@ -109,20 +109,20 @@ public class DeckEditorPanel extends javax.swing.JPanel {
jSplitPane1.setOpaque(false);
countdown = new Timer(1000,
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (--timeout > 0) {
setTimeout(timeout);
} else {
if (updateDeckTask != null) {
updateDeckTask.cancel(true);
@Override
public void actionPerformed(ActionEvent e) {
if (--timeout > 0) {
setTimeout(timeout);
} else {
if (updateDeckTask != null) {
updateDeckTask.cancel(true);
}
setTimeout(0);
countdown.stop();
removeDeckEditor();
}
}
setTimeout(0);
countdown.stop();
removeDeckEditor();
}
}
});
});
}
/**
@ -154,7 +154,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
this.tableId = tableId;
this.mode = mode;
this.btnAddLand.setVisible(false);
switch (mode) {
case LIMITED_BUILDING:
this.btnAddLand.setVisible(true);
@ -209,149 +209,145 @@ public class DeckEditorPanel extends javax.swing.JPanel {
component.clearCardEventListeners();
component.addCardEventListener(
new Listener<Event>() {
@Override
public void event(Event event) {
switch (event.getEventName()) {
case "double-click":
moveSelectorCardToDeck(event);
break;
case "alt-double-click":
if (mode == DeckEditorMode.FREE_BUILDING) {
moveSelectorCardToSideboard(event);
} else {
// because in match mode selector is used as sideboard the card goes to deck also for shift click
moveSelectorCardToDeck(event);
@Override
public void event(Event event) {
switch (event.getEventName()) {
case "double-click":
moveSelectorCardToDeck(event);
break;
case "alt-double-click":
if (mode == DeckEditorMode.FREE_BUILDING) {
moveSelectorCardToSideboard(event);
} else {
// because in match mode selector is used as sideboard the card goes to deck also for shift click
moveSelectorCardToDeck(event);
}
break;
case "remove-main":
DeckEditorPanel.this.deckArea.getDeckList().handleDoubleClick();
break;
case "remove-sideboard":
DeckEditorPanel.this.deckArea.getSideboardList().handleDoubleClick();
break;
}
break;
case "remove-main":
DeckEditorPanel.this.deckArea.getDeckList().handleDoubleClick();
break;
case "remove-sideboard":
DeckEditorPanel.this.deckArea.getSideboardList().handleDoubleClick();
break;
}
refreshDeck();
}
});
refreshDeck();
}
});
}
this.deckArea.clearDeckEventListeners();
this.deckArea.addDeckEventListener(
new Listener<Event>() {
@Override
public void event(Event event) {
if (mode.equals(DeckEditorMode.FREE_BUILDING)) {
switch (event.getEventName()) {
case "double-click":
{
SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getCards()) {
if (card.getId().equals(cardView.getId())) {
deck.getCards().remove(card);
@Override
public void event(Event event) {
if (mode.equals(DeckEditorMode.FREE_BUILDING)) {
switch (event.getEventName()) {
case "double-click": {
SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getCards()) {
if (card.getId().equals(cardView.getId())) {
deck.getCards().remove(card);
break;
}
}
hidePopup();
refreshDeck();
break;
}
case "alt-double-click": {
SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getCards()) {
if (card.getId().equals(cardView.getId())) {
deck.getCards().remove(card);
deck.getSideboard().add(card);
break;
}
}
hidePopup();
refreshDeck();
break;
}
case "set-number": {
setCardNumberToCardsList(event, deck.getCards());
}
}
} else {
// constructing phase or sideboarding during match -> card goes always to sideboard
switch (event.getEventName()) {
case "double-click":
case "alt-double-click": {
SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getCards()) {
if (card.getId().equals(cardView.getId())) {
deck.getCards().remove(card);
deck.getSideboard().add(card);
cardSelector.loadSideboard(new ArrayList<>(deck.getSideboard()), getBigCard());
break;
}
}
hidePopup();
refreshDeck();
break;
}
}
hidePopup();
refreshDeck();
break;
}
case "alt-double-click":
{
SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getCards()) {
if (card.getId().equals(cardView.getId())) {
deck.getCards().remove(card);
deck.getSideboard().add(card);
break;
}
}
hidePopup();
refreshDeck();
break;
}
case "set-number":
{
setCardNumberToCardsList(event, deck.getCards());
}
}
} else {
// constructing phase or sideboarding during match -> card goes always to sideboard
switch (event.getEventName()) {
case "double-click":
case "alt-double-click":
{
SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getCards()) {
if (card.getId().equals(cardView.getId())) {
deck.getCards().remove(card);
deck.getSideboard().add(card);
cardSelector.loadSideboard(new ArrayList<>(deck.getSideboard()), getBigCard());
break;
}
}
hidePopup();
refreshDeck();
break;
}
}
}
}
});
});
this.deckArea.addSideboardEventListener(
new Listener<Event>() {
@Override
public void event(Event event) {
if (mode.equals(DeckEditorMode.FREE_BUILDING)) {
// normal edit mode
switch (event.getEventName()) {
case "double-click":
// remove card from sideboard (don't add it to deck)
SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getSideboard()) {
if (card.getId().equals(cardView.getId())) {
deck.getSideboard().remove(card);
@Override
public void event(Event event) {
if (mode.equals(DeckEditorMode.FREE_BUILDING)) {
// normal edit mode
switch (event.getEventName()) {
case "double-click":
// remove card from sideboard (don't add it to deck)
SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getSideboard()) {
if (card.getId().equals(cardView.getId())) {
deck.getSideboard().remove(card);
break;
}
}
hidePopup();
refreshDeck();
break;
}
}
hidePopup();
refreshDeck();
break;
case "alt-double-click":
// remove card from sideboard
cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getSideboard()) {
if (card.getId().equals(cardView.getId())) {
deck.getSideboard().remove(card);
deck.getCards().add(card);
case "alt-double-click":
// remove card from sideboard
cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getSideboard()) {
if (card.getId().equals(cardView.getId())) {
deck.getSideboard().remove(card);
deck.getCards().add(card);
break;
}
}
hidePopup();
refreshDeck();
break;
case "set-number": {
setCardNumberToCardsList(event, deck.getSideboard());
}
}
hidePopup();
refreshDeck();
break;
case "set-number":
{
setCardNumberToCardsList(event, deck.getSideboard());
}
}
} else {
// construct phase or sideboarding during match
switch (event.getEventName()) {
case "double-click":
case "alt-double-click":
SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getSideboard()) {
if (card.getId().equals(cardView.getId())) {
deck.getSideboard().remove(card);
deck.getCards().add(card);
}
} else {
// construct phase or sideboarding during match
switch (event.getEventName()) {
case "double-click":
case "alt-double-click":
SimpleCardView cardView = (SimpleCardView) event.getSource();
for (Card card : deck.getSideboard()) {
if (card.getId().equals(cardView.getId())) {
deck.getSideboard().remove(card);
deck.getCards().add(card);
break;
}
}
hidePopup();
refreshDeck();
break;
}
} hidePopup();
refreshDeck();
break;
}
}
}
}
}
});
});
refreshDeck();
this.setVisible(true);
@ -364,8 +360,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
int cardsFound = 0;
List<Card> toDelete = new ArrayList<>();
for (Card card : cards) {
if (card.getName().equals(cardView.getName())
&& card.getCardNumber() == cardView.getCardNumber()
if (card.getName().equals(cardView.getName())
&& card.getCardNumber() == cardView.getCardNumber()
&& card.getExpansionSetCode().equals(cardView.getExpansionSetCode())) {
cardsFound++;
if (cardsFound > numberToSet) {
@ -373,23 +369,23 @@ public class DeckEditorPanel extends javax.swing.JPanel {
}
}
}
}
if (toDelete.isEmpty()) {
// add cards
CardInfo cardInfo = CardRepository.instance.findCard(cardView.getExpansionSetCode(), cardView.getCardNumber());
for (int i = cardsFound; i < numberToSet; i++) {
cards.add(cardInfo.getMockCard());
}
}
} else {
// remove cards
for (Card card: toDelete) {
// remove cards
for (Card card : toDelete) {
cards.remove(card);
}
}
hidePopup();
refreshDeck();
}
private void moveSelectorCardToDeck(Event event) {
SimpleCardView cardView = (SimpleCardView) event.getSource();
CardInfo cardInfo = CardRepository.instance.findCard(cardView.getExpansionSetCode(), cardView.getCardNumber());
@ -417,7 +413,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
((CardInfoPane) cardInfoPane).setCard(new CardView(card), null);
}
hidePopup();
}
}
}
private void moveSelectorCardToSideboard(Event event) {
@ -432,7 +428,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
}
hidePopup();
}
private void hidePopup() {
Plugins.getInstance().getActionCallback().mouseExited(null, null);
}
@ -483,7 +479,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
text = text + Integer.toString(second);
}
this.txtTimeRemaining.setText(text);
if (s==60) {
if (s == 60) {
AudioManager.playOnCountdown1();
}
}
@ -602,75 +598,73 @@ public class DeckEditorPanel extends javax.swing.JPanel {
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
/*.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLayeredPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE))*/
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(lblDeckName)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.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(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
/*.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLayeredPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE))*/
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(btnSave)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnLoad)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnNew)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnExit))
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(btnImport)
.addContainerGap()
.addComponent(btnAddLand)
.addContainerGap()
.addComponent(btnSubmit))
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(txtTimeRemaining))
)
.addContainerGap()));
.addGap(6, 6, 6)
.addComponent(lblDeckName)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.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(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(btnSave)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnLoad)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnNew)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnExit))
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(btnImport)
.addContainerGap()
.addComponent(btnAddLand)
.addContainerGap()
.addComponent(btnSubmit))
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(txtTimeRemaining))
)
.addContainerGap()));
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtDeckName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblDeckName))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnSave)
.addComponent(btnLoad)
.addComponent(btnNew)
.addComponent(btnExit))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnImport)
.addComponent(btnAddLand)
.addComponent(btnSubmit))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtTimeRemaining))
//.addComponent(jLayeredPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, isShowCardInfo ? 30 : 159, Short.MAX_VALUE)
.addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 104, Short.MAX_VALUE)
.addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)));
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtDeckName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblDeckName))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnSave)
.addComponent(btnLoad)
.addComponent(btnNew)
.addComponent(btnExit))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnImport)
.addComponent(btnAddLand)
.addComponent(btnSubmit))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtTimeRemaining))
//.addComponent(jLayeredPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, isShowCardInfo ? 30 : 159, Short.MAX_VALUE)
.addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 104, Short.MAX_VALUE)
.addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 604, Short.MAX_VALUE)));
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 604, Short.MAX_VALUE)));
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
@ -697,7 +691,9 @@ public class DeckEditorPanel extends javax.swing.JPanel {
}
refreshDeck();
try {
MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath());
if (file != null) {
MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath());
}
} catch (IOException ex) {
}
}
@ -800,7 +796,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
addLand.showDialog(deck, mode);
refreshDeck();
}//GEN-LAST:event_btnAddLandActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private mage.client.cards.BigCard bigCard;
private javax.swing.JButton btnExit;

View file

@ -28,18 +28,13 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" 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="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="lblPort" alignment="1" 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="lblPassword" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="lblFlag" alignment="1" min="-2" max="-2" attributes="0"/>
</Group>
@ -53,14 +48,29 @@
<Component id="txtServer" pref="286" max="32767" 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="txtPassword" alignment="1" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnFind" min="-2" max="-2" attributes="0"/>
</Group>
<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 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>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -85,6 +95,11 @@
<Component id="txtUserName" min="-2" max="-2" attributes="0"/>
<Component id="lblUserName" min="-2" max="-2" attributes="0"/>
</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"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="lblFlag" max="32767" attributes="0"/>
@ -96,13 +111,16 @@
<Component id="chkForceUpdateDB" min="-2" max="-2" attributes="0"/>
<EmptySpace 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"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" 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="btnForgotPassword" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
<Component id="btnRegister" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@ -152,6 +170,16 @@
</Component>
<Component class="javax.swing.JTextField" name="txtUserName">
</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">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
@ -209,5 +237,23 @@
</Component>
<Component class="javax.swing.JLabel" name="lblStatus">
</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>
</Form>

View file

@ -56,16 +56,17 @@ import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import mage.client.MageFrame;
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_FLAG;
import mage.client.preference.MagePreferences;
import mage.client.util.Config;
import mage.client.util.gui.countryBox.CountryItemEditor;
import mage.remote.Connection;
import mage.remote.Connection.ProxyType;
import org.apache.log4j.Logger;
/**
@ -76,6 +77,8 @@ public class ConnectDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(ConnectDialog.class);
private Connection connection;
private ConnectTask task;
private RegisterUserDialog registerUserDialog;
private ResetPasswordDialog resetPasswordDialog;
private final ActionListener connectAction = new ActionListener() {
@Override
@ -90,15 +93,24 @@ public class ConnectDialog extends MageDialog {
public ConnectDialog() {
initComponents();
this.txtUserName.addActionListener(connectAction);
this.txtServer.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() {
this.txtServer.setText(MageFrame.getPreferences().get("serverAddress", Config.serverName));
this.txtPort.setText(MageFrame.getPreferences().get("serverPort", Integer.toString(Config.port)));
this.txtUserName.setText(MageFrame.getPreferences().get("userName", ""));
String serverAddress = MagePreferences.getServerAddressWithDefault(Config.serverName);
this.txtServer.setText(serverAddress);
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.chkForceUpdateDB.setSelected(false); // has always to be set manually to force comparison
@ -117,9 +129,11 @@ public class ConnectDialog extends MageDialog {
}
private void saveSettings() {
MageFrame.getPreferences().put("serverAddress", txtServer.getText().trim());
MageFrame.getPreferences().put("serverPort", txtPort.getText().trim());
MageFrame.getPreferences().put("userName", txtUserName.getText().trim());
String serverAddress = txtServer.getText().trim();
MagePreferences.setServerAddress(serverAddress);
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()));
}
@ -139,6 +153,8 @@ public class ConnectDialog extends MageDialog {
txtPort = new javax.swing.JTextField();
lblUserName = new javax.swing.JLabel();
txtUserName = new javax.swing.JTextField();
lblPassword = new javax.swing.JLabel();
txtPassword = new javax.swing.JPasswordField();
lblFlag = new javax.swing.JLabel();
cbFlag = new mage.client.util.gui.countryBox.CountryComboBox();
chkAutoConnect = new javax.swing.JCheckBox();
@ -147,6 +163,8 @@ public class ConnectDialog extends MageDialog {
btnConnect = new javax.swing.JButton();
btnCancel = new javax.swing.JButton();
lblStatus = new javax.swing.JLabel();
btnRegister = new javax.swing.JButton();
btnForgotPassword = new javax.swing.JButton();
setTitle("Connect to server");
setNormalBounds(new java.awt.Rectangle(100, 100, 410, 307));
@ -175,6 +193,9 @@ public class ConnectDialog extends MageDialog {
lblUserName.setLabelFor(txtUserName);
lblUserName.setText("User name:");
lblPassword.setLabelFor(txtPassword);
lblPassword.setText("Password:");
lblFlag.setLabelFor(txtUserName);
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());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
@ -224,17 +261,13 @@ public class ConnectDialog extends MageDialog {
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.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.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblPort)
.addComponent(lblServer)
.addComponent(lblUserName))
.addComponent(lblUserName)
.addComponent(lblPassword))
.addComponent(lblFlag, javax.swing.GroupLayout.Alignment.TRAILING))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.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)
.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(txtUserName))
.addComponent(txtUserName)
.addComponent(txtPassword))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnFind))
.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())
);
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(lblUserName))
.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)
.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))
@ -278,12 +327,15 @@ public class ConnectDialog extends MageDialog {
.addComponent(chkForceUpdateDB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.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)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnConnect)
.addComponent(btnCancel))
.addComponent(btnCancel)
.addComponent(btnForgotPassword))
.addGap(3, 3, 3)
.addComponent(btnRegister)
.addContainerGap())
);
@ -302,10 +354,6 @@ public class ConnectDialog extends MageDialog {
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()) {
JOptionPane.showMessageDialog(rootPane, "Please provide a server address");
return;
@ -314,9 +362,14 @@ public class ConnectDialog extends MageDialog {
JOptionPane.showMessageDialog(rootPane, "Please provide a port number");
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) {
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;
}
@ -327,30 +380,10 @@ public class ConnectDialog extends MageDialog {
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.setForceDBComparison(this.chkForceUpdateDB.isSelected());
MageFrame.getPreferences().put(KEY_CONNECT_FLAG, ((CountryItemEditor) cbFlag.getEditor()).getImageItem());
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);
}
}
}
PreferencesDialog.setProxyInformation(connection);
// pref settings
MageFrame.getInstance().setUserPrefsToConnection(connection);
@ -514,8 +547,12 @@ public class ConnectDialog extends MageDialog {
if (selectedServer != null) {
String[] params = selectedServer.split(":");
if (params.length == 3) {
this.txtServer.setText(params[1]);
String serverAddress = params[1];
this.txtServer.setText(serverAddress);
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 {
JOptionPane.showMessageDialog(null, "Wrong server data format.");
}
@ -541,19 +578,47 @@ public class ConnectDialog extends MageDialog {
// TODO add your handling code here:
}//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
private javax.swing.JButton btnCancel;
private javax.swing.JButton btnConnect;
private javax.swing.JButton btnFind;
private javax.swing.JButton btnForgotPassword;
private javax.swing.JButton btnRegister;
private mage.client.util.gui.countryBox.CountryComboBox cbFlag;
private javax.swing.JCheckBox chkAutoConnect;
private javax.swing.JCheckBox chkForceUpdateDB;
private javax.swing.JButton jProxySettingsButton;
private javax.swing.JLabel lblFlag;
private javax.swing.JLabel lblPassword;
private javax.swing.JLabel lblPort;
private javax.swing.JLabel lblServer;
private javax.swing.JLabel lblStatus;
private javax.swing.JLabel lblUserName;
private javax.swing.JPasswordField txtPassword;
private javax.swing.JTextField txtPort;
private javax.swing.JTextField txtServer;
private javax.swing.JTextField txtUserName;

View file

@ -2298,6 +2298,30 @@ public class PreferencesDialog extends javax.swing.JDialog {
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
*/

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.
*/
/*
/*
* TableWaitingDialog.java
*
* Created on Dec 16, 2009, 10:27:44 AM
@ -68,7 +68,7 @@ public class TableWaitingDialog extends MageDialog {
private Session session;
private final TableWaitModel tableWaitModel;
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
@ -268,10 +268,8 @@ public class TableWaitingDialog extends MageDialog {
if (session.startMatch(roomId, tableId)) {
closeDialog();
}
} else {
if (session.startTournament(roomId, tableId)) {
closeDialog();
}
} else if (session.startTournament(roomId, tableId)) {
closeDialog();
}
}//GEN-LAST:event_btnStartActionPerformed
@ -319,7 +317,7 @@ public class TableWaitingDialog extends MageDialog {
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];
public void loadData(TableView table) {
@ -353,6 +351,8 @@ class TableWaitModel extends AbstractTableModel {
return seats[arg0].getPlayerName();
case 3:
return seats[arg0].getPlayerType();
case 4:
return seats[arg0].getHistory();
}
}
return "";

View file

@ -26,7 +26,7 @@
* or implied, of BetaSteward_at_googlemail.com.
*/
/*
/*
* PlayerPanel.java
*
* 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()
+ "<br/>Country: " + countryname
+ "<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
StringBuilder tooltipText = new StringBuilder(basicTooltipText);
@ -580,7 +581,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
manaCountLabelX.setText("0");
manaLabels.put("X", manaCountLabelX);
r = new Rectangle(12, 12);
BufferedImage imageManaX = ManaSymbols.getManaSymbolImageSmall("X");
BufferedImage imageManaX = ManaSymbols.getManaSymbolImageSmall("C");
HoverButton btnColorlessMana = new HoverButton(null, imageManaX, imageManaX, imageManaX, r);
btnColorlessMana.setToolTipText("Colorless mana");
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.
*/
/*
/*
* ChatPanel.java
*
* 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 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.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());
jScrollPaneTalk.setSystemMessagesPane(colorPaneSystem);
@ -118,7 +118,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
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];
public void loadData(Collection<RoomUsersView> roomUserInfoList) throws MageRemoteException {
@ -154,7 +154,7 @@ public class PlayersChatPanel extends javax.swing.JPanel {
case 1:
return players[arg0].getUserName();
case 2:
return players[arg0].getInfoState();
return players[arg0].getHistory();
case 3:
return players[arg0].getInfoGames();
case 4:

View file

@ -1,31 +1,30 @@
/*
* 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.
*/
* 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.client.util;
import java.awt.Component;
@ -78,64 +77,64 @@ public class ButtonColumn extends AbstractCellEditor implements TableCellRendere
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (hasFocus)
{
if (hasFocus) {
renderButton.setForeground(table.getForeground());
renderButton.setBackground(UIManager.getColor("Button.background"));
}
else if (isSelected)
{
} else if (isSelected) {
renderButton.setForeground(table.getSelectionForeground());
renderButton.setBackground(table.getSelectionBackground());
}
else
{
renderButton.setBackground(table.getSelectionBackground());
} else {
renderButton.setForeground(table.getForeground());
renderButton.setBackground(UIManager.getColor("Button.background"));
}
renderButton.setText( (value == null) ? "" : value.toString() );
renderButton.setText((value == null) ? "" : value.toString());
return renderButton;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
text = (value == null) ? "" : value.toString();
editButton.setText( text );
editButton.setText(text);
return editButton;
}
@Override
public void actionPerformed(ActionEvent e) {
int row = table.convertRowIndexToModel( table.getEditingRow() );
fireEditingStopped();
ActionEvent event = new ActionEvent(table, ActionEvent.ACTION_PERFORMED, "" + row);
action.actionPerformed(event);
if (table.getRowCount() >= table.getEditingRow()) {
int row = table.convertRowIndexToModel(table.getEditingRow());
fireEditingStopped();
ActionEvent event = new ActionEvent(table, ActionEvent.ACTION_PERFORMED, "" + row);
action.actionPerformed(event);
}
}
@Override
public void mousePressed(MouseEvent arg0) {
if (table.isEditing() && table.getCellEditor() == this)
if (table.isEditing() && table.getCellEditor() == this) {
isButtonColumnEditor = true;
}
}
@Override
public void mouseReleased(MouseEvent arg0) {
if (isButtonColumnEditor && table.isEditing())
if (isButtonColumnEditor && table.isEditing()) {
table.getCellEditor().stopCellEditing();
}
isButtonColumnEditor = false;
}
@Override
public void mouseClicked(MouseEvent arg0) {}
public void mouseClicked(MouseEvent arg0) {
}
@Override
public void mouseEntered(MouseEvent arg0) {}
public void mouseEntered(MouseEvent arg0) {
}
@Override
public void mouseExited(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {
}
}

View file

@ -1,14 +1,9 @@
package org.mage.card.arcane;
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;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.HashMap;
@ -16,6 +11,13 @@ import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
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 {
@ -30,10 +32,10 @@ public class ManaSymbols {
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",
"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) {
File file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_MANA_MEDIUM + "/" + symbol + ".jpg");
File file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_MANA_MEDIUM + "/" + symbol + ".jpg");
Rectangle r = new Rectangle(11, 11);
try {
Image image = UI.getImageIcon(file.getAbsolutePath()).getImage();
@ -198,6 +200,7 @@ public class ManaSymbols {
}
public enum Type {
CARD,
TOOLTIP,
PAY

View file

@ -1,12 +1,10 @@
/**
* DownloadJob.java
*
*
* Created on 25.08.2010
*/
package org.mage.plugins.card.dl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@ -21,25 +19,26 @@ import org.mage.plugins.card.dl.beans.properties.Property;
import org.mage.plugins.card.dl.lm.AbstractLaternaBean;
import org.mage.plugins.card.utils.CardImageUtils;
/**
* The class DownloadJob.
*
*
* @version V0.0 25.08.2010
* @author Clemens Koza
*/
public class DownloadJob extends AbstractLaternaBean {
public static enum State {
NEW, WORKING, FINISHED, ABORTED;
}
private final String name;
private final Source source;
private final Destination destination;
private final Property<State> state = properties.property("state", State.NEW);
private final Property<String> message = properties.property("message");
private final Property<Exception> error = properties.property("error");
private final BoundedRangeModel progress = new DefaultBoundedRangeModel();
private final String name;
private final Source source;
private final Destination destination;
private final Property<State> state = properties.property("state", State.NEW);
private final Property<String> message = properties.property("message");
private final Property<Exception> error = properties.property("error");
private final BoundedRangeModel progress = new DefaultBoundedRangeModel();
public DownloadJob(String name, Source source, Destination destination) {
this.name = name;
@ -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
*/
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
* with the given message.
* Sets the job's state to {@link State#ABORTED} and the error message to
* the given message. Logs a warning with the given message.
*
* @param 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
* given exception.
* Sets the job's state to {@link State#ABORTED} and the error to the given
* exception. Logs a warning with the given exception.
*
* @param error
*/
public void setError(Exception error) {
@ -78,14 +81,15 @@ 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
* given message and exception.
* Sets the job's state to {@link State#ABORTED} and the error to the given
* exception. Logs a warning with the given message and exception.
*
* @param message
* @param error
*/
public void setError(String message, Exception error) {
if (message == null) {
message = "Download of " + this.getName() + "from " + this.getSource().toString() + " caused error: " + error.toString();
}
// log.warn(message, error);
@ -97,6 +101,7 @@ public class DownloadJob extends AbstractLaternaBean {
/**
* Sets the job's message.
*
* @param message
*/
public void setMessage(String message) {
@ -119,7 +124,6 @@ public class DownloadJob extends AbstractLaternaBean {
return message.getValue();
}
public String getName() {
return name;
}
@ -163,9 +167,9 @@ public class DownloadJob extends AbstractLaternaBean {
@Override
public String toString() {
return proxy != null ? proxy.type().toString()+" " :"" + url;
return proxy != null ? proxy.type().toString() + " " : "" + url;
}
};
}
@ -189,11 +193,11 @@ public class DownloadJob extends AbstractLaternaBean {
public int length() throws IOException {
return getConnection().getContentLength();
}
@Override
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);
}
@Override
public boolean isValid() throws IOException {
if (file.isFile()) {
return file.length() > 0;
}
return false;
}
@Override
public boolean exists() {
return file.isFile();
@ -228,16 +240,20 @@ public class DownloadJob extends AbstractLaternaBean {
}
public interface Source {
InputStream open() throws IOException;
int length() throws IOException;
}
public interface Destination {
OutputStream open() throws IOException;
boolean exists() throws IOException;
boolean isValid() throws IOException;
void delete() throws IOException;
}
}

View file

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

View file

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

View file

@ -616,7 +616,9 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
new TFile(temporaryFile).cp_rp(outputFile);
}
} 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
logger.debug("Return ed HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
}

View file

@ -1,6 +1,14 @@
#Generate|TOK:OGW|Elemental||
#Generate|TOK:OGW|Plant||
#Generate|TOK:OGW|Zombie||
|Generate}TOK:OGW|Angel||
|Generate|TOK:OGW|Elemental|1|
|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||

View file

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

View file

@ -55,10 +55,21 @@ import mage.view.UserView;
*/
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
// 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 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
// void deregisterClient(String sessionId) throws MageException;

View file

@ -45,6 +45,9 @@ public class Connection {
private int port;
private String username;
private String password;
private String email;
private String authToken;
private String adminPassword;
private ProxyType proxyType;
private String proxyHost;
private int proxyPort;
@ -172,6 +175,30 @@ public class Connection {
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() {
return proxyHost;
}

View file

@ -122,195 +122,36 @@ public class SessionImpl implements Session {
return sessionId;
}
@Override
public synchronized boolean connect(Connection connection) {
if (isConnected()) {
disconnect(true);
}
this.connection = connection;
this.canceled = false;
return connect();
// RemotingTask encapsulates a task which is involved with some JBoss Remoting. This is
// intended to be used with handleRemotingTaskExceptions for sharing the common exception
// handling.
public interface RemotingTask {
public boolean run() throws Throwable;
}
@Override
public boolean stopConnecting() {
canceled = true;
return true;
}
@Override
public boolean connect() {
sessionState = SessionState.CONNECTING;
// handleRemotingTaskExceptions runs the given task and handles exceptions appropriately. This
// way we can share the common exception handling.
private boolean handleRemotingTaskExceptions(RemotingTask remoting) {
try {
System.setProperty("http.nonProxyHosts", "code.google.com");
System.setProperty("socksNonProxyHosts", "code.google.com");
// clear previous values
System.clearProperty("socksProxyHost");
System.clearProperty("socksProxyPort");
System.clearProperty("http.proxyHost");
System.clearProperty("http.proxyPort");
switch (connection.getProxyType()) {
case SOCKS:
System.setProperty("socksProxyHost", connection.getProxyHost());
System.setProperty("socksProxyPort", Integer.toString(connection.getProxyPort()));
break;
case HTTP:
System.setProperty("http.proxyHost", connection.getProxyHost());
System.setProperty("http.proxyPort", Integer.toString(connection.getProxyPort()));
Authenticator.setDefault(new MageAuthenticator(connection.getProxyUsername(), connection.getProxyPassword()));
break;
}
InvokerLocator clientLocator = new InvokerLocator(connection.getURI());
Map<String, String> metadata = new HashMap<>();
/*
5.8.3.1.1. Write timeouts
The socket timeout facility offered by the JDK applies only to read operations on the socket. As of release 2.5.2,
the socket and bisocket (and also sslsocket and sslbisocket) transports offer a write timeout facility. When a client
or server is configured, in any of the usual ways, with the parameter org.jboss.remoting.transport.socket.SocketWrapper.WRITE_TIMEOUT
(actual value "writeTimeout") set to a positive value (in milliseconds), all write operations will time out if they do
not complete within the configured period. When a write operation times out, the socket upon which the write was invoked
will be closed, which is likely to result in a java.net.SocketException.
Note. A SocketException is considered to be a "retriable" exception, so, if the parameter "numberOfCallRetries" is set
to a value greater than 1, an invocation interrupted by a write timeout can be retried.
Note. The write timeout facility applies to writing of both invocations and responses. It applies to push callbacks as well.
*/
metadata.put(SocketWrapper.WRITE_TIMEOUT, "2000");
metadata.put("generalizeSocketException", "true");
server = (MageServer) TransporterClient.createTransporterClient(clientLocator.getLocatorURI(), MageServer.class, metadata);
// http://docs.jboss.org/jbossremoting/docs/guide/2.5/html_single/#d0e1057
Map<String, String> clientMetadata = new HashMap<>();
clientMetadata.put(SocketWrapper.WRITE_TIMEOUT, "2000");
/* generalizeSocketException
* If set to false, a failed invocation will be retried in the case of
* SocketExceptions. If set to true, a failed invocation will be retried in the case of
* <classname>SocketException</classname>s and also any <classname>IOException</classname>
* whose message matches the regular expression
* <code>^.*(?:connection.*reset|connection.*closed|broken.*pipe).*$</code>.
* See also the "numberOfCallRetries" parameter, above. The default value is false.*/
clientMetadata.put("generalizeSocketException", "true");
/* A remoting server also has the capability to detect when a client is no longer available.
* This is done by estabilishing a lease with the remoting clients that connect to a server.
* On the client side, an org.jboss.remoting.LeasePinger periodically sends PING messages to
* the server, and on the server side an org.jboss.remoting.Lease informs registered listeners
* if the PING doesn't arrive withing the specified timeout period. */
clientMetadata.put(Client.ENABLE_LEASE, "true");
/*
When the socket client invoker makes its first invocation, it will check to see if there is an available
socket connection in its pool. Since is the first invocation, there will not be and will create a new socket
connection and use it for making the invocation. Then when finished making invocation, will return the still
active socket connection to the pool. As more client invocations are made, is possible for the number of
socket connections to reach the maximum allowed (which is controlled by 'clientMaxPoolSize' property). At this
point, when the next client invocation is made, it will wait up to some configured number of milliseconds, at
which point it will throw an org.jboss.remoting.CannotConnectException. The number of milliseconds is given by
the parameter MicroSocketClientInvoker.CONNECTION_WAIT (actual value "connectionWait"), with a default of
30000 milliseconds. Note that if more than one call retry is configured (see next paragraph),
the CannotConnectException will be swallowed.
Once the socket client invoker get an available socket connection from the pool, are not out of the woods yet.
For example, a network problem could cause a java.net.SocketException. There is also a possibility that the socket
connection, while still appearing to be valid, has "gone stale" while sitting in the pool. For example, a ServerThread
on the other side of the connection could time out and close its socket. If the attempt to complete an invocation
fails, then MicroSocketClientInvoker will make a number of attempts, according to the parameter "numberOfCallRetries",
with a default value of 3. Once the configured number of retries has been exhausted,
an org.jboss.remoting.InvocationFailureException will be thrown.
*/
clientMetadata.put("numberOfCallRetries", "1");
/**
* I'll explain the meaning of "secondaryBindPort" and
* "secondaryConnectPort", and maybe that will help. The Remoting
* bisocket transport creates two ServerSockets on the server. The
* "primary" ServerSocket is used to create connections used for
* ordinary invocations, e.g., a request to create a JMS consumer,
* and the "secondary" ServerSocket is used to create "control"
* connections for internal Remoting messages. The port for the
* primary ServerSocket is configured by the "serverBindPort"
* parameter, and the port for the secondary ServerSocket is, by
* default, chosen randomly. The "secondaryBindPort" parameter can
* be used to assign a specific port to the secondary ServerSocket.
* Now, if there is a translating firewall between the client and
* server, the client should be given the value of the port that is
* translated to the actual binding port of the secondary
* ServerSocket. For example, your configuration will tell the
* secondary ServerSocket to bind to port 14000, and it will tell
* the client to connect to port 14001. It assumes that there is a
* firewall which will translate 14001 to 14000. Apparently, that's
* not happening.
*/
// secondaryBindPort - the port to which the secondary server socket is to be bound. By default, an arbitrary port is selected.
// secondaryConnectPort - the port clients are to use to connect to the secondary server socket.
// By default, the value of secondaryBindPort is used. secondaryConnectPort is useful if the server is behind a translating firewall.
// Indicated the max number of threads used within oneway thread pool.
clientMetadata.put(Client.MAX_NUM_ONEWAY_THREADS, "10");
clientMetadata.put(Remoting.USE_CLIENT_CONNECTION_IDENTITY, "true");
callbackClient = new Client(clientLocator, "callback", clientMetadata);
Map<String, String> listenerMetadata = new HashMap<>();
if (debugMode) {
// prevent client from disconnecting while debugging
listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_PERIOD, "1000000");
listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_TIMEOUT, "900000");
} else {
listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_PERIOD, "15000");
listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_TIMEOUT, "13000");
}
callbackClient.connect(new ClientConnectionListener(), listenerMetadata);
Map<String, String> callbackMetadata = new HashMap<>();
callbackMetadata.put(Bisocket.IS_CALLBACK_SERVER, "true");
if (callbackHandler == null) {
callbackHandler = new CallbackHandler();
}
callbackClient.addListener(callbackHandler, callbackMetadata);
Set callbackConnectors = callbackClient.getCallbackConnectors(callbackHandler);
if (callbackConnectors.size() != 1) {
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);
this.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;
serverState = server.getServerState();
if (!connection.getUsername().equals("Admin")) {
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() + " ");
return true;
}
disconnect(false);
// client.showMessage("Unable to connect to server.");
return remoting.run();
} 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();
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);
@ -347,6 +188,247 @@ public class SessionImpl implements Session {
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
public boolean stopConnecting() {
canceled = true;
return true;
}
private boolean establishJBossRemotingConnection(final Connection connection) {
if (isConnected()) {
disconnect(true);
}
this.connection = connection;
this.canceled = false;
sessionState = SessionState.CONNECTING;
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("socksNonProxyHosts", "code.google.com");
// clear previous values
System.clearProperty("socksProxyHost");
System.clearProperty("socksProxyPort");
System.clearProperty("http.proxyHost");
System.clearProperty("http.proxyPort");
switch (connection.getProxyType()) {
case SOCKS:
System.setProperty("socksProxyHost", connection.getProxyHost());
System.setProperty("socksProxyPort", Integer.toString(connection.getProxyPort()));
break;
case HTTP:
System.setProperty("http.proxyHost", connection.getProxyHost());
System.setProperty("http.proxyPort", Integer.toString(connection.getProxyPort()));
Authenticator.setDefault(new MageAuthenticator(connection.getProxyUsername(), connection.getProxyPassword()));
break;
}
InvokerLocator clientLocator = new InvokerLocator(connection.getURI());
Map<String, String> metadata = new HashMap<>();
/*
5.8.3.1.1. Write timeouts
The socket timeout facility offered by the JDK applies only to read operations on the socket. As of release 2.5.2,
the socket and bisocket (and also sslsocket and sslbisocket) transports offer a write timeout facility. When a client
or server is configured, in any of the usual ways, with the parameter org.jboss.remoting.transport.socket.SocketWrapper.WRITE_TIMEOUT
(actual value "writeTimeout") set to a positive value (in milliseconds), all write operations will time out if they do
not complete within the configured period. When a write operation times out, the socket upon which the write was invoked
will be closed, which is likely to result in a java.net.SocketException.
Note. A SocketException is considered to be a "retriable" exception, so, if the parameter "numberOfCallRetries" is set
to a value greater than 1, an invocation interrupted by a write timeout can be retried.
Note. The write timeout facility applies to writing of both invocations and responses. It applies to push callbacks as well.
*/
metadata.put(SocketWrapper.WRITE_TIMEOUT, "2000");
metadata.put("generalizeSocketException", "true");
server = (MageServer) TransporterClient.createTransporterClient(clientLocator.getLocatorURI(), MageServer.class, metadata);
// http://docs.jboss.org/jbossremoting/docs/guide/2.5/html_single/#d0e1057
Map<String, String> clientMetadata = new HashMap<>();
clientMetadata.put(SocketWrapper.WRITE_TIMEOUT, "2000");
/* generalizeSocketException
* If set to false, a failed invocation will be retried in the case of
* SocketExceptions. If set to true, a failed invocation will be retried in the case of
* <classname>SocketException</classname>s and also any <classname>IOException</classname>
* whose message matches the regular expression
* <code>^.*(?:connection.*reset|connection.*closed|broken.*pipe).*$</code>.
* See also the "numberOfCallRetries" parameter, above. The default value is false.*/
clientMetadata.put("generalizeSocketException", "true");
/* A remoting server also has the capability to detect when a client is no longer available.
* This is done by estabilishing a lease with the remoting clients that connect to a server.
* On the client side, an org.jboss.remoting.LeasePinger periodically sends PING messages to
* the server, and on the server side an org.jboss.remoting.Lease informs registered listeners
* if the PING doesn't arrive withing the specified timeout period. */
clientMetadata.put(Client.ENABLE_LEASE, "true");
/*
When the socket client invoker makes its first invocation, it will check to see if there is an available
socket connection in its pool. Since is the first invocation, there will not be and will create a new socket
connection and use it for making the invocation. Then when finished making invocation, will return the still
active socket connection to the pool. As more client invocations are made, is possible for the number of
socket connections to reach the maximum allowed (which is controlled by 'clientMaxPoolSize' property). At this
point, when the next client invocation is made, it will wait up to some configured number of milliseconds, at
which point it will throw an org.jboss.remoting.CannotConnectException. The number of milliseconds is given by
the parameter MicroSocketClientInvoker.CONNECTION_WAIT (actual value "connectionWait"), with a default of
30000 milliseconds. Note that if more than one call retry is configured (see next paragraph),
the CannotConnectException will be swallowed.
Once the socket client invoker get an available socket connection from the pool, are not out of the woods yet.
For example, a network problem could cause a java.net.SocketException. There is also a possibility that the socket
connection, while still appearing to be valid, has "gone stale" while sitting in the pool. For example, a ServerThread
on the other side of the connection could time out and close its socket. If the attempt to complete an invocation
fails, then MicroSocketClientInvoker will make a number of attempts, according to the parameter "numberOfCallRetries",
with a default value of 3. Once the configured number of retries has been exhausted,
an org.jboss.remoting.InvocationFailureException will be thrown.
*/
clientMetadata.put("numberOfCallRetries", "1");
/**
* I'll explain the meaning of "secondaryBindPort" and
* "secondaryConnectPort", and maybe that will help. The Remoting
* bisocket transport creates two ServerSockets on the server. The
* "primary" ServerSocket is used to create connections used for
* ordinary invocations, e.g., a request to create a JMS consumer,
* and the "secondary" ServerSocket is used to create "control"
* connections for internal Remoting messages. The port for the
* primary ServerSocket is configured by the "serverBindPort"
* parameter, and the port for the secondary ServerSocket is, by
* default, chosen randomly. The "secondaryBindPort" parameter can
* be used to assign a specific port to the secondary ServerSocket.
* Now, if there is a translating firewall between the client and
* server, the client should be given the value of the port that is
* translated to the actual binding port of the secondary
* ServerSocket. For example, your configuration will tell the
* secondary ServerSocket to bind to port 14000, and it will tell
* the client to connect to port 14001. It assumes that there is a
* firewall which will translate 14001 to 14000. Apparently, that's
* not happening.
*/
// secondaryBindPort - the port to which the secondary server socket is to be bound. By default, an arbitrary port is selected.
// secondaryConnectPort - the port clients are to use to connect to the secondary server socket.
// By default, the value of secondaryBindPort is used. secondaryConnectPort is useful if the server is behind a translating firewall.
// Indicated the max number of threads used within oneway thread pool.
clientMetadata.put(Client.MAX_NUM_ONEWAY_THREADS, "10");
clientMetadata.put(Remoting.USE_CLIENT_CONNECTION_IDENTITY, "true");
callbackClient = new Client(clientLocator, "callback", clientMetadata);
Map<String, String> listenerMetadata = new HashMap<>();
if (debugMode) {
// prevent client from disconnecting while debugging
listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_PERIOD, "1000000");
listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_TIMEOUT, "900000");
} else {
listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_PERIOD, "15000");
listenerMetadata.put(ConnectionValidator.VALIDATOR_PING_TIMEOUT, "13000");
}
callbackClient.connect(new ClientConnectionListener(), listenerMetadata);
Map<String, String> callbackMetadata = new HashMap<>();
callbackMetadata.put(Bisocket.IS_CALLBACK_SERVER, "true");
if (callbackHandler == null) {
callbackHandler = new CallbackHandler();
}
callbackClient.addListener(callbackHandler, callbackMetadata);
Set callbackConnectors = callbackClient.getCallbackConnectors(callbackHandler);
if (callbackConnectors.size() != 1) {
logger.warn("There should be one callback Connector (number existing = " + callbackConnectors.size() + ")");
}
callbackClient.invoke(null);
sessionId = callbackClient.getSessionId();
sessionState = SessionState.CONNECTED;
logger.info("Connected to MAGE server at " + connection.getHost() + ":" + connection.getPort());
return true;
}
});
if (result) {
return true;
}
disconnect(false);
return false;
}
private void updateDatabase(boolean forceDBComparison, ServerState serverState) {
long cardDBVersion = CardRepository.instance.getContentVersionFromDB();
if (forceDBComparison || serverState.getCardsContentVersion() > cardDBVersion) {
@ -1389,9 +1471,20 @@ public class SessionImpl implements Session {
@Override
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
public boolean updatePreferencesForServer(UserData userData) {
try {

View file

@ -34,12 +34,16 @@ import mage.remote.Connection;
*/
public interface Connect {
boolean register(Connection connection);
boolean emailAuthToken(Connection connection);
boolean resetPassword(Connection connection);
boolean connect(Connection connection);
boolean stopConnecting();
boolean connect();
void disconnect(boolean showMessage);
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_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_INFO = "";

View file

@ -1,43 +1,42 @@
/*
* 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.
*/
* 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.view;
import java.io.Serializable;
import mage.ConditionalMana;
import mage.players.ManaPool;
import java.io.Serializable;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class ManaPoolView implements Serializable {
private static final long serialVersionUID = 1L;
private int red;

View file

@ -44,6 +44,7 @@ public class SeatView implements Serializable {
private UUID playerId;
private final String playerName;
private final String playerType;
private final String history;
public SeatView(Seat seat) {
if (seat.getPlayer() != null) {
@ -51,13 +52,16 @@ public class SeatView implements Serializable {
this.playerName = seat.getPlayer().getName();
if (seat.getPlayer().getUserData() == null) {
this.flagName = UserData.getDefaultFlagName();
this.history = "";
} else {
this.flagName = seat.getPlayer().getUserData().getFlagName();
this.history = seat.getPlayer().getUserData().getHistory();
}
} else {
// Empty seat
this.playerName = "";
this.flagName = "";
this.history = "";
}
this.playerType = seat.getPlayerType();
}
@ -78,4 +82,8 @@ public class SeatView implements Serializable {
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
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
*/
package mage.view;
import java.io.Serializable;
@ -39,14 +39,14 @@ public class UsersView implements Serializable {
private final String flagName;
private final String userName;
private final String infoState;
private final String history;
private final String infoGames;
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.history = history;
this.userName = userName;
this.infoState = infoState;
this.infoGames = infoGames;
this.infoPing = infoPing;
}
@ -59,8 +59,8 @@ public class UsersView implements Serializable {
return userName;
}
public String getInfoState() {
return infoState;
public String getHistory() {
return history;
}
public String getInfoGames() {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -46,8 +46,8 @@ import mage.util.CardUtil;
*/
public class Commander extends DeckValidator {
protected List<String> banned = new ArrayList<>();
protected List<String> bannedCommander = new ArrayList<>();
protected List<String> banned = new ArrayList<>();
protected List<String> bannedCommander = new ArrayList<>();
public Commander() {
this("Commander");
@ -74,6 +74,7 @@ public class Commander extends DeckValidator {
banned.add("Painter's Servant");
banned.add("Panoptic Mirror");
banned.add("Primeval Titan");
banned.add("Prophet of Kruphix");
banned.add("Protean Hulk");
banned.add("Recurring Nightmare");
banned.add("Rofellos, Llanowar Emissary");
@ -103,7 +104,7 @@ public class Commander extends DeckValidator {
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"));
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
@ -130,22 +131,22 @@ public class Commander extends DeckValidator {
invalid.put("Commander", "Commander invalid ");
return false;
}
if ((commander.getCardType().contains(CardType.CREATURE) && commander.getSupertype().contains("Legendary")) ||
(commander.getCardType().contains(CardType.PLANESWALKER) && commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) {
if ((commander.getCardType().contains(CardType.CREATURE) && commander.getSupertype().contains("Legendary"))
|| (commander.getCardType().contains(CardType.PLANESWALKER) && commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) {
if (!bannedCommander.contains(commander.getName())) {
FilterMana color = CardUtil.getColorIdentity(commander);
for (Card card : deck.getCards()) {
if (!cardHasValidColor(color, card)) {
invalid.put(card.getName(), "Invalid color (" + commander.getName() +")");
invalid.put(card.getName(), "Invalid color (" + commander.getName() + ")");
valid = false;
}
}
} else {
invalid.put("Commander", "Commander banned (" + commander.getName() +")");
invalid.put("Commander", "Commander banned (" + commander.getName() + ")");
valid = false;
}
} else {
invalid.put("Commander", "Commander invalid (" + commander.getName() +")");
invalid.put("Commander", "Commander invalid (" + commander.getName() + ")");
valid = false;
}
} else {

View file

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

View file

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

View file

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

View file

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

View file

@ -120,7 +120,7 @@ public class TinyLeaders extends DeckValidator {
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"));
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
@ -145,19 +145,20 @@ public class TinyLeaders extends DeckValidator {
if (deck.getSideboard().size() <= 10) {
Card commander = GameTinyLeadersImpl.getCommanderCard(deck.getName(), null);
/**
* 905.5b - Each card must have a converted mana cost of three of less.
* Cards with {X} in their mana cost count X as zero.
* Split and double-face cards are legal only if both of their halves would be legal independently.
* 905.5b - Each card must have a converted mana cost of three of
* less. Cards with {X} in their mana cost count X as zero. Split
* 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 (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." +
"(You can use the \"Sultai\" for a UBG (2/2) default Commander.)");
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 (3/3) default Commander or \"Glass\" for a colorless 3/3 default Commander.)");
} 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 " +
"(use the \"Sultai\" for a UBG (2/2) default Commander)");
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 (3/3) default Commander or \"Glass\" for a colorless (3/3) default Commander)");
}
}
@ -172,12 +173,12 @@ public class TinyLeaders extends DeckValidator {
FilterMana color = CardUtil.getColorIdentity(commander);
for (Card card : deck.getCards()) {
if (!isCardFormatValid(card, commander, color)) {
valid = false;
valid = false;
}
}
for (Card card : deck.getSideboard()) {
if (!isCardFormatValid(card, commander, color)) {
valid = false;
valid = false;
}
}
} else {
@ -204,14 +205,14 @@ public class TinyLeaders extends DeckValidator {
//905.5b - Converted mana cost must be 3 or less
if (card instanceof SplitCard) {
if (((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() > 3) {
if (((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() > 3) {
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() + ")");
return false;
}
return false;
}
} else {
if (card.getManaCost().convertedManaCost() > 3) {
invalid.put(card.getName(), "Invalid cost (" + card.getManaCost().convertedManaCost() + ")");
@ -220,7 +221,7 @@ public class TinyLeaders extends DeckValidator {
}
return true;
}
/**
*
* @param commander FilterMana object with Color Identity of Commander set

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -27,6 +27,11 @@
*/
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.common.LimitedTimesPerTurnActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
@ -38,7 +43,13 @@ import mage.cards.Card;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
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.match.MatchType;
import mage.game.permanent.token.EmptyToken;
@ -46,8 +57,6 @@ import mage.game.turn.TurnMod;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.*;
/**
*
* @author nigelzor
@ -89,7 +98,7 @@ public class MomirDuel extends GameImpl {
@Override
public Set<UUID> getOpponents(UUID playerId) {
Set<UUID> opponents = new HashSet<>();
for (UUID opponentId: this.getPlayer(playerId).getInRange()) {
for (UUID opponentId : this.getPlayer(playerId).getInRange()) {
if (!opponentId.equals(playerId)) {
opponents.add(opponentId);
}
@ -114,7 +123,7 @@ class MomirEmblem extends Emblem {
public MomirEmblem() {
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.
LimitedTimesPerTurnActivatedAbility ability = new LimitedTimesPerTurnActivatedAbility(Zone.COMMAND, new MomirEffect(), new VariableManaCost());
ability.addCost(new DiscardCardCost());
@ -153,7 +162,9 @@ class MomirEffect extends OneShotEffect {
EmptyToken token = new EmptyToken();
CardUtil.copyTo(token).from(card);
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;
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -56,6 +56,7 @@ import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.ColoredManaCost;
import mage.abilities.costs.mana.ColorlessManaCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.HybridManaCost;
import mage.abilities.costs.mana.ManaCost;
@ -1007,7 +1008,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (card.getManaCost().getVariableCosts().size() > 0) {
//don't use variable mana costs unless there is at least 3 extra mana for X
for (Mana option : options) {
option.add(Mana.ColorlessMana(3));
option.add(Mana.GenericMana(3));
}
}
for (Mana mana : options) {
@ -1041,7 +1042,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (ability.getManaCosts().getVariableCosts().size() > 0) {
//don't use variable mana costs unless there is at least 3 extra mana for X
for (Mana option : abilityOptions) {
option.add(Mana.ColorlessMana(3));
option.add(Mana.GenericMana(3));
}
}
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
for (ManaAbility manaAbility : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) {
if (cost instanceof GenericManaCost) {
@ -1182,7 +1195,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
// pay phyrexian life costs
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;
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -34,9 +34,9 @@ import mage.game.draft.DraftCube;
* @author LevelX2
*/
public class MTGOLegacyCube extends DraftCube {
public class LegacyCube extends DraftCube {
public MTGOLegacyCube() {
public LegacyCube() {
super("MTGO Legacy Cube (600 cards)");
cubeCards.add(new CardIdentity("Accorder Paladin",""));
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
*/
public class MTGOLegacyCubeMarch2015 extends DraftCube {
public class LegacyCubeMarch2015 extends DraftCube {
public MTGOLegacyCubeMarch2015() {
public LegacyCubeMarch2015() {
super("MTGO Legacy Cube March 2015 (600 cards)");
cubeCards.add(new DraftCube.CardIdentity("Accorder Paladin",""));
cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay",""));

View file

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

View file

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

View file

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

View file

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

View file

@ -19,6 +19,17 @@
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"
serverName="mage-server"
@ -32,9 +43,20 @@
maxSecondsIdle="600"
minUserNameLength="3"
maxUserNameLength="14"
userNamePattern="[^a-z0-9_]"
invalidUserNamePattern="[^a-z0-9_]"
minPasswordLength="8"
maxPasswordLength="100"
maxAiOpponents="15"
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>
<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="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 Legacy Cube (600 cards)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOLegacyCube"/>
<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 September 2015 (600 cards)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOLegacyCubeSeptember2015"/>
<draftCube name="MTGO Legacy Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCube"/>
<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" 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 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"/>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.6</version>
<version>1.4.8</version>
</parent>
<artifactId>mage-server</artifactId>
@ -148,6 +148,62 @@
<version>${project.version}</version>
<scope>runtime</scope>
</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>
<build>

View file

@ -1,6 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<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"
serverName="mage-server"
port="17171"
@ -13,9 +43,20 @@
maxSecondsIdle="600"
minUserNameLength="3"
maxUserNameLength="14"
userNamePattern="[^a-z0-9_]"
invalidUserNamePattern="[^a-z0-9_]"
minPasswordLength="8"
maxPasswordLength="100"
maxAiOpponents="15"
saveGameActivated="false"
authenticationActivated="false"
googleAccount=""
mailgunApiKey=""
mailgunDomain=""
mailSmtpHost=""
mailSmtpPort=""
mailUser=""
mailPassword=""
mailFromAddress=""
/>
<playerTypes>
<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="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 Legacy Cube (600 cards)" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOLegacyCube"/>
<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 September 2015 (600 cards)" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOLegacyCubeSeptember2015"/>
<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" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
<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 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"/>

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
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
*/
package mage.server;
import java.util.ArrayList;
@ -44,14 +43,15 @@ import org.apache.log4j.Logger;
public class ChatManager {
private static final Logger logger = Logger.getLogger(ChatManager.class);
private static final ChatManager INSTANCE = new ChatManager();
public static ChatManager getInstance() {
return INSTANCE;
}
private ChatManager() {}
private ChatManager() {
}
private final ConcurrentHashMap<UUID, ChatSession> chatSessions = new ConcurrentHashMap<>();
@ -66,16 +66,16 @@ public class ChatManager {
if (chatSession != null) {
chatSession.join(userId);
} else {
logger.trace("Chat to join not found - chatId: " + chatId +" userId: " + userId);
}
logger.trace("Chat to join not found - chatId: " + chatId + " userId: " + userId);
}
}
public void leaveChat(UUID chatId, UUID userId) {
ChatSession chatSession = chatSessions.get(chatId);
if (chatSession != null && chatSession.hasUser(userId)) {
chatSession.kill(userId, DisconnectReason.CleaningUp);
}
}
}
public void destroyChatSession(UUID chatId) {
@ -88,7 +88,7 @@ public class ChatManager {
logger.trace("Chat removed - chatId: " + chatId);
} else {
logger.trace("Chat to destroy does not exist - chatId: " + chatId);
}
}
}
}
}
@ -110,7 +110,7 @@ public class ChatManager {
ChatSession chatSession = chatSessions.get(chatId);
if (chatSession != null) {
if (message.startsWith("\\") || message.startsWith("/")) {
User user = UserManager.getInstance().findUser(userName);
User user = UserManager.getInstance().getUserByName(userName);
if (user != null && performUserCommand(user, message, chatId)) {
return;
}
@ -119,63 +119,56 @@ public class ChatManager {
}
}
private boolean performUserCommand(User user, String message, UUID chatId) {
String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH);
if (command.equals("I") || command.equals("INFO")) {
user.setInfo("");
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);
if (command.startsWith("H ") || command.startsWith("HISTORY ")) {
message = UserManager.getInstance().getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9));
chatSessions.get(chatId).broadcastInfoToUser(user, message);
return true;
}
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(" ");
if (first > 1) {
String userToName = rest.substring(0,first);
String userToName = rest.substring(0, first);
rest = rest.substring(first + 1).trim();
User userTo = UserManager.getInstance().findUser(userToName);
User userTo = UserManager.getInstance().getUserByName(userToName);
if (userTo != null) {
if (!chatSessions.get(chatId).broadcastWhisperToUser(user, userTo, rest)) {
message += new StringBuilder("<br/>User ").append(userToName).append(" not found").toString();
chatSessions.get(chatId).broadcastInfoToUser(user,message);
chatSessions.get(chatId).broadcastInfoToUser(user, message);
}
} else {
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;
}
}
if (command.equals("L") || command.equals("LIST")) {
message += new StringBuilder("<br/>List of commands:")
.append("<br/>\\info [text] - set a info text to your player")
.append("<br/>\\list - Show a list of commands")
.append("<br/>\\whisper [player name] [text] - whisper to the player with the given name").toString();
chatSessions.get(chatId).broadcastInfoToUser(user,message);
.append("<br/>\\history or \\h [username] - shows the history of a player")
.append("<br/>\\list or \\l - Show a list of commands")
.append("<br/>\\whisper or \\w [player name] [text] - whisper to the player with the given name").toString();
chatSessions.get(chatId).broadcastInfoToUser(user, message);
return true;
}
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 message
* @param color
* @param color
*/
public void broadcast(UUID userId, String message, MessageColor color) {
User user = UserManager.getInstance().getUser(userId);
if (user != null) {
for (ChatSession chat: chatSessions.values()) {
for (ChatSession chat : chatSessions.values()) {
if (chat.hasUser(userId)) {
chat.broadcast(user.getName(), message, color);
}
@ -186,16 +179,16 @@ public class ChatManager {
public void sendReconnectMessage(UUID userId) {
User user = UserManager.getInstance().getUser(userId);
if (user != null) {
for (ChatSession chat: chatSessions.values()) {
for (ChatSession chat : chatSessions.values()) {
if (chat.hasUser(userId)) {
chat.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS);
}
}
}
}
}
}
public void removeUser(UUID userId, DisconnectReason reason) {
for (ChatSession chatSession: chatSessions.values()) {
for (ChatSession chatSession : chatSessions.values()) {
if (chatSession.hasUser(userId)) {
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;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
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 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 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) {
this.password = password;
public MageServerImpl(String adminPassword, boolean testMode) {
this.adminPassword = adminPassword;
this.testMode = testMode;
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
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 {
if (version.compareTo(Main.getVersion()) != 0) {
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());
}
return SessionManager.getInstance().registerUser(sessionId, userName);
return SessionManager.getInstance().connectUser(sessionId, userName, password);
} catch (MageException ex) {
if (ex instanceof MageVersionException) {
throw (MageVersionException) ex;
@ -134,15 +217,15 @@ public class MageServerImpl implements MageServer {
}
@Override
public boolean registerAdmin(String password, String sessionId, MageVersion version) throws MageException {
public boolean connectAdmin(String adminPassword, String sessionId, MageVersion version) throws MageException {
try {
if (version.compareTo(Main.getVersion()) != 0) {
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");
}
return SessionManager.getInstance().registerAdmin(sessionId);
return SessionManager.getInstance().connectAdmin(sessionId);
} catch (Exception ex) {
handleException(ex);
}
@ -362,7 +445,7 @@ public class MageServerImpl implements MageServer {
// }
@Override
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;
}
execute("startMatch", sessionId, new Action() {
@ -387,7 +470,7 @@ public class MageServerImpl implements MageServer {
// }
@Override
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;
}
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 {
if (checkAdminRights) {
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.
*
* 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.
*/
* 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.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.game.match.MatchType;
import mage.game.tournament.TournamentType;
@ -37,6 +43,7 @@ import mage.server.draft.CubeFactory;
import mage.server.game.DeckValidatorFactory;
import mage.server.game.GameFactory;
import mage.server.game.PlayerFactory;
import mage.server.record.UserStatsRepository;
import mage.server.tournament.TournamentFactory;
import mage.server.util.ConfigSettings;
import mage.server.util.PluginClassLoader;
@ -46,26 +53,23 @@ import mage.server.util.config.GamePlugin;
import mage.server.util.config.Plugin;
import mage.utils.MageVersion;
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.ServerInvokerCallbackHandler;
import org.jboss.remoting.transport.Connector;
import org.jboss.remoting.transport.bisocket.BisocketServerInvoker;
import org.jboss.remoting.transport.socket.SocketWrapper;
import org.jboss.remoting.transporter.TransporterClient;
import org.jboss.remoting.transporter.TransporterServer;
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
@ -73,14 +77,13 @@ import org.jboss.remoting.transport.bisocket.BisocketServerInvoker;
public class Main {
private static final Logger logger = Logger.getLogger(Main.class);
private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO);
private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO);
private static final String testModeArg = "-testMode=";
private static final String fastDBModeArg = "-fastDbMode=";
private static final String adminPasswordArg = "-adminPassword=";
private static final String pluginFolder = "plugins";
public static PluginClassLoader classLoader = new PluginClassLoader();
public static TransporterServer server;
protected static boolean testMode;
@ -95,19 +98,17 @@ public class Main {
logger.info("Logging level: " + logger.getEffectiveLevel());
String adminPassword = "";
for (String arg: args) {
for (String arg : args) {
if (arg.startsWith(testModeArg)) {
testMode = Boolean.valueOf(arg.replace(testModeArg, ""));
}
else if (arg.startsWith(adminPasswordArg)) {
} else if (arg.startsWith(adminPasswordArg)) {
adminPassword = arg.replace(adminPasswordArg, "");
adminPassword = SystemUtil.sanitize(adminPassword);
}
else if (arg.startsWith(fastDBModeArg)) {
} else if (arg.startsWith(fastDBModeArg)) {
fastDbMode = Boolean.valueOf(arg.replace(fastDBModeArg, ""));
}
}
logger.info("Loading cards...");
if (fastDbMode) {
CardScanner.scanned = true;
@ -116,54 +117,68 @@ public class Main {
}
logger.info("Done.");
logger.info("Updating user stats DB...");
UserStatsRepository.instance.updateUserStats();
logger.info("Done.");
deleteSavedGames();
ConfigSettings config = ConfigSettings.getInstance();
for (GamePlugin plugin: config.getGameTypes()) {
for (GamePlugin plugin : config.getGameTypes()) {
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));
}
for (Plugin plugin: config.getPlayerTypes()) {
for (Plugin plugin : config.getPlayerTypes()) {
PlayerFactory.getInstance().addPlayerType(plugin.getName(), loadPlugin(plugin));
}
for (Plugin plugin: config.getDraftCubes()) {
for (Plugin plugin : config.getDraftCubes()) {
CubeFactory.getInstance().addDraftCube(plugin.getName(), loadPlugin(plugin));
}
for (Plugin plugin: config.getDeckTypes()) {
for (Plugin plugin : config.getDeckTypes()) {
DeckValidatorFactory.getInstance().addDeckType(plugin.getName(), loadPlugin(plugin));
}
logger.info("Config - max seconds idle: " + config.getMaxSecondsIdle());
logger.info("Config - max game threads: " + config.getMaxGameThreads());
logger.info("Config - max AI opponents: " + config.getMaxAiOpponents());
logger.info("Config - min user name l.: " + config.getMinUserNameLength());
logger.info("Config - max user name l.: " + config.getMaxUserNameLength());
logger.info("Config - save game active: " + (config.isSaveGameActivated() ? "True":"false"));
logger.info("Config - min usr name le.: " + config.getMinUserNameLength());
logger.info("Config - max usr name le.: " + config.getMaxUserNameLength());
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 - lease period : " + config.getLeasePeriod());
logger.info("Config - max pool size : " + config.getMaxPoolSize());
logger.info("Config - num accp.threads: " + config.getNumAcceptThreads());
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.setHost(config.getServerAddress());
connection.setPort(config.getPort());
try {
// Parameter: serializationtype => jboss
InvokerLocator serverLocator = new InvokerLocator(connection.getURI());
InvokerLocator serverLocator = new InvokerLocator(connection.getURI());
if (!isAlreadyRunning(serverLocator)) {
server = new MageTransporterServer(serverLocator, new MageServerImpl(adminPassword, testMode), MageServer.class.getName(), new MageServerInvocationHandler());
server.start();
logger.info("Started MAGE server - listening on " + connection.toString());
if (testMode) {
logger.info("MAGE server running in test mode");
}
initStatistics();
}
else {
} else {
logger.fatal("Unable to start MAGE server - another server is already started");
}
} catch (Exception ex) {
@ -192,6 +207,7 @@ public class Main {
}
static class ClientConnectionListener implements ConnectionListener {
@Override
public void handleConnectionException(Throwable throwable, Client client) {
Session session = SessionManager.getInstance().getSession(client.getSessionId());
@ -207,12 +223,12 @@ public class Main {
if (throwable instanceof ClientDisconnectedException) {
// Seems like the random diconnects from public server land here and should not be handled as explicit disconnects
// So it should be possible to reconnect to server and continue games if DisconnectReason is set to LostConnection
//SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.Disconnected);
//SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.Disconnected);
SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.LostConnection);
logger.info("CLIENT DISCONNECTED - " + sessionInfo);
logger.debug("Stack Trace", throwable);
} else {
SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.LostConnection);
} else {
SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.LostConnection);
logger.info("LOST CONNECTION - " + sessionInfo);
if (logger.isDebugEnabled()) {
if (throwable == null) {
@ -220,7 +236,7 @@ public class Main {
} else {
logger.debug(" - cause: " + Session.getBasicCause(throwable).toString());
}
}
}
}
}
}
@ -253,13 +269,13 @@ public class Main {
@Override
public void setMBeanServer(MBeanServer server) {
}
@Override
public void setInvoker(ServerInvoker invoker) {
public void setInvoker(ServerInvoker invoker) {
((BisocketServerInvoker) invoker).setSecondaryBindPort(ConfigSettings.getInstance().getSecondaryBindPort());
((BisocketServerInvoker) invoker).setBacklog(ConfigSettings.getInstance().getBacklogSize());
((BisocketServerInvoker) invoker).setBacklog(ConfigSettings.getInstance().getBacklogSize());
((BisocketServerInvoker) invoker).setNumAcceptThreads(ConfigSettings.getInstance().getNumAcceptThreads());
}
@ -330,7 +346,7 @@ public class Main {
logger.debug("Loading tournament type: " + plugin.getClassName());
return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance();
} 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) {
logger.fatal("Error loading game type " + plugin.getJar(), ex);
}
@ -343,15 +359,14 @@ public class Main {
directory.mkdirs();
}
File[] files = directory.listFiles(
new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".game");
new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".game");
}
}
}
);
for (File file : files)
{
for (File file : files) {
file.delete();
}
}

View file

@ -55,6 +55,8 @@ import org.jboss.remoting.callback.InvokerCallbackHandler;
public class Session {
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 UUID userId;
@ -74,8 +76,98 @@ public class Session {
this.lock = new ReentrantLock();
}
public String registerUser(String userName) throws MageException {
String returnMessage = registerUserHandling(userName);
public String registerUser(String userName, String password, String email) throws MageException {
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) {
sendErrorMessageToClient(returnMessage);
}
@ -86,27 +178,21 @@ public class Session {
return lock.isLocked();
}
public String registerUserHandling(String userName) throws MageException {
public String connectUserHandling(String userName, String password) throws MageException {
this.isAdmin = false;
if (userName.equals("Admin")) {
return "User name Admin already in use";
}
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";
if (ConfigSettings.getInstance().isAuthenticationActivated()) {
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.";
}
}
User user = UserManager.getInstance().createUser(userName, host);
boolean reconnect = false;
if (user == null) { // user already exists
user = UserManager.getInstance().findUser(userName);
if (user.getHost().equals(host)) {
user = UserManager.getInstance().getUserByName(userName);
// 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
this.userId = user.getId();
if (user.getSessionId().isEmpty()) {
@ -135,11 +221,11 @@ public class Session {
return null;
}
public void registerAdmin() {
public void connectAdmin() {
this.isAdmin = true;
User user = UserManager.getInstance().createUser("Admin", host);
if (user == null) {
user = UserManager.getInstance().findUser("Admin");
user = UserManager.getInstance().getUserByName("Admin");
}
UserData adminUserData = UserData.getDefaultUserDataView();
adminUserData.setGroupId(UserGroup.ADMIN.getGroupId());
@ -151,7 +237,7 @@ public class Session {
}
public boolean setUserData(String userName, UserData userData) {
User user = UserManager.getInstance().findUser(userName);
User user = UserManager.getInstance().getUserByName(userName);
if (user != null) {
if (user.getUserData() == null || user.getUserData().getGroupId() == UserGroup.DEFAULT.getGroupId()) {
user.setUserData(userData);
@ -279,7 +365,7 @@ public class Session {
this.host = hostAddress;
}
void sendErrorMessageToClient(String message) {
public void sendErrorMessageToClient(String message) {
List<String> messageData = new LinkedList<>();
messageData.add("Error while connecting to server");
messageData.add(message);

View file

@ -70,31 +70,51 @@ public class SessionManager {
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);
if (session != null) {
String returnMessage = session.registerUser(userName);
String returnMessage = session.connectUser(userName, password);
if (returnMessage == null) {
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("- sessionId: " + sessionId);
logger.debug("- host: " + session.getHost());
return true;
} else {
logger.debug(userName + " not registered: " + returnMessage);
logger.debug(userName + " not connected: " + returnMessage);
}
} else {
logger.error(userName + " tried to join with no sessionId");
logger.error(userName + " tried to connect with no sessionId");
}
return false;
}
public boolean registerAdmin(String sessionId) {
public boolean connectAdmin(String sessionId) {
Session session = sessions.get(sessionId);
if (session != null) {
session.registerAdmin();
session.connectAdmin();
LogServiceImpl.instance.log(LogKeys.KEY_ADMIN_CONNECTED, "Admin", session.getHost(), sessionId);
logger.info("Admin connected from " + session.getHost());
return true;
@ -217,4 +237,13 @@ public class SessionManager {
}
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.GameManager;
import mage.server.game.PlayerFactory;
import mage.server.record.TableRecorderImpl;
import mage.server.services.LogKeys;
import mage.server.services.impl.LogServiceImpl;
import mage.server.tournament.TournamentController;
@ -105,7 +106,7 @@ public class TableController {
} else {
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());
init();
}
@ -124,7 +125,7 @@ public class TableController {
} else {
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());
}
@ -237,6 +238,7 @@ public class TableController {
TournamentPlayer newTournamentPlayer = tournament.getPlayer(newPlayer.getId());
newTournamentPlayer.setState(oldTournamentPlayer.getState());
newTournamentPlayer.setReplacedTournamentPlayer(oldTournamentPlayer);
DraftManager.getInstance().getController(table.getId()).replacePlayer(oldPlayer, newPlayer);
return true;
@ -957,26 +959,16 @@ public class TableController {
return getTable().getState();
}
public synchronized boolean changeTableState(TableState newTableState) {
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)) {
// tournament is not ready, can't start
return false;
}
if (!table.allSeatsAreOccupied()) {
logger.debug("Not alle Seats are occupied: stop start tableId:" + table.getId());
return false;
}
break;
public synchronized boolean changeTableStateToStarting() {
if (!getTable().getState().equals(TableState.READY_TO_START)) {
// tournament is not ready, can't start
return false;
}
getTable().setState(newTableState);
if (!table.allSeatsAreOccupied()) {
logger.debug("Not alle Seats are occupied: stop start tableId:" + table.getId());
return false;
}
getTable().setState(TableState.STARTING);
return true;
}
}

View file

@ -40,12 +40,15 @@ import java.util.concurrent.TimeUnit;
import mage.cards.decks.Deck;
import mage.constants.ManaType;
import mage.game.Table;
import mage.game.result.ResultProtos;
import mage.game.tournament.TournamentPlayer;
import mage.interfaces.callback.ClientCallback;
import mage.players.net.UserData;
import mage.server.draft.DraftSession;
import mage.server.game.GameManager;
import mage.server.game.GameSessionPlayer;
import mage.server.record.UserStats;
import mage.server.record.UserStatsRepository;
import mage.server.tournament.TournamentController;
import mage.server.tournament.TournamentManager;
import mage.server.tournament.TournamentSession;
@ -59,7 +62,7 @@ import org.apache.log4j.Logger;
*/
public class User {
private static final Logger logger = Logger.getLogger(User.class);
private static final Logger LOGGER = Logger.getLogger(User.class);
public enum UserState {
@ -79,11 +82,11 @@ public class User {
private final Map<UUID, Deck> sideboarding;
private final List<UUID> watchedGames;
private String sessionId;
private String info = "";
private String pingInfo = "";
private Date lastActivity;
private UserState userState;
private UserData userData;
private UserStats userStats;
public User(String userName, String host) {
this.userId = UUID.randomUUID();
@ -103,6 +106,7 @@ public class User {
this.watchedGames = new ArrayList<>();
this.tablesToDelete = new ArrayList<>();
this.sessionId = "";
this.userStats = null;
}
public String getName() {
@ -126,15 +130,15 @@ public class User {
if (sessionId.isEmpty()) {
userState = UserState.Disconnected;
lostConnection();
logger.trace("USER - lost connection: " + userName + " id: " + userId);
LOGGER.trace("USER - lost connection: " + userName + " id: " + userId);
} else if (userState == UserState.Created) {
userState = UserState.Connected;
logger.trace("USER - created: " + userName + " id: " + userId);
LOGGER.trace("USER - created: " + userName + " id: " + userId);
} else {
userState = UserState.Reconnected;
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) {
if (lastActivity.before(expired)) {
logger.trace(userName + " is expired!");
LOGGER.trace(userName + " is expired!");
userState = UserState.Expired;
return true;
}
logger.trace(new StringBuilder("isExpired: User ").append(userName).append(" lastActivity: ").append(lastActivity).append(" expired: ").append(expired).toString());
return false; /*userState == UserState.Disconnected && */
LOGGER.trace(new StringBuilder("isExpired: User ").append(userName).append(" lastActivity: ").append(lastActivity).append(" expired: ").append(expired).toString());
return false;
/*userState == UserState.Disconnected && */
}
@ -357,35 +362,35 @@ public class User {
}
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()) {
draftSession.setKilled();
}
draftSessions.clear();
logger.trace("REMOVE " + getName() + " Tournament sessions " + userTournaments.size());
LOGGER.trace("REMOVE " + getName() + " Tournament sessions " + userTournaments.size());
for (UUID tournamentId : userTournaments.values()) {
TournamentManager.getInstance().quit(tournamentId, getId());
}
userTournaments.clear();
logger.trace("REMOVE " + getName() + " Tables " + tables.size());
LOGGER.trace("REMOVE " + getName() + " Tables " + tables.size());
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());
}
tables.clear();
logger.trace("REMOVE " + getName() + " Game sessions: " + gameSessions.size());
LOGGER.trace("REMOVE " + getName() + " Game sessions: " + gameSessions.size());
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);
gameSessionPlayer.quitGame();
}
gameSessions.clear();
logger.trace("REMOVE " + getName() + " watched Games " + watchedGames.size());
LOGGER.trace("REMOVE " + getName() + " watched Games " + watchedGames.size());
for (UUID gameId : watchedGames) {
GameManager.getInstance().stopWatching(gameId, userId);
}
watchedGames.clear();
logger.trace("REMOVE " + getName() + " Chats ");
LOGGER.trace("REMOVE " + getName() + " Chats ");
ChatManager.getInstance().removeUser(userId, reason);
}
@ -394,6 +399,12 @@ public class User {
this.userData.update(userData);
} else {
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 {
// 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());
}
} else {
logger.error(getName() + " tournament key missing - tableId: " + table.getId(), null);
LOGGER.error(getName() + " tournament key missing - tableId: " + table.getId(), null);
}
} else {
switch (table.getState()) {
@ -497,14 +508,6 @@ public class User {
return sb.toString();
}
public String getInfo() {
return info;
}
public void setInfo(String Info) {
this.info = Info;
}
public void addGameWatchInfo(UUID 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

@ -1,16 +1,16 @@
/*
* Copyright 2011 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
@ -20,7 +20,7 @@
* 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.
@ -38,6 +38,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import mage.server.User.UserState;
import mage.server.record.UserStats;
import mage.server.record.UserStatsRepository;
import mage.server.util.ThreadExecutor;
import org.apache.log4j.Logger;
@ -45,7 +47,7 @@ import org.apache.log4j.Logger;
*
* manages users - if a user is disconnected and 10 minutes have passed with no
* activity the user is removed
*
*
* @author BetaSteward_at_googlemail.com
*/
public class UserManager {
@ -55,7 +57,8 @@ public class UserManager {
private static final Logger logger = Logger.getLogger(UserManager.class);
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 UserManager INSTANCE = new UserManager();
@ -63,8 +66,8 @@ public class UserManager {
public static UserManager getInstance() {
return INSTANCE;
}
private UserManager() {
private UserManager() {
expireExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
@ -74,11 +77,12 @@ public class UserManager {
}
public User createUser(String userName, String host) {
if (findUser(userName) != null) {
if (getUserByName(userName) != null) {
return null; //user already exists
}
User user = new User(userName, host);
users.put(user.getId(), user);
usersByName.put(userName, user);
return user;
}
@ -89,13 +93,8 @@ public class UserManager {
return null;
}
public User findUser(String userName) {
for (User user: users.values()) {
if (user.getName().equals(userName)) {
return user;
}
}
return null;
public User getUserByName(String userName) {
return usersByName.get(userName);
}
public Collection<User> getUsers() {
@ -116,7 +115,7 @@ public class UserManager {
public void disconnect(UUID userId, DisconnectReason reason) {
if (userId != null) {
User user = users.get(userId);
if (user != null) {
if (user != null) {
user.setSessionId(""); // Session will be set again with new id if user reconnects
}
ChatManager.getInstance().removeUser(userId, reason);
@ -126,43 +125,44 @@ public class UserManager {
public boolean isAdmin(UUID userId) {
if (userId != null) {
User user = users.get(userId);
if (user != null) {
if (user != null) {
return user.getName().equals("Admin");
}
}
return false;
}
public void removeUser(final UUID userId, final DisconnectReason reason) {
public void removeUser(final UUID userId, final DisconnectReason reason) {
if (userId != null) {
final User user = users.get(userId);
if (user != null) {
callExecutor.execute(
new Runnable() {
@Override
public void run() {
try {
logger.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId);
user.remove(reason);
logger.debug("USER REMOVE END - " + user.getName());
} catch (Exception ex) {
handleException(ex);
} finally {
users.remove(userId);
}
new Runnable() {
@Override
public void run() {
try {
logger.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId);
user.remove(reason);
logger.debug("USER REMOVE END - " + user.getName());
} catch (Exception ex) {
handleException(ex);
} finally {
users.remove(userId);
usersByName.remove(user.getName());
}
}
}
);
} else {
logger.warn("Trying to remove userId: " + userId + " - but it does not exist.");
}
}
}
}
public boolean extendUserSession(UUID userId, String pingInfo) {
if (userId != null) {
User user = users.get(userId);
if (user != null) {
if (user != null) {
user.updateLastActivity(pingInfo);
return true;
}
@ -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() {
Calendar calendar = Calendar.getInstance();
@ -187,13 +188,39 @@ public class UserManager {
public void handleException(Exception ex) {
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) {
logger.debug("- Cause: " + (ex.getCause().getMessage() == null ? "null":ex.getCause().getMessage()));
logger.debug("- Cause: " + (ex.getCause().getMessage() == null ? "null" : ex.getCause().getMessage()));
}
ex.printStackTrace();
}else {
} else {
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) {
tableList.add(new TableView(table));
} else if (matchList.size() < 50) {
if (table.isTournament()) {
matchList.add(new MatchView(table));
} else {
matchList.add(new MatchView(table));
}
matchList.add(new MatchView(table));
} else {
// more since 50 matches finished since this match so remove it
if (table.isTournament()) {
@ -118,13 +114,13 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
List<UsersView> users = new ArrayList<>();
for (User user : UserManager.getInstance().getUsers()) {
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) {
logger.fatal("User update exception: " + user.getName() + " - " + ex.toString(), ex);
users.add(new UsersView(
(user.getUserData() != null && user.getUserData().getFlagName() != null) ? user.getUserData().getFlagName() : "world",
user.getName() != null ? user.getName() : "<no name>",
user.getInfo() != null ? user.getInfo() : "<no info>",
user.getHistory() != null ? user.getHistory() : "<no history>",
"[exception]",
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_USER_REGISTERED = "userRegistered";
String KEY_USER_CONNECTED = "userConnected";
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 mage.game.match.Match;
import mage.game.match.MatchOptions;
import mage.game.result.ResultProtos.TourneyQuitStatus;
import mage.game.tournament.Tournament;
import mage.game.tournament.TournamentPairing;
import mage.game.tournament.TournamentPlayer;
@ -351,31 +352,34 @@ public class TournamentController {
tournamentSession.setKilled();
if (tournamentPlayer.isInTournament()) {
String info;
TourneyQuitStatus status;
if (tournament.isDoneConstructing()) {
info = new StringBuilder("during round ").append(tournament.getRounds().size()).toString();
// quit active matches of that tournament
TableManager.getInstance().userQuitTournamentSubTables(tournament.getId(), userId);
} else {
if (tournamentPlayer.getState().equals(TournamentPlayerState.DRAFTING)) {
info = "during Draft phase";
if (!checkToReplaceDraftPlayerByAi(userId, tournamentPlayer)) {
this.abortDraftTournament();
} else {
DraftController draftController = DraftManager.getInstance().getController(tableId);
if (draftController != null) {
DraftSession draftSession = draftController.getDraftSession(playerId);
if (draftSession != null) {
DraftManager.getInstance().kill(draftSession.getDraftId(), userId);
}
status = TourneyQuitStatus.DURING_ROUND;
} else if (tournamentPlayer.getState().equals(TournamentPlayerState.DRAFTING)) {
info = "during Draft phase";
if (!checkToReplaceDraftPlayerByAi(userId, tournamentPlayer)) {
this.abortDraftTournament();
} else {
DraftController draftController = DraftManager.getInstance().getController(tableId);
if (draftController != null) {
DraftSession draftSession = draftController.getDraftSession(playerId);
if (draftSession != null) {
DraftManager.getInstance().kill(draftSession.getDraftId(), userId);
}
}
} else if (tournamentPlayer.getState().equals(TournamentPlayerState.CONSTRUCTING)) {
info = "during Construction phase";
} else {
info = "";
}
status = TourneyQuitStatus.DURING_DRAFTING;
} else if (tournamentPlayer.getState().equals(TournamentPlayerState.CONSTRUCTING)) {
info = "during Construction phase";
status = TourneyQuitStatus.DURING_CONSTRUCTION;
} else {
info = "";
status = TourneyQuitStatus.NO_TOURNEY_QUIT;
}
tournamentPlayer.setQuit(info);
tournamentPlayer.setQuit(info, status);
tournament.quit(playerId);
tournamentSession.quit();
ChatManager.getInstance().broadcast(chatId, "", tournamentPlayer.getPlayer().getLogName() + " has quit the tournament", MessageColor.BLACK, true, MessageType.STATUS, SoundToPlay.PlayerQuitTournament);

View file

@ -94,7 +94,7 @@ public class ConfigSettings {
public int getBacklogSize() {
return config.getServer().getBacklogSize().intValue();
}
public int getMaxGameThreads() {
return config.getServer().getMaxGameThreads().intValue();
}
@ -111,17 +111,61 @@ public class ConfigSettings {
return config.getServer().getMaxUserNameLength().intValue();
}
public String getUserNamePattern() {
return config.getServer().getUserNamePattern();
public String getInvalidUserNamePattern() {
return config.getServer().getInvalidUserNamePattern();
}
public int getMinPasswordLength() {
return config.getServer().getMinPasswordLength().intValue();
}
public int getMaxPasswordLength() {
return config.getServer().getMaxPasswordLength().intValue();
}
public String getMaxAiOpponents() {
return config.getServer().getMaxAiOpponents();
}
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() {
return config.getPlayerTypes().getPlayerType();

View file

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Config.xsd">
<server serverAddress="0.0.0.0"
serverName="mage-server"
port="17171"
secondaryBindPort="-1"
backlogSize="200"
numAcceptThreads="2"
maxPoolSize="300"
leasePeriod="5000"
<server serverAddress="0.0.0.0"
serverName="mage-server"
port="17171"
secondaryBindPort="-1"
backlogSize="200"
numAcceptThreads="2"
maxPoolSize="300"
leasePeriod="5000"
maxGameThreads="10"
maxSecondsIdle="600"
minUserNameLength="3"
@ -16,6 +16,8 @@
userNamePattern="[^a-z0-9_]"
maxAiOpponents="15"
saveGameActivated="false"
authenticationActivated="false"
googleAccount=""
/>
<playerTypes>
<playerType name="Human" jar="Mage.Player.Human.jar" className="mage.player.human.HumanPlayer"/>

View file

@ -2,19 +2,19 @@
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="config">
<xs:element name="config">
<xs:complexType>
<xs:sequence>
<xs:element ref="server"/>
<xs:element ref="playerTypes"/>
<xs:element ref="gameTypes"/>
<xs:element ref="tournamentTypes"/>
<xs:element ref="draftCubes"/>
<xs:element ref="draftCubes"/>
<xs:element ref="deckTypes"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="server">
<xs:complexType>
<xs:attribute name="serverAddress" type="xs:string" use="required"/>
@ -22,16 +22,27 @@
<xs:attribute name="port" type="xs:positiveInteger" use="required"/>
<xs:attribute name="maxGameThreads" type="xs:positiveInteger" use="required"/>
<xs:attribute name="maxSecondsIdle" type="xs:positiveInteger" use="required"/>
<xs:attribute name="secondaryBindPort" type="xs:integer" use="required"/>
<xs:attribute name="backlogSize" type="xs:positiveInteger" use="required"/>
<xs:attribute name="numAcceptThreads" type="xs:positiveInteger" use="required"/>
<xs:attribute name="maxPoolSize" 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="maxUserNameLength" type="xs:positiveInteger" use="required"/>
<xs:attribute name="userNamePattern" type="xs:string" use="required"/>
<xs:attribute name="maxAiOpponents" type="xs:string" use="optional"/>
<xs:attribute name="saveGameActivated" type="xs:boolean" use="optional"/>
<xs:attribute name="secondaryBindPort" type="xs:integer" use="required"/>
<xs:attribute name="backlogSize" type="xs:positiveInteger" use="required"/>
<xs:attribute name="numAcceptThreads" type="xs:positiveInteger" use="required"/>
<xs:attribute name="maxPoolSize" 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="maxUserNameLength" type="xs:positiveInteger" 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="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:element>
@ -56,7 +67,7 @@
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="gameTypes">
<xs:complexType>
<xs:sequence>

View file

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

View file

@ -48,7 +48,7 @@ public class BattleForZendikar extends ExpansionSet {
return fINSTANCE;
}
List<CardInfo> savedSpecialLand = new ArrayList<>();
protected final List<CardInfo> savedSpecialLand = new ArrayList<>();
private BattleForZendikar() {
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.hasBasicLands = true;
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.numBoosterUncommon = 3;
this.numBoosterRare = 1;
this.ratioBoosterMythic = 8;
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
public List<CardInfo> getSpecialLand() {
List<CardInfo> specialLand = new ArrayList<>();
if (savedSpecialLand.isEmpty()) {
CardCriteria criteria = new CardCriteria();
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 specialLand;
return new ArrayList<>(savedSpecialLand);
}
}

View file

@ -5,8 +5,14 @@
*/
package mage.sets;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import mage.cards.ExpansionSet;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.constants.SetType;
/**
@ -21,9 +27,12 @@ public class OathOfTheGatewatch extends ExpansionSet {
return fINSTANCE;
}
protected final List<CardInfo> savedSpecialLand = new ArrayList<>();
private OathOfTheGatewatch() {
super("Oath of the Gatewatch", "OGW", "mage.sets.oathofthegatewatch", new GregorianCalendar(2016, 1, 22).getTime(), SetType.EXPANSION);
this.blockName = "Battle for Zendikar";
this.parentSet = BattleForZendikar.getInstance();
this.hasBoosters = true;
this.hasBasicLands = false;
this.numBoosterLands = 1;
@ -31,5 +40,21 @@ public class OathOfTheGatewatch extends ExpansionSet {
this.numBoosterUncommon = 3;
this.numBoosterRare = 1;
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

@ -54,15 +54,11 @@ import mage.target.targetpointer.FixedTarget;
* @author jeffwadsworth
*/
public class Crystallization extends CardImpl {
public Crystallization(UUID ownerId) {
super(ownerId, 144, "Crystallization", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{G/U}{W}");
this.expansionSetCode = "ARB";
this.subtype.add("Aura");
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
@ -77,11 +73,11 @@ public class Crystallization extends CardImpl {
// When enchanted creature becomes the target of a spell or ability, exile that creature.
this.addAbility(new CrystallizationTriggeredAbility());
}
public Crystallization(final Crystallization card) {
super(card);
}
@Override
public Crystallization copy() {
return new Crystallization(this);
@ -89,15 +85,15 @@ public class Crystallization extends CardImpl {
}
class CrystallizationTriggeredAbility extends TriggeredAbilityImpl {
public CrystallizationTriggeredAbility() {
super(Zone.BATTLEFIELD, new ExileTargetEffect());
}
public CrystallizationTriggeredAbility(final CrystallizationTriggeredAbility ability) {
super(ability);
}
@Override
public CrystallizationTriggeredAbility copy() {
return new CrystallizationTriggeredAbility(this);
@ -107,7 +103,7 @@ class CrystallizationTriggeredAbility extends TriggeredAbilityImpl {
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.TARGETED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent enchantment = game.getPermanent(sourceId);
@ -120,7 +116,7 @@ class CrystallizationTriggeredAbility extends TriggeredAbilityImpl {
}
return false;
}
@Override
public String getRule() {
return "When enchanted creature becomes the target of a spell or ability, exile that creature.";

View file

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

View file

@ -105,7 +105,7 @@ class VectisDominatorEffect extends OneShotEffect {
cost.clearPaid();
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)) {
cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), true);
cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), true, null);
}
if (!cost.isPaid()) {
return targetCreature.tap(game);

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