From f68460603ac65cba99a2ae9e49d245436c90975f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20=C3=85strand?= Date: Wed, 22 Feb 2017 20:17:26 +0100 Subject: [PATCH] Add client-side user ignore list This commit adds a client-side per-server ignore list. * Whispers and talk from an ignored user is hidden * Ignored users cannot join your tables * Ignored users tables are hidden --- .../src/main/java/mage/client/MageFrame.java | 6 ++ .../main/java/mage/client/SessionHandler.java | 7 +- .../java/mage/client/chat/ChatPanelBasic.java | 8 +- .../mage/client/chat/ChatPanelSeparated.java | 3 +- .../java/mage/client/chat/LocalCommands.java | 65 ++++++++++++ .../mage/client/dialog/NewTableDialog.java | 3 + .../client/preference/MagePreferences.java | 39 +++++++- .../client/remote/CallbackClientImpl.java | 12 +++ .../java/mage/client/table/TablesPane.java | 6 ++ .../java/mage/client/table/TablesPanel.java | 26 ++++- .../java/mage/client/util/IgnoreList.java | 98 +++++++++++++++++++ .../preference/MagePreferencesTest.java | 47 +++++++++ .../java/mage/client/util/IgnoreListTest.java | 85 ++++++++++++++++ Mage.Common/src/mage/remote/SessionImpl.java | 6 ++ .../src/mage/remote/interfaces/Connect.java | 4 + Mage.Common/src/mage/view/ChatMessage.java | 2 +- .../main/java/mage/server/ChatManager.java | 5 +- .../main/java/mage/server/ChatSession.java | 4 +- .../java/mage/server/TableController.java | 4 +- Mage/src/main/java/mage/game/Table.java | 18 +++- .../java/mage/game/match/MatchOptions.java | 11 +++ .../main/java/mage/players/PlayerImpl.java | 2 +- 22 files changed, 443 insertions(+), 18 deletions(-) create mode 100644 Mage.Client/src/main/java/mage/client/chat/LocalCommands.java create mode 100644 Mage.Client/src/main/java/mage/client/util/IgnoreList.java create mode 100644 Mage.Client/src/test/java/mage/client/preference/MagePreferencesTest.java create mode 100644 Mage.Client/src/test/java/mage/client/util/IgnoreListTest.java diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 79a7037063..529c630d99 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -1057,6 +1057,12 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { this.tablesPane.hideTables(); } + public void setTableFilter() { + if (this.tablesPane != null) { + this.tablesPane.setTableFilter(); + } + } + public void showGames(boolean setActive) { MagePane topPanebefore = getTopMost(tablesPane); if (!tablesPane.isVisible()) { diff --git a/Mage.Client/src/main/java/mage/client/SessionHandler.java b/Mage.Client/src/main/java/mage/client/SessionHandler.java index b99b42e460..74930a76df 100644 --- a/Mage.Client/src/main/java/mage/client/SessionHandler.java +++ b/Mage.Client/src/main/java/mage/client/SessionHandler.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Set; import java.util.UUID; import mage.cards.decks.DeckCardLists; +import mage.client.chat.LocalCommands; import mage.constants.ManaType; import mage.constants.PlayerAction; import mage.game.match.MatchOptions; @@ -306,7 +307,11 @@ public class SessionHandler { } public static boolean sendChatMessage(UUID chatId, String text) { - return session.sendChatMessage(chatId, text); + if (!LocalCommands.handleLocalCommands(chatId, text)) { + return session.sendChatMessage(chatId, text); + } else { + return false; + } } public static boolean sendPlayerManaType(UUID gameId, UUID playerId, ManaType data) { diff --git a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java index 1fa3ee5e80..634f956679 100644 --- a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java +++ b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java @@ -271,8 +271,8 @@ public class ChatPanelBasic extends javax.swing.JPanel { if (color.equals(MessageColor.YELLOW)) { textColor = "Yellow"; } - if (messageType == MessageType.WHISPER) { - if (username.equalsIgnoreCase("Whisper from " + SessionHandler.getUserName())) { + if (messageType == MessageType.WHISPER_FROM) { + if (username.equalsIgnoreCase(SessionHandler.getUserName())) { if (message.toLowerCase().startsWith("profanity 0")) { PreferencesDialog.saveValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0"); } else if (message.toLowerCase().startsWith("profanity 1")) { @@ -281,6 +281,10 @@ public class ChatPanelBasic extends javax.swing.JPanel { PreferencesDialog.saveValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "2"); } } + username = "Whisper from " + username; + } + if (messageType == MessageType.WHISPER_TO) { + username = "Whisper to " + username; } Matcher matchPattern = cardNamePattern.matcher(message); diff --git a/Mage.Client/src/main/java/mage/client/chat/ChatPanelSeparated.java b/Mage.Client/src/main/java/mage/client/chat/ChatPanelSeparated.java index cfae0931f9..a3bc1aaa97 100644 --- a/Mage.Client/src/main/java/mage/client/chat/ChatPanelSeparated.java +++ b/Mage.Client/src/main/java/mage/client/chat/ChatPanelSeparated.java @@ -57,7 +57,8 @@ public class ChatPanelSeparated extends ChatPanelBasic { public void receiveMessage(String username, String message, String time, ChatMessage.MessageType messageType, ChatMessage.MessageColor color) { switch (messageType) { case TALK: - case WHISPER: + case WHISPER_TO: + case WHISPER_FROM: case USER_INFO: super.receiveMessage(username, message, time, messageType, color); return; diff --git a/Mage.Client/src/main/java/mage/client/chat/LocalCommands.java b/Mage.Client/src/main/java/mage/client/chat/LocalCommands.java new file mode 100644 index 0000000000..ec854cad40 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/chat/LocalCommands.java @@ -0,0 +1,65 @@ +package mage.client.chat; + +import mage.client.MageFrame; +import mage.client.SessionHandler; +import mage.client.util.IgnoreList; +import mage.interfaces.callback.ClientCallback; +import mage.view.ChatMessage; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Optional; +import java.util.StringTokenizer; +import java.util.UUID; + +public class LocalCommands { + + private static final DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT); + + /** + * Handler for commands that do not require server interaction, i.e settings etc + * @param chatId + * @param text + * @return true if the command was handled locally, else false + */ + public static boolean handleLocalCommands(UUID chatId, String text) { + final StringTokenizer st = new StringTokenizer(text.trim()); + final int tokens = st.countTokens(); + if (tokens == 0) { + return false; + } + + final String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); + Optional response = Optional.empty(); + + switch (st.nextToken()) { + case "/ignore": + case "\\ignore": + final String ignoreTarget = tokens > 1 ? st.nextToken() : ""; + response = Optional.of(IgnoreList.ignore(serverAddress, ignoreTarget)); + break; + case "/unignore": + case "\\unignore": + final String unignoreTarget = tokens > 1 ? st.nextToken() : ""; + response = Optional.of(IgnoreList.unignore(serverAddress, unignoreTarget)); + break; + // TODO: move profanity settings to here + default: + break; + } + + if (response.isPresent()) { + displayLocalCommandResponse(chatId, response.get()); + return true; + } + + return false; + } + + private static void displayLocalCommandResponse(UUID chatId, String response) { + final String text = new StringBuilder().append("").append(response).append("").toString(); + ClientCallback chatMessage = new ClientCallback("chatMessage", chatId, + new ChatMessage("", text, timeFormatter.format(new Date()), ChatMessage.MessageColor.BLUE)); + MageFrame.getInstance().processCallback(chatMessage); + } +} diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java index be43daee88..c94ebc1808 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java @@ -41,6 +41,7 @@ import mage.client.SessionHandler; import mage.client.components.MageComponents; import mage.client.table.TablePlayerPanel; import mage.client.util.Event; +import mage.client.util.IgnoreList; import mage.client.util.Listener; import mage.constants.MatchTimeLimit; import mage.constants.MultiplayerAttackOption; @@ -386,6 +387,8 @@ public class NewTableDialog extends MageDialog { options.setPassword(this.txtPassword.getText()); options.setQuitRatio((Integer) this.spnQuitRatio.getValue()); options.setEdhPowerLevel((Integer) this.spnEdhPowerLevel.getValue()); + String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); + options.setBannedUsers(IgnoreList.ignoreList(serverAddress)); if (!checkMatchOptions(options)) { return; } diff --git a/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java b/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java index 6f63f14f18..64f200a28f 100644 --- a/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java +++ b/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java @@ -1,8 +1,11 @@ package mage.client.preference; +import com.google.common.collect.Sets; +import mage.client.MageFrame; + +import java.util.Set; import java.util.prefs.BackingStoreException; 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 { @@ -14,6 +17,8 @@ public class MagePreferences { private static final String KEY_EMAIL = "email"; private static final String KEY_AUTO_CONNECT = "autoConnect"; + private static final String NODE_KEY_IGNORE_LIST = "ignoreListString"; + private static Preferences prefs() { // TODO: Move MageFrame.prefs to this class. return MageFrame.getPreferences(); @@ -98,4 +103,36 @@ public class MagePreferences { public static void setAutoConnect(boolean autoConnect) { prefs().putBoolean(KEY_AUTO_CONNECT, autoConnect); } + + public static void addIgnoredUser(String serverAddress, String username) { + ignoreListNode(serverAddress).putBoolean(username, true); + } + + public static boolean removeIgnoredUser(String serverAddress, String username) { + Preferences ignoreList = ignoreListNode(serverAddress); + boolean exists = ignoreList.getBoolean(username, false); + if (exists) { + ignoreList.remove(username); + } + + return exists; + } + + public static Set ignoreList(String serverAddress) { + try { + return Sets.newHashSet(ignoreListNode(serverAddress).keys()); + } catch (BackingStoreException e) { + e.printStackTrace(); + } + return Sets.newHashSet(); + } + + public static void clearIgnoreList(String serverAddress) throws BackingStoreException { + ignoreListNode(serverAddress).clear(); + } + + private static Preferences ignoreListNode(String serverAddress) { + return prefs().node(NODE_KEY_IGNORE_LIST).node(serverAddress); + } + } 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 c2bd89eb95..3185af1bee 100644 --- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java +++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java @@ -34,6 +34,7 @@ import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import mage.cards.decks.Deck; import mage.client.MageFrame; +import mage.client.SessionHandler; import mage.client.chat.ChatPanelBasic; import mage.client.constants.Constants.DeckEditorMode; import mage.client.dialog.PreferencesDialog; @@ -42,6 +43,7 @@ import mage.client.game.GamePanel; import mage.client.plugins.impl.Plugins; import mage.client.util.DeckUtil; import mage.client.util.GameManager; +import mage.client.util.IgnoreList; import mage.client.util.audio.AudioManager; import mage.client.util.object.SaveObjectUtil; import mage.interfaces.callback.CallbackClient; @@ -110,6 +112,15 @@ public class CallbackClientImpl implements CallbackClient { break; case "chatMessage": { ChatMessage message = (ChatMessage) callback.getData(); + + // Drop messages from ignored users + if (message.getUsername() != null && IgnoreList.IGNORED_MESSAGE_TYPES.contains(message.getMessageType())) { + final String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); + if (IgnoreList.userIsIgnored(serverAddress, message.getUsername())) { + break; + } + } + ChatPanelBasic panel = MageFrame.getChat(callback.getObjectId()); if (panel != null) { // play the sound related to the message @@ -422,6 +433,7 @@ public class CallbackClientImpl implements CallbackClient { usedPanel.receiveMessage("", new StringBuilder("Download card images by using the \"Images\" menu to the top right .") .append("
Download icons and symbols by using the \"Symbols\" menu to the top right.") .append("
\\list - Show a list of available chat commands.") + .append("
").append(IgnoreList.usage()) .append("
Type \\w yourUserName profanity 0 (or 1 or 2) to turn off/on the profanity filter").toString(), null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE); break; diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPane.java b/Mage.Client/src/main/java/mage/client/table/TablesPane.java index 78e685ae6e..dad29c460f 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPane.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPane.java @@ -140,4 +140,10 @@ public class TablesPane extends MagePane { public void deactivated() { tablesPanel.stopTasks(); } + + public void setTableFilter() { + if (tablesPanel != null) { + tablesPanel.setTableFilter(); + } + } } diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index 3000313736..56dacd4e4c 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -51,6 +51,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; @@ -85,6 +86,7 @@ import mage.client.dialog.TableWaitingDialog; import static mage.client.table.TablesPanel.PASSWORDED; import mage.client.util.ButtonColumn; import mage.client.util.GUISizeHelper; +import mage.client.util.IgnoreList; import mage.client.util.MageTableRowSorter; import mage.client.util.gui.GuiDisplayUtil; import mage.client.util.gui.TableUtil; @@ -550,7 +552,7 @@ public class TablesPanel extends javax.swing.JPanel { return chatPanelMain.getUserChatPanel(); } - private void setTableFilter() { + public void setTableFilter() { // state List> stateFilterList = new ArrayList<>(); if (btnStateWaiting.isSelected()) { @@ -630,6 +632,20 @@ public class TablesPanel extends javax.swing.JPanel { passwordFilterList.add(RowFilter.regexFilter("^\\*\\*\\*$", TableTableModel.COLUMN_PASSWORD)); } + // Hide games of ignored players + List> ignoreListFilterList = new ArrayList<>(); + String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); + final Set ignoreListCopy = IgnoreList.ignoreList(serverAddress); + if (ignoreListCopy.size() > 0) { + ignoreListFilterList.add(new RowFilter() { + @Override + public boolean include(Entry entry) { + final String owner = entry.getStringValue(TableTableModel.COLUMN_OWNER); + return !ignoreListCopy.contains(owner); + } + }); + } + if (stateFilterList.isEmpty() || typeFilterList.isEmpty() || formatFilterList.isEmpty() || skillFilterList.isEmpty() || ratingFilterList.isEmpty() || passwordFilterList.isEmpty()) { // no selection @@ -673,6 +689,12 @@ public class TablesPanel extends javax.swing.JPanel { filterList.addAll(passwordFilterList); } + if (ignoreListFilterList.size() > 1) { + filterList.add(RowFilter.orFilter(ignoreListFilterList)); + } else if (ignoreListFilterList.size() == 1) { + filterList.addAll(ignoreListFilterList); + } + if (filterList.size() == 1) { activeTablesSorter.setRowFilter(filterList.get(0)); } else { @@ -1177,6 +1199,8 @@ public class TablesPanel extends javax.swing.JPanel { options.setSkillLevel(SkillLevel.CASUAL); options.setRollbackTurnsAllowed(true); options.setQuitRatio(100); + String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); + options.setBannedUsers(IgnoreList.ignoreList(serverAddress)); table = SessionHandler.createTable(roomId, options); SessionHandler.joinTable(roomId, table.getTableId(), "Human", "Human", 1, DeckImporterUtil.importDeck("test.dck"), ""); diff --git a/Mage.Client/src/main/java/mage/client/util/IgnoreList.java b/Mage.Client/src/main/java/mage/client/util/IgnoreList.java new file mode 100644 index 0000000000..6c020518d0 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/util/IgnoreList.java @@ -0,0 +1,98 @@ +package mage.client.util; + +import com.google.common.collect.ImmutableSet; +import mage.client.MageFrame; +import mage.client.preference.MagePreferences; +import mage.view.ChatMessage; + +import java.util.Arrays; +import java.util.Set; + +public class IgnoreList { + + private static final String USAGE = "
\\ignore - shows current ignore list on this server." + + "
\\ignore [username] - add a username to your ignore list on this server." + + "
\\unignore [username] - remove a username from your ignore list on this server.
"; + + public static final int MAX_IGNORE_LIST_SIZE = 50; + public static Set IGNORED_MESSAGE_TYPES = + ImmutableSet.of(ChatMessage.MessageType.TALK, + ChatMessage.MessageType.WHISPER_FROM); + + public static String usage() { + return USAGE; + } + + public static Set ignoreList(String serverAddress) { + return MagePreferences.ignoreList(serverAddress); + } + + public static String ignoreListString(String serverAddress) { + final String[] list = MagePreferences.ignoreList(serverAddress).toArray(new String[0]); + Arrays.sort(list); + return "Current ignore list on " + serverAddress + ": " + + Arrays.toString(list) + + ""; + } + + public static String ignore(String serverAddress, String user) { + if (user == null || user.length() == 0) { + return ignoreListString(serverAddress); + } + + if (MagePreferences.ignoreList(serverAddress).size() >= MAX_IGNORE_LIST_SIZE) { + return "Your ignore list is too big, remove a user to be able to add a new one."; + } + + if (userIsIgnored(serverAddress, user)) { + return new StringBuilder() + .append(user) + .append(" is already on your ignore list on ") + .append(serverAddress) + .toString(); + } + + MagePreferences.addIgnoredUser(serverAddress, user); + updateTablesTable(); + + return new StringBuilder() + .append("Added ") + .append(user) + .append(" to your ignore list on ") + .append(serverAddress) + .toString(); + } + + private static void updateTablesTable() { + MageFrame mageFrame = MageFrame.getInstance(); + if (mageFrame != null) { + mageFrame.setTableFilter(); + } + } + + public static String unignore(String serverAddress, String user) { + if (user == null || user.length() == 0) { + return usage(); + } + if (MagePreferences.removeIgnoredUser(serverAddress, user)) { + updateTablesTable(); + return new StringBuilder() + .append("Removed ") + .append(user) + .append(" from your ignore list on ") + .append(serverAddress) + .toString(); + } else { + return new StringBuilder() + .append("No such user \"") + .append(user) + .append("\" on your ignore list on ") + .append(serverAddress) + .toString(); + } + } + + public static boolean userIsIgnored(String serverAddress, String username) { + return MagePreferences.ignoreList(serverAddress).contains(username); + } +} diff --git a/Mage.Client/src/test/java/mage/client/preference/MagePreferencesTest.java b/Mage.Client/src/test/java/mage/client/preference/MagePreferencesTest.java new file mode 100644 index 0000000000..7b9681e712 --- /dev/null +++ b/Mage.Client/src/test/java/mage/client/preference/MagePreferencesTest.java @@ -0,0 +1,47 @@ +package mage.client.preference; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +public class MagePreferencesTest { + @Before + public void setUp() { + MagePreferences.ignoreList("test.com.xx").clear(); + } + + @After + public void tearDown() { + MagePreferences.ignoreList("test.com.xx").clear(); + } + + @Test + public void testIgnoreList() throws Exception { + assertThat(MagePreferences.ignoreList("test.com.xx").size(), is(0)); + assertThat(MagePreferences.removeIgnoredUser("test.com.xx", "test"), is(false)); + + MagePreferences.addIgnoredUser("test.com.xx", "test"); + assertThat(MagePreferences.ignoreList("test.com.xx").size(), is(1)); + assertThat(MagePreferences.ignoreList("other.com.xx").size(), is(0)); + + MagePreferences.addIgnoredUser("test.com.xx", "lul"); + assertThat(MagePreferences.ignoreList("test.com.xx").size(), is(2)); + + assertThat(MagePreferences.ignoreList("test.com.xx").contains("test"), is(true)); + assertThat(MagePreferences.ignoreList("test.com.xx").contains("lul"), is(true)); + + assertThat(MagePreferences.removeIgnoredUser("test.com.xx", "test"), is(true)); + assertThat(MagePreferences.removeIgnoredUser("test.com.xx", "test"), is(false)); + assertThat(MagePreferences.ignoreList("test.com.xx").size(), is(1)); + + assertThat(MagePreferences.removeIgnoredUser("test.com.xx", "lul"), is(true)); + assertThat(MagePreferences.removeIgnoredUser("test.com.xx", "lul"), is(false)); + assertThat(MagePreferences.ignoreList("test.com.xx").size(), is(0)); + + assertThat(MagePreferences.ignoreList("test.com.xx").contains("test"), is(false)); + assertThat(MagePreferences.ignoreList("test.com.xx").contains("lul"), is(false)); + } +} \ No newline at end of file diff --git a/Mage.Client/src/test/java/mage/client/util/IgnoreListTest.java b/Mage.Client/src/test/java/mage/client/util/IgnoreListTest.java new file mode 100644 index 0000000000..c4ad2f8b44 --- /dev/null +++ b/Mage.Client/src/test/java/mage/client/util/IgnoreListTest.java @@ -0,0 +1,85 @@ +package mage.client.util; + +import mage.client.preference.MagePreferences; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static junit.framework.TestCase.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +public class IgnoreListTest { + + @Before + public void setUp() throws Exception { + MagePreferences.clearIgnoreList("test.com.xx"); + } + + @After + public void tearDown() throws Exception { + MagePreferences.clearIgnoreList("test.com.xx"); + } + + @Test + public void ignoreListEmpty() throws Exception { + assertThat(IgnoreList.ignoreListString("test.com.xx"), is("Current ignore list on test.com.xx: []")); + } + + @Test + public void ignoreList() throws Exception { + final String test = IgnoreList.ignore("test.com.xx", "test"); + final String kranken = IgnoreList.ignore("test.com.xx", "kranken"); + assertThat(IgnoreList.ignoreListString("test.com.xx"), is("Current ignore list on test.com.xx: [kranken, test]")); + assertThat(test, is("Added test to your ignore list on test.com.xx")); + assertThat(kranken, is("Added kranken to your ignore list on test.com.xx")); + } + + @Test + public void ignore() throws Exception { + assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(false)); + final String r = IgnoreList.ignore("test.com.xx", "kranken"); + assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(true)); + assertEquals(r, "Added kranken to your ignore list on test.com.xx"); + } + + @Test + public void ignoreAgain() throws Exception { + assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(false)); + IgnoreList.ignore("test.com.xx", "kranken"); + final String r = IgnoreList.ignore("test.com.xx", "kranken"); + assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(true)); + assertEquals(r, "kranken is already on your ignore list on test.com.xx"); + } + + @Test + public void ignoreDefaultResponse() throws Exception { + final String r1 = IgnoreList.ignore("test.com.xx", ""); + final String r2 = IgnoreList.ignore("test.com.xx", null); + assertThat(IgnoreList.ignoreListString("test.com.xx"), is("Current ignore list on test.com.xx: []")); + assertEquals(r1, r2); + assertEquals(r2, "Current ignore list on test.com.xx: []"); + } + + @Test + public void ignoreMaxSize() throws Exception { + for (int i = 0; i < 50; i++) { + IgnoreList.ignore("test.com.xx", "" + i); + } + final String r = IgnoreList.ignore("test.com.xx", "lul"); + assertEquals(r, "Your ignore list is too big, remove a user to be able to add a new one."); + assertThat(IgnoreList.ignoreListString("test.com.xx"), is("Current ignore list on test.com.xx: [0, 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 3, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 4, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 5, 6, 7, 8, 9]")); + } + + @Test + public void unignore() throws Exception { + assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(false)); + IgnoreList.ignore("test.com.xx", "kranken"); + assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(true)); + final String r = IgnoreList.unignore("test.com.xx", "kranken"); + assertThat(IgnoreList.userIsIgnored("test.com.xx", "kranken"), is(false)); + assertEquals(r, "Removed kranken from your ignore list on test.com.xx"); + + } + +} \ No newline at end of file diff --git a/Mage.Common/src/mage/remote/SessionImpl.java b/Mage.Common/src/mage/remote/SessionImpl.java index c3a98840c1..3549dcd0c5 100644 --- a/Mage.Common/src/mage/remote/SessionImpl.java +++ b/Mage.Common/src/mage/remote/SessionImpl.java @@ -244,6 +244,10 @@ public class SessionImpl implements Session { }); } + public Optional getServerHostname() { + return isConnected() ? Optional.of(connection.getHost()) : Optional.empty(); + } + @Override public boolean stopConnecting() { canceled = true; @@ -960,6 +964,8 @@ public class SessionImpl implements Session { return false; } + + @Override public boolean joinGame(UUID gameId) { try { diff --git a/Mage.Common/src/mage/remote/interfaces/Connect.java b/Mage.Common/src/mage/remote/interfaces/Connect.java index 5cb8750e59..63cbdc431d 100644 --- a/Mage.Common/src/mage/remote/interfaces/Connect.java +++ b/Mage.Common/src/mage/remote/interfaces/Connect.java @@ -29,6 +29,8 @@ package mage.remote.interfaces; import mage.remote.Connection; +import java.util.Optional; + /** * @author noxx */ @@ -52,6 +54,8 @@ public interface Connect { boolean isConnected(); + Optional getServerHostname(); + boolean disconnectUser(String userSessionId); boolean endUserSession(String userSessionId); diff --git a/Mage.Common/src/mage/view/ChatMessage.java b/Mage.Common/src/mage/view/ChatMessage.java index d13dccddb3..888837b9d6 100644 --- a/Mage.Common/src/mage/view/ChatMessage.java +++ b/Mage.Common/src/mage/view/ChatMessage.java @@ -49,7 +49,7 @@ public class ChatMessage implements Serializable { } public enum MessageType { - USER_INFO, STATUS, GAME, TALK, WHISPER + USER_INFO, STATUS, GAME, TALK, WHISPER_FROM, WHISPER_TO } public enum SoundToPlay { diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java index b8f655733f..70de72b033 100644 --- a/Mage.Server/src/main/java/mage/server/ChatManager.java +++ b/Mage.Server/src/main/java/mage/server/ChatManager.java @@ -190,7 +190,10 @@ public class ChatManager { + "
\\me - shows the history of the current player" + "
\\list or \\l - Show a list of commands" + "
\\whisper or \\w [player name] [text] - whisper to the player with the given name" - + "
[Card Name] - Show a highlighted card name"; + + "
[Card Name] - Show a highlighted card name" + + "
\\ignore - shows current ignore list on this server." + + "
\\ignore [username] - add a username to your ignore list on this server." + + "
\\unignore [username] - remove a username from your ignore list on this server."; private boolean performUserCommand(User user, String message, UUID chatId, boolean doError) { String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH); diff --git a/Mage.Server/src/main/java/mage/server/ChatSession.java b/Mage.Server/src/main/java/mage/server/ChatSession.java index 34119c0852..cb9290d84e 100644 --- a/Mage.Server/src/main/java/mage/server/ChatSession.java +++ b/Mage.Server/src/main/java/mage/server/ChatSession.java @@ -127,10 +127,10 @@ public class ChatSession { public boolean broadcastWhisperToUser(User fromUser, User toUser, String message) { if (clients.containsKey(toUser.getId())) { toUser.fireCallback(new ClientCallback("chatMessage", chatId, - new ChatMessage(new StringBuilder("Whisper from ").append(fromUser.getName()).toString(), message, timeFormatter.format(new Date()), MessageColor.YELLOW, MessageType.WHISPER, SoundToPlay.PlayerWhispered))); + new ChatMessage(fromUser.getName(), message, timeFormatter.format(new Date()), MessageColor.YELLOW, MessageType.WHISPER_FROM, SoundToPlay.PlayerWhispered))); if (clients.containsKey(fromUser.getId())) { fromUser.fireCallback(new ClientCallback("chatMessage", chatId, - new ChatMessage(new StringBuilder("Whisper to ").append(toUser.getName()).toString(), message, timeFormatter.format(new Date()), MessageColor.YELLOW, MessageType.WHISPER, null))); + new ChatMessage(toUser.getName(), message, timeFormatter.format(new Date()), MessageColor.YELLOW, MessageType.WHISPER_TO, null))); 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 f4490101b7..2a3de710b8 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -99,7 +99,7 @@ public class TableController { } else { controllerName = "System"; } - table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), match); + table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), match, options.getBannedUsers()); chatId = ChatManager.getInstance().createChatSession("Match Table " + table.getId()); init(); } @@ -118,7 +118,7 @@ public class TableController { } else { controllerName = "System"; } - table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), tournament); + table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), tournament, options.getMatchOptions().getBannedUsers()); chatId = ChatManager.getInstance().createChatSession("Tourn. table " + table.getId()); } diff --git a/Mage/src/main/java/mage/game/Table.java b/Mage/src/main/java/mage/game/Table.java index 1a019a24a7..44b04c1205 100644 --- a/Mage/src/main/java/mage/game/Table.java +++ b/Mage/src/main/java/mage/game/Table.java @@ -30,7 +30,9 @@ package mage.game; import java.io.Serializable; import java.util.Arrays; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.UUID; import mage.cards.decks.DeckValidator; import mage.constants.TableState; @@ -63,6 +65,7 @@ public class Table implements Serializable { private Match match; private Tournament tournament; private TableRecorder recorder; + private Set bannedUsernames; @FunctionalInterface public interface TableRecorder { @@ -71,21 +74,21 @@ public class Table implements Serializable { protected TableEventSource tableEventSource = new TableEventSource(); - public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder, Tournament tournament) { - this(roomId, gameType, name, controllerName, validator, playerTypes, recorder); + public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder, Tournament tournament, Set bannedUsernames) { + this(roomId, gameType, name, controllerName, validator, playerTypes, recorder, bannedUsernames); this.tournament = tournament; this.isTournament = true; setState(TableState.WAITING); } - public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder, Match match) { - this(roomId, gameType, name, controllerName, validator, playerTypes, recorder); + public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder, Match match, Set bannedUsernames) { + this(roomId, gameType, name, controllerName, validator, playerTypes, recorder, bannedUsernames); this.match = match; this.isTournament = false; setState(TableState.WAITING); } - protected Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder) { + protected Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List playerTypes, TableRecorder recorder, Set bannedUsernames) { tableId = UUID.randomUUID(); this.roomId = roomId; this.numSeats = playerTypes.size(); @@ -96,6 +99,7 @@ public class Table implements Serializable { createSeats(playerTypes); this.validator = validator; this.recorder = recorder; + this.bannedUsernames = new HashSet<>(bannedUsernames); } private void createSeats(List playerTypes) { @@ -308,6 +312,10 @@ public class Table implements Serializable { } } + public boolean userIsBanned(String username) { + return bannedUsernames.contains(username); + } + public TableProto toProto() { TableProto.Builder builder = TableProto.newBuilder(); if (this.isTournament()) { diff --git a/Mage/src/main/java/mage/game/match/MatchOptions.java b/Mage/src/main/java/mage/game/match/MatchOptions.java index 3bcd909ab8..3b581aef1b 100644 --- a/Mage/src/main/java/mage/game/match/MatchOptions.java +++ b/Mage/src/main/java/mage/game/match/MatchOptions.java @@ -30,7 +30,9 @@ package mage.game.match; import java.io.Serializable; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import mage.constants.MatchTimeLimit; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; @@ -61,6 +63,7 @@ public class MatchOptions implements Serializable { protected int edhPowerLevel; protected boolean rated; protected int numSeatsForMatch; + protected Set bannedUsers = new HashSet<>(); /** * Time each player has during the game to play using his\her priority. @@ -226,6 +229,14 @@ public class MatchOptions implements Serializable { this.rated = rated; } + public Set getBannedUsers() { + return bannedUsers; + } + + public void setBannedUsers(Set bannedUsers) { + this.bannedUsers = bannedUsers; + } + public ResultProtos.MatchOptionsProto toProto() { ResultProtos.MatchOptionsProto.Builder builder = ResultProtos.MatchOptionsProto.newBuilder() .setName(this.getName()) diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index e162bc382d..0ec4220302 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -3067,7 +3067,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean canJoinTable(Table table) { - return true; + return !table.userIsBanned(name); } @Override