diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 2408b06cea2..a08c1e16a02 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -92,6 +92,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.prefs.Preferences; +import mage.view.UserRequestMessage; import net.java.truevfs.access.TArchiveDetector; import net.java.truevfs.access.TConfig; import net.java.truevfs.kernel.spec.FsAccessOption; @@ -1059,6 +1060,24 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } } + public void showUserRequestDialog(final UserRequestMessage userRequestMessage) { + final UserRequestDialog userRequestDialog = new UserRequestDialog(); + userRequestDialog.setLocation(100, 100); + desktopPane.add(userRequestDialog, JLayeredPane.MODAL_LAYER); +// ui.addComponent(MageComponents.DESKTOP_PANE, userRequestDialog); + if (SwingUtilities.isEventDispatchThread()) { + userRequestDialog.showDialog(userRequestMessage); + } else { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + userRequestDialog.showDialog(userRequestMessage); + } + }); + } + + } + public void showErrorDialog(final String title, final String message) { if (SwingUtilities.isEventDispatchThread()) { errorDialog.showDialog(title, message); diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index 332114b44fd..4570ed36725 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -24,7 +24,6 @@ - @@ -32,6 +31,7 @@ + @@ -80,12 +80,12 @@ - + - + @@ -107,7 +107,39 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -119,11 +151,6 @@ - - - - - @@ -138,11 +165,6 @@ - - - - - @@ -157,11 +179,6 @@ - - - - - @@ -178,7 +195,42 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -191,11 +243,6 @@ - - - - - @@ -207,11 +254,6 @@ - - - - - @@ -223,11 +265,17 @@ - - - - - + + + + + + + + + + + @@ -244,7 +292,22 @@ - + + + + + + + + + + + + + + + + @@ -255,11 +318,6 @@ - - - - - @@ -1054,7 +1112,7 @@ - + diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 9c772f8d6b6..acf8934ce47 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -83,6 +83,7 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_PERMANENTS_IN_ONE_PILE = "nonLandPermanentsInOnePile"; public static final String KEY_SHOW_PLAYER_NAMES_PERMANENTLY = "showPlayerNamesPermanently"; public static final String KEY_SHOW_ABILITY_PICKER_FORCED = "showAbilityPicker"; + public static final String KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS = "gameAllowRequestShowHandCards"; public static final String KEY_GAME_LOG_AUTO_SAVE = "gameLogAutoSave"; public static final String KEY_CARD_IMAGES_USE_DEFAULT = "cardImagesUseDefault"; @@ -318,6 +319,7 @@ public class PreferencesDialog extends javax.swing.JDialog { nonLandPermanentsInOnePile = new javax.swing.JCheckBox(); showPlayerNamesPermanently = new javax.swing.JCheckBox(); showAbilityPickerForced = new javax.swing.JCheckBox(); + cbAllowRequestToShowHandCards = new javax.swing.JCheckBox(); main_gamelog = new javax.swing.JPanel(); cbGameLogAutoSave = new javax.swing.JCheckBox(); tabPhases = new javax.swing.JPanel(); @@ -423,7 +425,6 @@ public class PreferencesDialog extends javax.swing.JDialog { setTitle("Preferences"); main_card.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card")); - main_card.setLayout(new java.awt.BorderLayout()); displayBigCardsInHand.setText("Use big images (for high resolution screens)"); displayBigCardsInHand.setToolTipText("Changes the size of the cards shown in hand. Switch this option off if you have a small screen size."); @@ -434,7 +435,6 @@ public class PreferencesDialog extends javax.swing.JDialog { displayBigCardsInHandActionPerformed(evt); } }); - main_card.add(displayBigCardsInHand, java.awt.BorderLayout.PAGE_START); showToolTipsInAnyZone.setSelected(true); showToolTipsInAnyZone.setText("Show card tooltips while hoovering with the mouse pointer over a card"); @@ -446,7 +446,6 @@ public class PreferencesDialog extends javax.swing.JDialog { showToolTipsInAnyZoneActionPerformed(evt); } }); - main_card.add(showToolTipsInAnyZone, java.awt.BorderLayout.CENTER); showCardName.setSelected(true); showCardName.setText("Show card name on card panel"); @@ -458,10 +457,34 @@ public class PreferencesDialog extends javax.swing.JDialog { showCardNameActionPerformed(evt); } }); - main_card.add(showCardName, java.awt.BorderLayout.PAGE_END); + + javax.swing.GroupLayout main_cardLayout = new javax.swing.GroupLayout(main_card); + main_card.setLayout(main_cardLayout); + main_cardLayout.setHorizontalGroup( + main_cardLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(main_cardLayout.createSequentialGroup() + .addContainerGap() + .addGroup(main_cardLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(main_cardLayout.createSequentialGroup() + .addComponent(displayBigCardsInHand, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + .addGroup(main_cardLayout.createSequentialGroup() + .addGroup(main_cardLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(showToolTipsInAnyZone) + .addComponent(showCardName)) + .addGap(0, 0, Short.MAX_VALUE)))) + ); + main_cardLayout.setVerticalGroup( + main_cardLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(main_cardLayout.createSequentialGroup() + .addComponent(displayBigCardsInHand) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(showToolTipsInAnyZone) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(showCardName)) + ); main_game.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Game")); - main_game.setLayout(new java.awt.BorderLayout()); nonLandPermanentsInOnePile.setSelected(true); nonLandPermanentsInOnePile.setLabel("Put non-land permanents in one pile"); @@ -470,8 +493,6 @@ public class PreferencesDialog extends javax.swing.JDialog { nonLandPermanentsInOnePileActionPerformed(evt); } }); - main_game.add(nonLandPermanentsInOnePile, java.awt.BorderLayout.PAGE_START); - nonLandPermanentsInOnePile.getAccessibleContext().setAccessibleName("nonLandPermanentsInOnePile"); showPlayerNamesPermanently.setSelected(true); showPlayerNamesPermanently.setText("Show player names on avatar permanently"); @@ -482,7 +503,6 @@ public class PreferencesDialog extends javax.swing.JDialog { showPlayerNamesPermanentlyActionPerformed(evt); } }); - main_game.add(showPlayerNamesPermanently, java.awt.BorderLayout.LINE_START); showAbilityPickerForced.setSelected(true); showAbilityPickerForced.setText("Show ability picker for abilities or spells without costs"); @@ -493,10 +513,49 @@ public class PreferencesDialog extends javax.swing.JDialog { showAbilityPickerForcedActionPerformed(evt); } }); - main_game.add(showAbilityPickerForced, java.awt.BorderLayout.PAGE_END); + + cbAllowRequestToShowHandCards.setSelected(true); + cbAllowRequestToShowHandCards.setText("Allow requests from players and spectators to show your hand cards"); + cbAllowRequestToShowHandCards.setToolTipText("This is the default setting used for your matches. If activated other players or spectators
\nof your match can send a request so you can allow them to see your hand cards."); + cbAllowRequestToShowHandCards.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + cbAllowRequestToShowHandCards.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cbAllowRequestToShowHandCardsActionPerformed(evt); + } + }); + + javax.swing.GroupLayout main_gameLayout = new javax.swing.GroupLayout(main_game); + main_game.setLayout(main_gameLayout); + main_gameLayout.setHorizontalGroup( + main_gameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(main_gameLayout.createSequentialGroup() + .addContainerGap() + .addGroup(main_gameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(main_gameLayout.createSequentialGroup() + .addComponent(cbAllowRequestToShowHandCards, javax.swing.GroupLayout.PREFERRED_SIZE, 546, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(main_gameLayout.createSequentialGroup() + .addGroup(main_gameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(showPlayerNamesPermanently, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(nonLandPermanentsInOnePile, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(showAbilityPickerForced, javax.swing.GroupLayout.Alignment.LEADING)) + .addGap(0, 0, Short.MAX_VALUE)))) + ); + main_gameLayout.setVerticalGroup( + main_gameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(main_gameLayout.createSequentialGroup() + .addComponent(nonLandPermanentsInOnePile) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(showPlayerNamesPermanently) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(showAbilityPickerForced) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbAllowRequestToShowHandCards)) + ); + + nonLandPermanentsInOnePile.getAccessibleContext().setAccessibleName("nonLandPermanentsInOnePile"); main_gamelog.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Game log")); - main_gamelog.setLayout(new java.awt.BorderLayout()); cbGameLogAutoSave.setSelected(true); cbGameLogAutoSave.setText("Auto save game logs (to \"../Mage.Client/gamelogs/\" directory)"); @@ -506,7 +565,20 @@ public class PreferencesDialog extends javax.swing.JDialog { cbGameLogAutoSaveActionPerformed(evt); } }); - main_gamelog.add(cbGameLogAutoSave, java.awt.BorderLayout.CENTER); + + javax.swing.GroupLayout main_gamelogLayout = new javax.swing.GroupLayout(main_gamelog); + main_gamelog.setLayout(main_gamelogLayout); + main_gamelogLayout.setHorizontalGroup( + main_gamelogLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(main_gamelogLayout.createSequentialGroup() + .addContainerGap() + .addComponent(cbGameLogAutoSave, javax.swing.GroupLayout.PREFERRED_SIZE, 528, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + main_gamelogLayout.setVerticalGroup( + main_gamelogLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(cbGameLogAutoSave, javax.swing.GroupLayout.Alignment.TRAILING) + ); javax.swing.GroupLayout tabMainLayout = new javax.swing.GroupLayout(tabMain); tabMain.setLayout(tabMainLayout); @@ -524,12 +596,12 @@ public class PreferencesDialog extends javax.swing.JDialog { tabMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(tabMainLayout.createSequentialGroup() .addContainerGap() - .addComponent(main_card, javax.swing.GroupLayout.PREFERRED_SIZE, 99, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(main_card, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(main_game, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(main_gamelog, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(145, Short.MAX_VALUE)) + .addContainerGap(120, Short.MAX_VALUE)) ); main_card.getAccessibleContext().setAccessibleName("Game panel"); @@ -1282,7 +1354,7 @@ public class PreferencesDialog extends javax.swing.JDialog { tabAvatars.setLayout(tabAvatarsLayout); tabAvatarsLayout.setHorizontalGroup( tabAvatarsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 582, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 598, Short.MAX_VALUE) ); tabAvatarsLayout.setVerticalGroup( tabAvatarsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1495,13 +1567,13 @@ public class PreferencesDialog extends javax.swing.JDialog { getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tabsPanel) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(saveButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(exitButton, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) + .addComponent(tabsPanel) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1527,6 +1599,7 @@ public class PreferencesDialog extends javax.swing.JDialog { save(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbGameLogAutoSave, KEY_GAME_LOG_AUTO_SAVE, "true", "false", UPDATE_CACHE_POLICY); // Phases @@ -1591,6 +1664,7 @@ public class PreferencesDialog extends javax.swing.JDialog { try { MageFrame.getSession().updatePreferencesForServer( getSelectedAvatar(), + dialog.cbAllowRequestToShowHandCards.isSelected(), dialog.showAbilityPickerForced.isSelected(), getUserSkipPrioritySteps()); @@ -1835,6 +1909,10 @@ public class PreferencesDialog extends javax.swing.JDialog { // TODO add your handling code here: }//GEN-LAST:event_cbEnableSkipButtonsSoundsActionPerformed + private void cbAllowRequestToShowHandCardsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbAllowRequestToShowHandCardsActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_cbAllowRequestToShowHandCardsActionPerformed + private void showProxySettings() { if (cbProxyType.getSelectedItem() == Connection.ProxyType.SOCKS) { this.pnlProxy.setVisible(true); @@ -1909,6 +1987,7 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true"); load(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true"); load(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true"); + load(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true"); load(prefs, dialog.cbGameLogAutoSave, KEY_GAME_LOG_AUTO_SAVE, "true"); load(prefs, dialog.checkBoxUpkeepYou, UPKEEP_YOU, "on","on"); @@ -2243,6 +2322,7 @@ public class PreferencesDialog extends javax.swing.JDialog { MageFrame.getSession().updatePreferencesForServer( id, PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_TOOLTIPS_ANY_ZONE, "true").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true").equals("true"), getUserSkipPrioritySteps()); } } @@ -2255,6 +2335,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JButton btnBrowseBackgroundImage; private javax.swing.JButton btnBrowseBattlefieldImage; private javax.swing.JButton btnBrowseImageLocation; + private javax.swing.JCheckBox cbAllowRequestToShowHandCards; private javax.swing.JCheckBox cbCheckForNewImages; private javax.swing.JCheckBox cbEnableBattlefieldBGM; private javax.swing.JCheckBox cbEnableDraftSounds; diff --git a/Mage.Client/src/main/java/mage/client/dialog/UserRequestDialog.form b/Mage.Client/src/main/java/mage/client/dialog/UserRequestDialog.form new file mode 100644 index 00000000000..2308caa7dd5 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/UserRequestDialog.form @@ -0,0 +1,91 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Mage.Client/src/main/java/mage/client/dialog/UserRequestDialog.java b/Mage.Client/src/main/java/mage/client/dialog/UserRequestDialog.java new file mode 100644 index 00000000000..2b859be4df2 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/UserRequestDialog.java @@ -0,0 +1,196 @@ +/* +* 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. +*/ + + +/* + * ErrorDialog.java + * + * Created on Dec 23, 2009, 11:01:32 AM + */ + +package mage.client.dialog; + +import mage.client.MageFrame; +import mage.constants.PlayerAction; +import mage.remote.Session; +import mage.view.UserRequestMessage; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class UserRequestDialog extends MageDialog { + + private UserRequestMessage userRequestMessage; + + /** Creates new form AskDialog */ + public UserRequestDialog() { + initComponents(); + } + + public void showDialog(UserRequestMessage userRequestMessage) { + this.userRequestMessage = userRequestMessage; + this.setTitle(userRequestMessage.getTitel()); + String text = "

" + userRequestMessage.getMessage() + "

"; + this.lblText.setText(text); + if (userRequestMessage.getButton1Text() != null) { + this.btn1.setText(userRequestMessage.getButton1Text()); + } else { + this.btn1.setVisible(false); + } + if (userRequestMessage.getButton2Text() != null) { + this.btn2.setText(userRequestMessage.getButton2Text()); + } else { + this.btn2.setVisible(false); + } + if (userRequestMessage.getButton3Text() != null) { + this.btn3.setText(userRequestMessage.getButton3Text()); + } else { + this.btn3.setVisible(false); + } + this.pack(); + this.revalidate(); + this.repaint(); + this.setModal(true); + 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") + // //GEN-BEGIN:initComponents + private void initComponents() { + + lblText = new javax.swing.JLabel(); + btn3 = new javax.swing.JButton(); + btn2 = new javax.swing.JButton(); + btn1 = new javax.swing.JButton(); + + setResizable(true); + setTitle("UserRequestMessage"); + + lblText.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + lblText.setText("message to the user"); + + btn3.setText("btn3"); + btn3.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btn3ActionPerformed(evt); + } + }); + + btn2.setText("btn2"); + btn2.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btn2ActionPerformed(evt); + } + }); + + btn1.setText("btn1"); + btn1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btn1ActionPerformed(evt); + } + }); + + 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() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(0, 289, Short.MAX_VALUE) + .addComponent(btn3, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btn2, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btn1, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(lblText, javax.swing.GroupLayout.DEFAULT_SIZE, 96, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btn1) + .addComponent(btn2) + .addComponent(btn3)) + .addGap(12, 12, 12)) + ); + + pack(); + }// //GEN-END:initComponents + + private void btn1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn1ActionPerformed + if (userRequestMessage.getButton1Action() != null) { + sendUserReplay(userRequestMessage.getButton1Action()); + } + this.removeDialog(); + }//GEN-LAST:event_btn1ActionPerformed + + private void btn2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn2ActionPerformed + if (userRequestMessage.getButton2Action() != null) { + sendUserReplay(userRequestMessage.getButton2Action()); + } + this.removeDialog(); + }//GEN-LAST:event_btn2ActionPerformed + + private void btn3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn3ActionPerformed + if (userRequestMessage.getButton3Action() != null) { + sendUserReplay(userRequestMessage.getButton3Action()); + } + this.removeDialog(); + }//GEN-LAST:event_btn3ActionPerformed + + private void sendUserReplay(PlayerAction playerAction) { + Session session = MageFrame.getSession(); + switch(playerAction) { + case ADD_PERMISSION_TO_SEE_HAND_CARDS: + session.sendPlayerAction(playerAction, userRequestMessage.getGameId(), userRequestMessage.getRelatedUserId()); + break; + default: + // not supported action + } + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btn1; + private javax.swing.JButton btn2; + private javax.swing.JButton btn3; + private javax.swing.JLabel lblText; + // End of variables declaration//GEN-END:variables + +} diff --git a/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java b/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java index e8372308bcc..03f6c96dff6 100644 --- a/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java @@ -299,7 +299,7 @@ public class FeedbackPanel extends javax.swing.JPanel { }//GEN-LAST:event_btnSpecialActionPerformed private void btnUndoActionPerformed(java.awt.event.ActionEvent evt) { - session.sendPlayerAction(PlayerAction.UNDO, gameId); + session.sendPlayerAction(PlayerAction.UNDO, gameId, null); } public void setHelperPanel(HelperPanel helper) { diff --git a/Mage.Client/src/main/java/mage/client/game/GamePanel.java b/Mage.Client/src/main/java/mage/client/game/GamePanel.java index e69f613cb9b..0d2786f5c9d 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java @@ -152,7 +152,7 @@ public final class GamePanel extends javax.swing.JPanel { private boolean initialized = false; private int lastUpdatedTurn; private boolean menuNameSet = false; - + private boolean handCardsOfOpponentAvailable = false; private Map loadedCards = new HashMap<>(); @@ -388,17 +388,18 @@ public final class GamePanel extends javax.swing.JPanel { this.feedbackPanel.init(gameId); this.feedbackPanel.clear(); + this.btnConcede.setVisible(false); this.btnStopWatching.setVisible(true); this.btnSwitchHands.setVisible(false); + this.chosenHandKey = ""; this.btnCancelSkip.setVisible(false); this.btnSkipToNextTurn.setVisible(false); this.btnSkipToEndTurn.setVisible(false); this.btnSkipToNextMain.setVisible(false); this.btnSkipStack.setVisible(false); - this.btnSkipToYourTurn.setVisible(false); - + this.btnSkipToYourTurn.setVisible(false); this.pnlReplay.setVisible(false); this.gameChatPanel.clear(); @@ -530,45 +531,59 @@ public final class GamePanel extends javax.swing.JPanel { } public synchronized void updateGame(GameView game, Map options) { - if (playerId == null || game.getHand() == null) { + if (playerId == null && game.getWatchedHands() == null) { this.handContainer.setVisible(false); } else { + this.handContainer.setVisible(true); handCards.clear(); - handCards.put(YOUR_HAND, game.getHand()); - - // Mark playable - if (game.getCanPlayInHand() != null) { - for (CardView card : handCards.get(YOUR_HAND).values()) { - if (game.getCanPlayInHand().contains(card.getId())) { - card.setPlayable(true); - } - } - } - - // Get opponents hand cards if available - if (game.getOpponentHands() != null) { - for (Map.Entry hand: game.getOpponentHands().entrySet()) { + if (game.getWatchedHands() != null) { + for (Map.Entry hand: game.getWatchedHands().entrySet()) { handCards.put(hand.getKey(), CardsViewUtil.convertSimple(hand.getValue(), loadedCards)); } } - - if (!handCards.containsKey(chosenHandKey)) { - chosenHandKey = YOUR_HAND; + if (playerId != null) { + handCards.put(YOUR_HAND, game.getHand()); + // Mark playable + if (game.getCanPlayInHand() != null) { + for (CardView card : handCards.get(YOUR_HAND).values()) { + if (game.getCanPlayInHand().contains(card.getId())) { + card.setPlayable(true); + } + } + } + // Get opponents hand cards if available (only possible for players) + if (game.getOpponentHands() != null) { + for (Map.Entry hand: game.getOpponentHands().entrySet()) { + handCards.put(hand.getKey(), CardsViewUtil.convertSimple(hand.getValue(), loadedCards)); + } + } + if (!handCards.containsKey(chosenHandKey)) { + chosenHandKey = YOUR_HAND; + } + } else if (chosenHandKey.isEmpty() && handCards.size() > 0) { + chosenHandKey = handCards.keySet().iterator().next(); + } + if (chosenHandKey != null && handCards.containsKey(chosenHandKey)) { + handContainer.loadCards(handCards.get(chosenHandKey), bigCard, gameId); } - handContainer.loadCards(handCards.get(chosenHandKey), bigCard, gameId); hideAll(); - // set visible only if we have any other hand visible than ours - boolean previous = btnSwitchHands.isVisible(); - boolean visible = handCards.size() > 1; - if (previous != visible) { - btnSwitchHands.setVisible(visible); - if (visible) { - JOptionPane.showMessageDialog(null, "You control other player's turn. \nUse \"Switch Hand\" button to switch between cards in different hands."); - } else { - JOptionPane.showMessageDialog(null, "You lost control on other player's turn."); + + if (playerId != null) { + // set visible only if we have any other hand visible than ours + btnSwitchHands.setVisible(handCards.size() > 1); + boolean change = (handCardsOfOpponentAvailable != (game.getOpponentHands() != null)); + if (change) { + handCardsOfOpponentAvailable = !handCardsOfOpponentAvailable; + if (handCardsOfOpponentAvailable) { + JOptionPane.showMessageDialog(null, "You control other player's turn. \nUse \"Switch Hand\" button to switch between cards in different hands."); + } else { + JOptionPane.showMessageDialog(null, "You lost control on other player's turn."); + } } + } else { + btnSwitchHands.setVisible(!handCards.isEmpty()); } } @@ -1280,7 +1295,7 @@ public final class GamePanel extends javax.swing.JPanel { btnStopWatching.setBorder(new EmptyBorder(0,0,0,0)); btnStopWatching.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getStopWatchButtonImage())); btnStopWatching.setFocusable(false); - btnSwitchHands.setToolTipText("Stop watching this game."); + btnStopWatching.setToolTipText("Stop watching this game."); btnStopWatching.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent evt) { @@ -1620,42 +1635,42 @@ public final class GamePanel extends javax.swing.JPanel { private void btnConcedeActionPerformed(java.awt.event.ActionEvent evt) { if (modalQuestion("Are you sure you want to concede?", "Confirm concede") == JOptionPane.YES_OPTION) { - session.sendPlayerAction(PlayerAction.CONCEDE, gameId); + session.sendPlayerAction(PlayerAction.CONCEDE, gameId, null); } } private void btnEndTurnActionPerformed(java.awt.event.ActionEvent evt) { - session.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN, gameId); + session.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN, gameId, null); AudioManager.playOnSkipButton(); updateSkipButtons(true, false, false, false, false); } private void btnUntilEndOfTurnActionPerformed(java.awt.event.ActionEvent evt) { - session.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_TURN_END_STEP, gameId); + session.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_TURN_END_STEP, gameId, null); AudioManager.playOnSkipButton(); updateSkipButtons(false, true, false, false, false); } private void btnUntilNextMainPhaseActionPerformed(java.awt.event.ActionEvent evt) { - session.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE, gameId); + session.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE, gameId, null); AudioManager.playOnSkipButton(); updateSkipButtons(false, false, true, false, false); } private void btnPassPriorityUntilNextYourTurnActionPerformed(java.awt.event.ActionEvent evt) { - session.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN, gameId); + session.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN, gameId, null); AudioManager.playOnSkipButton(); updateSkipButtons(false, false, false, true, false); } private void btnPassPriorityUntilStackResolvedActionPerformed(java.awt.event.ActionEvent evt) { - session.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_STACK_RESOLVED, gameId); + session.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_STACK_RESOLVED, gameId, null); AudioManager.playOnSkipButton(); updateSkipButtons(false, false, false, false, true); } private void restorePriorityActionPerformed(java.awt.event.ActionEvent evt) { - session.sendPlayerAction(PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS, gameId); + session.sendPlayerAction(PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS, gameId, null); AudioManager.playOnSkipButtonCancel(); updateSkipButtons(false, false, false, false, false); } diff --git a/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java b/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java index 3288a5dd0da..775ef573023 100644 --- a/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java @@ -64,7 +64,8 @@ public class PlayAreaPanel extends javax.swing.JPanel { private UUID gameId; private boolean smallMode = false; private boolean playingMode = true; - private GamePanel gamePanel; + private final GamePanel gamePanel; + private final boolean playerItself; private JCheckBoxMenuItem manaPoolMenuItem; @@ -72,23 +73,27 @@ public class PlayAreaPanel extends javax.swing.JPanel { public static final int PANEL_HEIGHT_SMALL = 190; /** Creates new form PlayAreaPanel - * @param isPlayer */ - public PlayAreaPanel(boolean isPlayer) { + * @param player + * @param bigCard + * @param gameId + * @param isPlayer true if the client is a player / false if the client is a watcher + * @param playerItself true if it's the area of the player itself + * @param priorityTime + * @param gamePanel */ + public PlayAreaPanel(PlayerView player, BigCard bigCard, UUID gameId, boolean playerItself, int priorityTime, boolean isPlayer, GamePanel gamePanel) { + //this(isPlayer); + this.playerItself = playerItself; initComponents(); setOpaque(false); battlefieldPanel.setOpaque(false); - + popupMenu = new JPopupMenu(); if (isPlayer) { - addPopupMenuPlayer(); + addPopupMenuPlayer(player.getUserData().allowRequestShowHandCards()); } else { addPopupMenuWatcher(); } this.add(popupMenu); - } - - public PlayAreaPanel(PlayerView player, BigCard bigCard, UUID gameId, boolean me, int priorityTime, boolean isPlayer, GamePanel gamePanel) { - this(isPlayer); this.gamePanel = gamePanel; init(player, bigCard, gameId, priorityTime); update(player); @@ -125,7 +130,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { } - private void addPopupMenuPlayer() { + private void addPopupMenuPlayer(boolean allowRequestToShowHandCards) { JMenuItem menuItem; @@ -150,7 +155,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS, gameId); + gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS, gameId, null); } }); @@ -163,7 +168,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN, gameId); + gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN, gameId, null); } }); @@ -174,7 +179,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_TURN_END_STEP, gameId); + gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_TURN_END_STEP, gameId, null); } }); @@ -185,7 +190,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE, gameId); + gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE, gameId, null); } }); menuItem = new JMenuItem("F9 - Skip everything until own next turn (stop on attack/block)"); @@ -195,7 +200,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN, gameId); + gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN, gameId, null); } }); @@ -212,7 +217,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { public void actionPerformed(ActionEvent e) { boolean manaPoolAutomatic = ((JCheckBoxMenuItem)e.getSource()).getState(); gamePanel.setMenuStates(manaPoolAutomatic); - gamePanel.getSession().sendPlayerAction(manaPoolAutomatic ? PlayerAction.MANA_AUTO_PAYMENT_ON: PlayerAction.MANA_AUTO_PAYMENT_OFF, gameId); + gamePanel.getSession().sendPlayerAction(manaPoolAutomatic ? PlayerAction.MANA_AUTO_PAYMENT_ON: PlayerAction.MANA_AUTO_PAYMENT_OFF, gameId, null); } }); @@ -225,12 +230,53 @@ public class PlayAreaPanel extends javax.swing.JPanel { menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - gamePanel.getSession().sendPlayerAction(PlayerAction.RESET_AUTO_SELECT_REPLACEMENT_EFFECTS, gameId); + gamePanel.getSession().sendPlayerAction(PlayerAction.RESET_AUTO_SELECT_REPLACEMENT_EFFECTS, gameId, null); } }); popupMenu.addSeparator(); + if (!playerItself) { + menuItem = new JMenuItem("Request permission to see hand cards"); + popupMenu.add(menuItem); + + // Request to see hand cards + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gamePanel.getSession().sendPlayerAction(PlayerAction.REQUEST_PERMISSION_TO_SEE_HAND_CARDS, gameId, playerId); + } + }); + } else { + menuItem = new JCheckBoxMenuItem("Allow requests to show your hand cards", allowRequestToShowHandCards); + menuItem.setMnemonic(KeyEvent.VK_A); + menuItem.setToolTipText("If activated watchers or other players can request to see your hand cards. If you grant this to a user, it's valid for the complete match."); + popupMenu.add(menuItem); + + // Requests allowed + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + boolean requestsAllowed = ((JCheckBoxMenuItem)e.getSource()).getState(); + gamePanel.getSession().sendPlayerAction(requestsAllowed ? PlayerAction.PERMISSION_REQUESTS_ALLOWED_ON: PlayerAction.PERMISSION_REQUESTS_ALLOWED_OFF, gameId, null); + } + }); + + menuItem = new JMenuItem("Revoke all permission(s) to see your hand cards"); + menuItem.setMnemonic(KeyEvent.VK_P); + menuItem.setToolTipText("Revoke already granted permission for all spectators to see your hand cards."); + popupMenu.add(menuItem); + + // revoke permissions to see hand cards + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gamePanel.getSession().sendPlayerAction(PlayerAction.REVOKE_PERMISSIONS_TO_SEE_HAND_CARDS, gameId, null); + } + }); + } + popupMenu.addSeparator(); + menuItem = new JMenuItem("Concede game"); popupMenu.add(menuItem); @@ -239,7 +285,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { @Override public void actionPerformed(ActionEvent e) { if (JOptionPane.showConfirmDialog(PlayAreaPanel.this, "Are you sure you want to concede the game?", "Confirm concede game", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - MageFrame.getSession().sendPlayerAction(PlayerAction.CONCEDE, gameId); + MageFrame.getSession().sendPlayerAction(PlayerAction.CONCEDE, gameId, null); } } }); @@ -297,6 +343,18 @@ public class PlayAreaPanel extends javax.swing.JPanel { } } }); + + menuItem = new JMenuItem("Request permission to see hand cards"); + popupMenu.add(menuItem); + + // Request to see hand cards + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gamePanel.getSession().sendPlayerAction(PlayerAction.REQUEST_PERMISSION_TO_SEE_HAND_CARDS, gameId, playerId); + } + }); + battlefieldPanel.getMainPanel().addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent Me) { diff --git a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java index 1ebde4bdb96..519010f36ca 100644 --- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java +++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java @@ -32,7 +32,6 @@ import java.util.UUID; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import mage.cards.decks.Deck; -import mage.choices.Choice; import mage.client.MageFrame; import mage.client.chat.ChatPanel; import static mage.client.chat.ChatPanel.ChatType.TABLES; @@ -62,6 +61,7 @@ import mage.view.GameClientMessage; import mage.view.GameEndView; import mage.view.GameView; import mage.view.TableClientMessage; +import mage.view.UserRequestMessage; import org.apache.log4j.Logger; /** @@ -252,7 +252,8 @@ public class CallbackClientImpl implements CallbackClient { if (panel != null) { panel.getChoice(message.getChoice(), callback.getObjectId()); - } break; + } + break; } case "gamePlayMana": { @@ -260,7 +261,8 @@ public class CallbackClientImpl implements CallbackClient { GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { panel.playMana(message.getMessage(), message.getGameView(), callback.getMessageId()); - } break; + } + break; } case "gamePlayXMana": { @@ -268,7 +270,8 @@ public class CallbackClientImpl implements CallbackClient { GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { panel.playXMana(message.getMessage(), message.getGameView(), callback.getMessageId()); - } break; + } + break; } case "gameSelectAmount": { @@ -346,7 +349,8 @@ public class CallbackClientImpl implements CallbackClient { DraftPanel panel = MageFrame.getDraft(callback.getObjectId()); if (panel != null) { panel.loadBooster(message.getDraftPickView()); - } break; + } + break; } case "draftUpdate": { @@ -364,17 +368,21 @@ public class CallbackClientImpl implements CallbackClient { // } else { // logger.warn("message out of sequence - ignoring"); // } -// break; + break; case "draftInit": { DraftClientMessage message = (DraftClientMessage) callback.getData(); DraftPanel panel = MageFrame.getDraft(callback.getObjectId()); if (panel != null) { panel.loadBooster(message.getDraftPickView()); - } break; + } + break; } case "tournamentInit": break; + case "userRequestDialog": + frame.showUserRequestDialog((UserRequestMessage) callback.getData()); + break; } messageId = callback.getMessageId(); } catch (Exception ex) { diff --git a/Mage.Common/src/mage/interfaces/MageServer.java b/Mage.Common/src/mage/interfaces/MageServer.java index 52188eb8a97..fd86ee26645 100644 --- a/Mage.Common/src/mage/interfaces/MageServer.java +++ b/Mage.Common/src/mage/interfaces/MageServer.java @@ -120,7 +120,7 @@ public interface MageServer { void quitMatch(UUID gameId, String sessionId) throws MageException; GameView getGameView(UUID gameId, String sessionId, UUID playerId) throws MageException; // priority, undo, concede, mana pool - void sendPlayerAction(PlayerAction playerAction, UUID gameId, String sessionId) throws MageException; + void sendPlayerAction(PlayerAction playerAction, UUID gameId, String sessionId, Object data) throws MageException; //tournament methods boolean startTournament(String sessionId, UUID roomId, UUID tableId) throws MageException; diff --git a/Mage.Common/src/mage/remote/Connection.java b/Mage.Common/src/mage/remote/Connection.java index 1ed71907f0c..0c7e03e18c9 100644 --- a/Mage.Common/src/mage/remote/Connection.java +++ b/Mage.Common/src/mage/remote/Connection.java @@ -54,6 +54,7 @@ public class Connection { private int avatarId; private boolean showAbilityPickerForced; + private boolean allowRequestShowHandCards; private UserSkipPrioritySteps userSkipPrioritySteps; private static final String serialization = "?serializationtype=jboss"; @@ -231,6 +232,13 @@ public class Connection { this.showAbilityPickerForced = showAbilityPickerForced; } + public boolean allowRequestShowHandCards() { + return allowRequestShowHandCards; + } + + public void setAllowRequestShowHandCards(boolean allowRequestShowHandCards) { + this.allowRequestShowHandCards = allowRequestShowHandCards; + } public UserSkipPrioritySteps getUserSkipPrioritySteps() { return userSkipPrioritySteps; } diff --git a/Mage.Common/src/mage/remote/SessionImpl.java b/Mage.Common/src/mage/remote/SessionImpl.java index c424c62df91..7405c8ee594 100644 --- a/Mage.Common/src/mage/remote/SessionImpl.java +++ b/Mage.Common/src/mage/remote/SessionImpl.java @@ -273,6 +273,7 @@ public class SessionImpl implements Session { if (connection.getPassword() == null) { UserDataView userDataView = new UserDataView(connection.getAvatarId(), connection.isShowAbilityPickerForced(), + connection.allowRequestShowHandCards(), connection.getUserSkipPrioritySteps()); // for backward compatibility. don't remove twice call - first one does nothing but for version checking registerResult = server.registerClient(connection.getUsername(), sessionId, client.getVersion()); @@ -1151,10 +1152,10 @@ public class SessionImpl implements Session { } @Override - public boolean sendPlayerAction(PlayerAction passPriorityAction, UUID gameId) { + public boolean sendPlayerAction(PlayerAction passPriorityAction, UUID gameId, Object data) { try { if (isConnected()) { - server.sendPlayerAction(passPriorityAction, gameId, sessionId); + server.sendPlayerAction(passPriorityAction, gameId, sessionId, data); return true; } } catch (MageException ex) { @@ -1355,10 +1356,10 @@ public class SessionImpl implements Session { } @Override - public boolean updatePreferencesForServer(int avatarId, boolean showAbilityPickerForced, UserSkipPrioritySteps userSkipPrioritySteps) { + public boolean updatePreferencesForServer(int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards, UserSkipPrioritySteps userSkipPrioritySteps) { try { if (isConnected()) { - UserDataView userDataView = new UserDataView(avatarId, showAbilityPickerForced, userSkipPrioritySteps); + UserDataView userDataView = new UserDataView(avatarId, showAbilityPickerForced, allowRequestShowHandCards, userSkipPrioritySteps); server.setUserData(connection.getUsername(), sessionId, userDataView); } return true; diff --git a/Mage.Common/src/mage/remote/interfaces/ClientData.java b/Mage.Common/src/mage/remote/interfaces/ClientData.java index 4ab81aaa3b7..e2cc74ff1ff 100644 --- a/Mage.Common/src/mage/remote/interfaces/ClientData.java +++ b/Mage.Common/src/mage/remote/interfaces/ClientData.java @@ -36,5 +36,5 @@ public interface ClientData { String getUserName(); - boolean updatePreferencesForServer(int avatarId, boolean showAbilityPickerForced, UserSkipPrioritySteps userSkipPrioritySteps); + boolean updatePreferencesForServer(int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards, UserSkipPrioritySteps userSkipPrioritySteps); } diff --git a/Mage.Common/src/mage/remote/interfaces/GamePlay.java b/Mage.Common/src/mage/remote/interfaces/GamePlay.java index 15134d550c9..d99f17011cb 100644 --- a/Mage.Common/src/mage/remote/interfaces/GamePlay.java +++ b/Mage.Common/src/mage/remote/interfaces/GamePlay.java @@ -80,6 +80,6 @@ public interface GamePlay { * @param gameId * @return */ - boolean sendPlayerAction(PlayerAction passPriorityAction, UUID gameId); + boolean sendPlayerAction(PlayerAction passPriorityAction, UUID gameId, Object Data); } diff --git a/Mage.Common/src/mage/view/GameEndView.java b/Mage.Common/src/mage/view/GameEndView.java index d86219e32dc..5f700d9dc68 100644 --- a/Mage.Common/src/mage/view/GameEndView.java +++ b/Mage.Common/src/mage/view/GameEndView.java @@ -66,7 +66,7 @@ public class GameEndView implements Serializable { int winner = 0; Player you = null; for (Player player: state.getPlayers().values()) { - PlayerView playerView = new PlayerView(player, state, game, playerId); + PlayerView playerView = new PlayerView(player, state, game, playerId, null); if (playerView.getPlayerId().equals(playerId)) { clientPlayer = playerView; you = player; diff --git a/Mage.Common/src/mage/view/GameView.java b/Mage.Common/src/mage/view/GameView.java index b2a84374b65..39f62f4299f 100644 --- a/Mage.Common/src/mage/view/GameView.java +++ b/Mage.Common/src/mage/view/GameView.java @@ -65,6 +65,7 @@ public class GameView implements Serializable { private CardsView hand; private Set canPlayInHand; private Map opponentHands; + private Map watchedHands; private final CardsView stack = new CardsView(); private final List exiles = new ArrayList<>(); private final List revealed = new ArrayList<>(); @@ -80,11 +81,11 @@ public class GameView implements Serializable { private final boolean isPlayer; - public GameView(GameState state, Game game, UUID createdForPlayerId) { + public GameView(GameState state, Game game, UUID createdForPlayerId, UUID watcherUserId) { this.isPlayer = createdForPlayerId != null; this.priorityTime = game.getPriorityTime(); for (Player player: state.getPlayers().values()) { - players.add(new PlayerView(player, state, game, createdForPlayerId)); + players.add(new PlayerView(player, state, game, createdForPlayerId, watcherUserId)); } for (StackObject stackObject: state.getStack()) { if (stackObject instanceof StackAbility) { @@ -222,6 +223,14 @@ public class GameView implements Serializable { this.opponentHands = opponentHands; } + public Map getWatchedHands() { + return watchedHands; + } + + public void setWatchedHands(Map watchedHands) { + this.watchedHands = watchedHands; + } + public TurnPhase getPhase() { return phase; } diff --git a/Mage.Common/src/mage/view/PlayerView.java b/Mage.Common/src/mage/view/PlayerView.java index e98091a010a..675c9d8a360 100644 --- a/Mage.Common/src/mage/view/PlayerView.java +++ b/Mage.Common/src/mage/view/PlayerView.java @@ -28,6 +28,12 @@ package mage.view; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; import mage.cards.Card; import mage.counters.CounterType; import mage.game.ExileZone; @@ -39,9 +45,6 @@ import mage.game.command.Emblem; import mage.game.permanent.Permanent; import mage.players.Player; -import java.io.Serializable; -import java.util.*; - /** * * @author BetaSteward_at_googlemail.com @@ -74,7 +77,7 @@ public class PlayerView implements Serializable { private final boolean passedUntilStackResolved; // F8 private final boolean passedAllTurns; // F9 - public PlayerView(Player player, GameState state, Game game, UUID createdForPlayerId) { + public PlayerView(Player player, GameState state, Game game, UUID createdForPlayerId, UUID watcherUserId) { this.playerId = player.getId(); this.name = player.getName(); this.life = player.getLife(); @@ -106,7 +109,7 @@ public class PlayerView implements Serializable { if (player.getUserData() != null) { this.userDataView = new UserDataView(player.getUserData()); } else { - this.userDataView = new UserDataView(0, false, null); + this.userDataView = new UserDataView(0, false, false, null); } for (CommandObject commandObject : game.getState().getCommand()) { diff --git a/Mage.Common/src/mage/view/UserDataView.java b/Mage.Common/src/mage/view/UserDataView.java index a76120b0080..b9ebc4f5b02 100644 --- a/Mage.Common/src/mage/view/UserDataView.java +++ b/Mage.Common/src/mage/view/UserDataView.java @@ -1,8 +1,7 @@ package mage.view; -import mage.players.net.UserData; - import java.io.Serializable; +import mage.players.net.UserData; import mage.players.net.UserSkipPrioritySteps; /** @@ -15,11 +14,13 @@ public class UserDataView implements Serializable { protected int avatarId; protected int userGroup; protected boolean showAbilityPickerForced; + protected boolean allowRequestShowHandCards; protected UserSkipPrioritySteps userSkipPrioritySteps; - public UserDataView(int avatarId, boolean showAbilityPickerForced, UserSkipPrioritySteps userSkipPrioritySteps) { + public UserDataView(int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards, UserSkipPrioritySteps userSkipPrioritySteps) { this.avatarId = avatarId; this.showAbilityPickerForced = showAbilityPickerForced; + this.allowRequestShowHandCards = allowRequestShowHandCards; this.userSkipPrioritySteps = userSkipPrioritySteps; } @@ -36,6 +37,10 @@ public class UserDataView implements Serializable { return showAbilityPickerForced; } + public boolean allowRequestShowHandCards() { + return allowRequestShowHandCards; + } + public UserSkipPrioritySteps getUserSkipPrioritySteps() { return userSkipPrioritySteps; } diff --git a/Mage.Common/src/mage/view/UserRequestMessage.java b/Mage.Common/src/mage/view/UserRequestMessage.java new file mode 100644 index 00000000000..a72a55987f4 --- /dev/null +++ b/Mage.Common/src/mage/view/UserRequestMessage.java @@ -0,0 +1,152 @@ +/* + * 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 java.util.UUID; +import mage.constants.PlayerAction; + +/** + * + * @author LevelX2 + */ + +public class UserRequestMessage implements Serializable { + private static final long serialVersionUID = 1L; + + private final String titel; + private final String message; + private final PlayerAction requestAction; + private UUID relatedUserId; + private String relatedUserName; + private UUID matchId; + private UUID gameId; + + private String button1Text; + private PlayerAction button1Action; + + private String button2Text; + private PlayerAction button2Action; + + private String button3Text; + private PlayerAction button3Action; + + + public UserRequestMessage(String titel, String message, PlayerAction requestAction) { + this.titel = titel; + this.message = message; + this.requestAction = requestAction; + this.button1Action = null; + this.button2Action = null; + this.button3Action = null; + } + + public void setMatchId(UUID matchId) { + this.matchId = matchId; + } + + public void setGameId(UUID gameId) { + this.gameId = gameId; + } + + public void setRelatedUser(UUID userId, String name) { + this.relatedUserId = userId; + this.relatedUserName = name; + } + + public void setButton1(String text, PlayerAction buttonAction) { + this.button1Text = text; + this.button1Action = buttonAction; + } + + public void setButton2(String text, PlayerAction buttonAction) { + this.button2Text = text; + this.button2Action = buttonAction; + } + public void setButton3(String text, PlayerAction buttonAction) { + this.button3Text = text; + this.button3Action = buttonAction; + } + + public String getTitel() { + return titel; + } + + public static long getSerialVersionUID() { + return serialVersionUID; + } + + public String getMessage() { + return message; + } + + public PlayerAction getRequestAction() { + return requestAction; + } + + public UUID getRelatedUserId() { + return relatedUserId; + } + + public String getRelatedUserName() { + return relatedUserName; + } + + public UUID getMatchId() { + return matchId; + } + + public UUID getGameId() { + return gameId; + } + + public String getButton1Text() { + return button1Text; + } + + public PlayerAction getButton1Action() { + return button1Action; + } + + public String getButton2Text() { + return button2Text; + } + + public PlayerAction getButton2Action() { + return button2Action; + } + + public String getButton3Text() { + return button3Text; + } + + public PlayerAction getButton3Action() { + return button3Action; + } + +} diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 6aa56c9bb65..0687612cff9 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -96,7 +96,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { public ComputerPlayer(String name, RangeOfInfluence range) { super(name, range); human = false; - userData = new UserData(UserGroup.COMPUTER, 64, false, null); + userData = new UserData(UserGroup.COMPUTER, 64, false, true, null); pickedCards = new ArrayList<>(); } diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 25d06db3cbf..90efd5641bf 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -749,8 +749,8 @@ public class MageServerImpl implements MageServer { } @Override - public void sendPlayerAction(final PlayerAction playerAction, final UUID gameId, final String sessionId) throws MageException { - execute("setdPlayerAction", sessionId, new Action() { + public void sendPlayerAction(final PlayerAction playerAction, final UUID gameId, final String sessionId, final Object data) throws MageException { + execute("sendPlayerAction", sessionId, new Action() { @Override public void execute() { Session session = SessionManager.getInstance().getSession(sessionId); @@ -758,7 +758,7 @@ public class MageServerImpl implements MageServer { logger.error("Session not found sessionId: "+ sessionId + " gameId:" + gameId); return; } - GameManager.getInstance().sendPlayerAction(playerAction, gameId, session.getUserId()); + GameManager.getInstance().sendPlayerAction(playerAction, gameId, session.getUserId(), data); } }); } diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java index 224cbe83f23..06f7e4ab740 100644 --- a/Mage.Server/src/main/java/mage/server/Session.java +++ b/Mage.Server/src/main/java/mage/server/Session.java @@ -139,7 +139,7 @@ public class Session { if (user == null) { user = UserManager.getInstance().findUser("Admin"); } - user.setUserData(new UserData(UserGroup.ADMIN, 0, false, null)); + user.setUserData(new UserData(UserGroup.ADMIN, 0, false, false, null)); if (!UserManager.getInstance().connectToSession(sessionId, user.getId())) { logger.info("Error connecting Admin!"); } @@ -151,7 +151,7 @@ public class Session { if (user != null) { UserData userData = user.getUserData(); if (userData == null) { - userData = new UserData(UserGroup.PLAYER, userDataView.getAvatarId(), userDataView.isShowAbilityPickerForced(), userDataView.getUserSkipPrioritySteps()); + userData = new UserData(UserGroup.PLAYER, userDataView.getAvatarId(), userDataView.isShowAbilityPickerForced(), userDataView.allowRequestShowHandCards(), userDataView.getUserSkipPrioritySteps()); user.setUserData(userData); } else { if (userDataView.getAvatarId() == 51) { // Update special avatar if first avatar is selected @@ -159,6 +159,7 @@ public class Session { } userData.setAvatarId(userDataView.getAvatarId()); userData.setShowAbilityPickerForced(userDataView.isShowAbilityPickerForced()); + userData.setAllowRequestShowHandCards(userDataView.allowRequestShowHandCards()); userData.setUserSkipPrioritySteps(userDataView.getUserSkipPrioritySteps()); } return true; diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 0a66445ce3f..aedf42cf6c7 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -585,7 +585,9 @@ public class TableController { user.removeConstructing(match.getPlayer(entry.getValue()).getPlayer().getId()); GameManager.getInstance().joinGame(match.getGame().getId(), user.getId()); logger.debug("Joined currently not connected user " + user.getName() + " matchId: " + match.getId()); - } + } + Player player = match.getPlayer(entry.getValue()).getPlayer(); + player.setRequestToShowHandCardsAllowed(user.getUserData().allowRequestShowHandCards()); user.gameStarted(match.getGame().getId(), entry.getValue()); if (creator == null) { diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index 4e97440c605..6ceb7164ddc 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -28,6 +28,24 @@ package mage.server.game; +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.zip.GZIPOutputStream; import mage.MageException; import mage.abilities.Ability; import mage.cards.Card; @@ -36,7 +54,9 @@ import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; +import mage.choices.Choice; import mage.constants.ManaType; +import mage.constants.PlayerAction; import mage.constants.Zone; import mage.game.Game; import mage.game.GameException; @@ -47,27 +67,25 @@ import mage.game.events.TableEvent; import mage.game.permanent.Permanent; import mage.interfaces.Action; import mage.players.Player; -import mage.server.*; +import mage.server.ChatManager; +import mage.server.Main; +import mage.server.TableManager; +import mage.server.User; +import mage.server.UserManager; import mage.server.util.ConfigSettings; import mage.server.util.Splitter; import mage.server.util.SystemUtil; import mage.server.util.ThreadExecutor; import mage.utils.timer.PriorityTimer; -import mage.view.*; +import mage.view.AbilityPickerView; +import mage.view.CardsView; +import mage.view.ChatMessage; import mage.view.ChatMessage.MessageColor; import mage.view.ChatMessage.MessageType; +import mage.view.GameView; +import mage.view.PermanentView; import org.apache.log4j.Logger; -import java.io.*; -import java.util.*; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.zip.GZIPOutputStream; -import mage.choices.Choice; -import mage.constants.PlayerAction; - /** * * @author BetaSteward_at_googlemail.com @@ -389,7 +407,7 @@ public class GameController implements GameCallback { } } - public void sendPlayerAction(PlayerAction playerAction, UUID userId) { + public void sendPlayerAction(PlayerAction playerAction, UUID userId, Object data) { switch(playerAction) { case UNDO: game.undo(getPlayerId(userId)); @@ -403,11 +421,71 @@ public class GameController implements GameCallback { case MANA_AUTO_PAYMENT_ON: game.setManaPoolMode(getPlayerId(userId), true); break; + case ADD_PERMISSION_TO_SEE_HAND_CARDS: + if (data instanceof UUID) { + UUID playerId = getPlayerId(userId); + if (playerId != null) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.addPermissionToShowHandCards((UUID) data); + } + } + } + break; + case REVOKE_PERMISSIONS_TO_SEE_HAND_CARDS: + UUID playerId = getPlayerId(userId); + if (playerId != null) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.revokePermissionToSeeHandCards(); + } + } + break; + case REQUEST_PERMISSION_TO_SEE_HAND_CARDS: + if (data instanceof UUID) { + requestPermissionToSeeHandCards(userId, (UUID) data); + } + break; default: game.sendPlayerAction(playerAction, getPlayerId(userId)); } } - + + private void requestPermissionToSeeHandCards(UUID userIdRequester, UUID userIdGranter) { + Player grantingPlayer = game.getPlayer(userIdGranter); + if (grantingPlayer != null) { + if (!grantingPlayer.getUsersAllowedToSeeHandCards().contains(userIdRequester)) { + if (grantingPlayer.isHuman()) { + GameSession gameSession = gameSessions.get(userIdGranter); + if (gameSession != null) { + UUID requestingPlayer = getPlayerId(userIdRequester); + if (requestingPlayer == null || !requestingPlayer.equals(grantingPlayer.getId())) { // don't allow request for your own cards + if (grantingPlayer.isRequestToShowHandCardsAllowed()) { + gameSession.requestPermissionToSeeHandCards(userIdRequester); + } else { + // player does not allow the request + User requester = UserManager.getInstance().getUser(userIdRequester); + if (requester != null) { + requester.showUserMessage("Request to show hand cards", "Player " + grantingPlayer.getName() + " does not allow to request to show hand cards!"); + } + } + } + } + } else { + // Non Human players always allow to see the hand cards + grantingPlayer.addPermissionToShowHandCards(userIdRequester); + } + } else { + // user can already see the cards + User requester = UserManager.getInstance().getUser(userIdRequester); + if (requester != null) { + requester.showUserMessage("Request to show hand cards", "You can see already the hand cards of player " + grantingPlayer.getName() + "!"); + } + } + + } + + } public void cheat(UUID userId, UUID playerId, DeckCardLists deckList) { Deck deck; diff --git a/Mage.Server/src/main/java/mage/server/game/GameManager.java b/Mage.Server/src/main/java/mage/server/game/GameManager.java index fd3acc8e08a..2b2a06807f2 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameManager.java +++ b/Mage.Server/src/main/java/mage/server/game/GameManager.java @@ -114,10 +114,10 @@ public class GameManager { } } - public void sendPlayerAction(PlayerAction playerAction, UUID gameId, UUID userId) { + public void sendPlayerAction(PlayerAction playerAction, UUID gameId, UUID userId, Object data) { GameController gameController = gameControllers.get(gameId); if (gameController != null) { - gameController.sendPlayerAction(playerAction, userId); + gameController.sendPlayerAction(playerAction, userId, data); } } diff --git a/Mage.Server/src/main/java/mage/server/game/GameSession.java b/Mage.Server/src/main/java/mage/server/game/GameSession.java index 39618564330..4ad4e26a202 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameSession.java +++ b/Mage.Server/src/main/java/mage/server/game/GameSession.java @@ -28,9 +28,24 @@ package mage.server.game; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import mage.cards.Cards; +import mage.choices.Choice; import mage.constants.ManaType; +import mage.constants.PlayerAction; import mage.game.Game; +import mage.game.Table; import mage.interfaces.callback.ClientCallback; import mage.players.Player; import mage.players.net.UserData; @@ -38,19 +53,15 @@ import mage.server.User; import mage.server.UserManager; import mage.server.util.ConfigSettings; import mage.server.util.ThreadExecutor; -import mage.view.*; +import mage.view.AbilityPickerView; +import mage.view.CardsView; +import mage.view.GameClientMessage; +import mage.view.GameView; +import mage.view.LookedAtView; +import mage.view.SimpleCardsView; +import mage.view.UserRequestMessage; import org.apache.log4j.Logger; -import java.io.Serializable; -import java.util.*; -import java.util.Map.Entry; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import mage.choices.Choice; -import mage.game.Table; - /** * * @author BetaSteward_at_googlemail.com @@ -173,6 +184,25 @@ public class GameSession extends GameWatcher { } } + public void requestPermissionToSeeHandCards(UUID watcherId) { + if (!killed) { + User watcher = UserManager.getInstance().getUser(watcherId); + User user = UserManager.getInstance().getUser(userId); + if (user != null && watcher != null) { + UserRequestMessage userRequestMessage = new UserRequestMessage( + "User request", + "Allow user " + watcher.getName() + " for this match to see your hand cards?
" + + "(You can revoke this every time using related popup menu item of your battlefield.)" + , PlayerAction.REQUEST_PERMISSION_TO_SEE_HAND_CARDS); + userRequestMessage.setRelatedUser(watcherId, watcher.getName()); + userRequestMessage.setGameId(game.getId()); + userRequestMessage.setButton1("Accept", PlayerAction.ADD_PERMISSION_TO_SEE_HAND_CARDS); + userRequestMessage.setButton2("Reject", null); + user.fireCallback(new ClientCallback("userRequestDialog", game.getId(), userRequestMessage)); + } + } + } + /** * Reset the timeout counter after priority in game changed * @@ -237,12 +267,12 @@ public class GameSession extends GameWatcher { public GameView getGameView() { Player player = game.getPlayer(playerId); player.setUserData(this.userData); - GameView gameView = new GameView(game.getState(), game, playerId); + GameView gameView = new GameView(game.getState(), game, playerId, null); gameView.setHand(new CardsView(player.getHand().getCards(game))); gameView.setCanPlayInHand(player.getPlayableInHand(game)); processControlledPlayers(player, gameView); - + processWatchedHands(userId, gameView); //TODO: should player who controls another player's turn be able to look at all these cards? List list = new ArrayList<>(); diff --git a/Mage.Server/src/main/java/mage/server/game/GameWatcher.java b/Mage.Server/src/main/java/mage/server/game/GameWatcher.java index 67d0ce07958..177a81e2ee3 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameWatcher.java +++ b/Mage.Server/src/main/java/mage/server/game/GameWatcher.java @@ -28,15 +28,19 @@ package mage.server.game; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; import mage.game.Game; import mage.game.Table; import mage.interfaces.callback.ClientCallback; +import mage.players.Player; import mage.server.User; import mage.server.UserManager; import mage.view.GameClientMessage; import mage.view.GameEndView; import mage.view.GameView; +import mage.view.SimpleCardsView; import org.apache.log4j.Logger; /** @@ -71,10 +75,10 @@ public class GameWatcher { public void update() { if (!killed) { - User user = UserManager.getInstance().getUser(userId); - if (user != null) { - user.fireCallback(new ClientCallback("gameUpdate", game.getId(), getGameView())); - } + User user = UserManager.getInstance().getUser(userId); + if (user != null) { + user.fireCallback(new ClientCallback("gameUpdate", game.getId(), getGameView())); + } } } @@ -120,9 +124,21 @@ public class GameWatcher { } public GameView getGameView() { - return new GameView(game.getState(), game, null); + GameView gameView = new GameView(game.getState(), game, null, userId); + processWatchedHands(userId, gameView); + return gameView; + + } + + protected void processWatchedHands(UUID userId, GameView gameView) { + Map handCards = new HashMap<>(); + for (Player player: game.getPlayers().values()) { + if (player.hasUserPermissionToSeeHand(userId)) { + handCards.put(player.getName(), new SimpleCardsView(player.getHand().getCards(game))); + gameView.setWatchedHands(handCards); + } + } } - public GameEndView getGameEndView(UUID playerId, Table table) { return new GameEndView(game.getState(), game, playerId, table); } diff --git a/Mage.Server/src/main/java/mage/server/game/ReplaySession.java b/Mage.Server/src/main/java/mage/server/game/ReplaySession.java index 16528aca921..c426fbe7db3 100644 --- a/Mage.Server/src/main/java/mage/server/game/ReplaySession.java +++ b/Mage.Server/src/main/java/mage/server/game/ReplaySession.java @@ -54,7 +54,7 @@ public class ReplaySession implements GameCallback { replay.start(); User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("replayInit", replay.getGame().getId(), new GameView(replay.next(), replay.getGame(), null))); + user.fireCallback(new ClientCallback("replayInit", replay.getGame().getId(), new GameView(replay.next(), replay.getGame(), null, null))); } } @@ -93,7 +93,7 @@ public class ReplaySession implements GameCallback { else { User user = UserManager.getInstance().getUser(userId); if (user != null) { - user.fireCallback(new ClientCallback("replayUpdate", replay.getGame().getId(), new GameView(state, game, null))); + user.fireCallback(new ClientCallback("replayUpdate", replay.getGame().getId(), new GameView(state, game, null, null))); } } } diff --git a/Mage/src/mage/constants/PlayerAction.java b/Mage/src/mage/constants/PlayerAction.java index cf0fc62ea37..ccf54950b4b 100644 --- a/Mage/src/mage/constants/PlayerAction.java +++ b/Mage/src/mage/constants/PlayerAction.java @@ -43,5 +43,10 @@ public enum PlayerAction { CONCEDE, MANA_AUTO_PAYMENT_ON, MANA_AUTO_PAYMENT_OFF, - RESET_AUTO_SELECT_REPLACEMENT_EFFECTS + RESET_AUTO_SELECT_REPLACEMENT_EFFECTS, + REVOKE_PERMISSIONS_TO_SEE_HAND_CARDS, + REQUEST_PERMISSION_TO_SEE_HAND_CARDS, + ADD_PERMISSION_TO_SEE_HAND_CARDS, + PERMISSION_REQUESTS_ALLOWED_ON, + PERMISSION_REQUESTS_ALLOWED_OFF } \ No newline at end of file diff --git a/Mage/src/mage/game/match/MatchPlayer.java b/Mage/src/mage/game/match/MatchPlayer.java index 1398c6916ce..9cead17c7fa 100644 --- a/Mage/src/mage/game/match/MatchPlayer.java +++ b/Mage/src/mage/game/match/MatchPlayer.java @@ -49,6 +49,7 @@ public class MatchPlayer { private boolean doneSideboarding; private int priorityTimeLeft; + public MatchPlayer(Player player, Deck deck) { this.player = player; this.deck = deck; diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index f035786493e..2b97d8f2aab 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -519,4 +519,13 @@ public interface Player extends MageItem, Copyable { */ void setCastSourceIdWithoutMana(UUID sourceId); UUID getCastSourceIdWithoutMana(); + + // permission handling to show hand cards + void addPermissionToShowHandCards(UUID watcherUserId); + boolean hasUserPermissionToSeeHand(UUID userId); + void revokePermissionToSeeHandCards(); + void setRequestToShowHandCardsAllowed(boolean requestAllowed); + boolean isRequestToShowHandCardsAllowed(); + Set getUsersAllowedToSeeHandCards(); + } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index a4ec9a05e32..8afda7b2d19 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -200,6 +200,10 @@ public abstract class PlayerImpl implements Player, Serializable { protected boolean isGameUnderControl = true; protected UUID turnController; protected Set playersUnderYourControl = new HashSet<>(); + + protected Set usersAllowedToSeeHandCards = new HashSet<>(); + protected boolean requestsAllowedToSeeHandCards = true; + protected List attachments = new ArrayList<>(); protected boolean topCardRevealed = false; @@ -214,12 +218,12 @@ public abstract class PlayerImpl implements Player, Serializable { protected UserData userData; + /** * During some steps we can't play anything */ - protected final Map silentPhaseSteps = new HashMap() {{ - put(PhaseStep.DECLARE_ATTACKERS, Step.StepPart.PRE); - }}; + protected final Map silentPhaseSteps = new HashMap() + {{ put(PhaseStep.DECLARE_ATTACKERS, Step.StepPart.PRE);}}; public PlayerImpl(String name, RangeOfInfluence range) { this(UUID.randomUUID()); @@ -286,6 +290,9 @@ public abstract class PlayerImpl implements Player, Serializable { this.topCardRevealed = player.topCardRevealed; this.playersUnderYourControl.clear(); this.playersUnderYourControl.addAll(player.playersUnderYourControl); + this.usersAllowedToSeeHandCards.addAll(player.usersAllowedToSeeHandCards); + this.requestsAllowedToSeeHandCards = player.requestsAllowedToSeeHandCards; + this.isTestMode = player.isTestMode; this.isGameUnderControl = player.isGameUnderControl; @@ -361,6 +368,9 @@ public abstract class PlayerImpl implements Player, Serializable { this.priorityTimeLeft = player.getPriorityTimeLeft(); this.reachedNextTurnAfterLeaving = player.hasReachedNextTurnAfterLeaving(); this.castSourceIdWithoutMana = player.getCastSourceIdWithoutMana(); + + this.usersAllowedToSeeHandCards.addAll(player.getUsersAllowedToSeeHandCards()); + this.requestsAllowedToSeeHandCards = player.isRequestToShowHandCardsAllowed(); } @Override @@ -1771,6 +1781,13 @@ public abstract class PlayerImpl implements Player, Serializable { passedUntilEndOfTurn = false; passedUntilNextMain = false; passedUntilStackResolved = false; + break; + case PERMISSION_REQUESTS_ALLOWED_OFF: + this.setRequestToShowHandCardsAllowed(false); + break; + case PERMISSION_REQUESTS_ALLOWED_ON: + this.setRequestToShowHandCardsAllowed(true); + break; } logger.trace("PASS Priority: " + playerAction.toString()); } @@ -2721,5 +2738,35 @@ public abstract class PlayerImpl implements Player, Serializable { public boolean getPassedUntilStackResolved() { return passedUntilStackResolved; } - + + @Override + public void revokePermissionToSeeHandCards() { + usersAllowedToSeeHandCards.clear(); + } + + @Override + public void addPermissionToShowHandCards(UUID watcherUserId) { + usersAllowedToSeeHandCards.add(watcherUserId); + } + + @Override + public void setRequestToShowHandCardsAllowed(boolean requestAllowed) { + this.requestsAllowedToSeeHandCards = requestAllowed; + } + + @Override + public boolean isRequestToShowHandCardsAllowed() { + return requestsAllowedToSeeHandCards; + } + @Override + public boolean hasUserPermissionToSeeHand(UUID userId) { + return usersAllowedToSeeHandCards.contains(userId); + } + + @Override + public Set getUsersAllowedToSeeHandCards() { + return usersAllowedToSeeHandCards; + } + + } diff --git a/Mage/src/mage/players/net/UserData.java b/Mage/src/mage/players/net/UserData.java index e586e6ade20..581e2bbed99 100644 --- a/Mage/src/mage/players/net/UserData.java +++ b/Mage/src/mage/players/net/UserData.java @@ -12,12 +12,14 @@ public class UserData implements Serializable { protected int groupId; protected int avatarId; protected boolean showAbilityPickerForced; + protected boolean allowRequestShowHandCards; protected UserSkipPrioritySteps userSkipPrioritySteps; - public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced, UserSkipPrioritySteps userSkipPrioritySteps) { + public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards, UserSkipPrioritySteps userSkipPrioritySteps) { this.groupId = userGroup.getGroupId(); this.avatarId = avatarId; this.showAbilityPickerForced = showAbilityPickerForced; + this.allowRequestShowHandCards = allowRequestShowHandCards; this.userSkipPrioritySteps = userSkipPrioritySteps; } @@ -45,6 +47,14 @@ public class UserData implements Serializable { this.showAbilityPickerForced = showAbilityPickerForced; } + public void setAllowRequestShowHandCards(boolean allowRequestShowHandCards) { + this.allowRequestShowHandCards = allowRequestShowHandCards; + } + + public boolean allowRequestShowHandCards() { + return allowRequestShowHandCards; + } + public UserSkipPrioritySteps getUserSkipPrioritySteps() { return userSkipPrioritySteps; }