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
This commit is contained in:
Anders Åstrand 2017-02-22 20:17:26 +01:00
parent 19fec8ee2a
commit f68460603a
22 changed files with 443 additions and 18 deletions

View file

@ -1057,6 +1057,12 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
this.tablesPane.hideTables(); this.tablesPane.hideTables();
} }
public void setTableFilter() {
if (this.tablesPane != null) {
this.tablesPane.setTableFilter();
}
}
public void showGames(boolean setActive) { public void showGames(boolean setActive) {
MagePane topPanebefore = getTopMost(tablesPane); MagePane topPanebefore = getTopMost(tablesPane);
if (!tablesPane.isVisible()) { if (!tablesPane.isVisible()) {

View file

@ -5,6 +5,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.cards.decks.DeckCardLists; import mage.cards.decks.DeckCardLists;
import mage.client.chat.LocalCommands;
import mage.constants.ManaType; import mage.constants.ManaType;
import mage.constants.PlayerAction; import mage.constants.PlayerAction;
import mage.game.match.MatchOptions; import mage.game.match.MatchOptions;
@ -306,7 +307,11 @@ public class SessionHandler {
} }
public static boolean sendChatMessage(UUID chatId, String text) { 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) { public static boolean sendPlayerManaType(UUID gameId, UUID playerId, ManaType data) {

View file

@ -271,8 +271,8 @@ public class ChatPanelBasic extends javax.swing.JPanel {
if (color.equals(MessageColor.YELLOW)) { if (color.equals(MessageColor.YELLOW)) {
textColor = "Yellow"; textColor = "Yellow";
} }
if (messageType == MessageType.WHISPER) { if (messageType == MessageType.WHISPER_FROM) {
if (username.equalsIgnoreCase("Whisper from " + SessionHandler.getUserName())) { if (username.equalsIgnoreCase(SessionHandler.getUserName())) {
if (message.toLowerCase().startsWith("profanity 0")) { if (message.toLowerCase().startsWith("profanity 0")) {
PreferencesDialog.saveValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0"); PreferencesDialog.saveValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0");
} else if (message.toLowerCase().startsWith("profanity 1")) { } 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"); 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); Matcher matchPattern = cardNamePattern.matcher(message);

View file

@ -57,7 +57,8 @@ public class ChatPanelSeparated extends ChatPanelBasic {
public void receiveMessage(String username, String message, String time, ChatMessage.MessageType messageType, ChatMessage.MessageColor color) { public void receiveMessage(String username, String message, String time, ChatMessage.MessageType messageType, ChatMessage.MessageColor color) {
switch (messageType) { switch (messageType) {
case TALK: case TALK:
case WHISPER: case WHISPER_TO:
case WHISPER_FROM:
case USER_INFO: case USER_INFO:
super.receiveMessage(username, message, time, messageType, color); super.receiveMessage(username, message, time, messageType, color);
return; return;

View file

@ -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<String> 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("<font color=yellow>").append(response).append("</font>").toString();
ClientCallback chatMessage = new ClientCallback("chatMessage", chatId,
new ChatMessage("", text, timeFormatter.format(new Date()), ChatMessage.MessageColor.BLUE));
MageFrame.getInstance().processCallback(chatMessage);
}
}

View file

@ -41,6 +41,7 @@ import mage.client.SessionHandler;
import mage.client.components.MageComponents; import mage.client.components.MageComponents;
import mage.client.table.TablePlayerPanel; import mage.client.table.TablePlayerPanel;
import mage.client.util.Event; import mage.client.util.Event;
import mage.client.util.IgnoreList;
import mage.client.util.Listener; import mage.client.util.Listener;
import mage.constants.MatchTimeLimit; import mage.constants.MatchTimeLimit;
import mage.constants.MultiplayerAttackOption; import mage.constants.MultiplayerAttackOption;
@ -386,6 +387,8 @@ public class NewTableDialog extends MageDialog {
options.setPassword(this.txtPassword.getText()); options.setPassword(this.txtPassword.getText());
options.setQuitRatio((Integer) this.spnQuitRatio.getValue()); options.setQuitRatio((Integer) this.spnQuitRatio.getValue());
options.setEdhPowerLevel((Integer) this.spnEdhPowerLevel.getValue()); options.setEdhPowerLevel((Integer) this.spnEdhPowerLevel.getValue());
String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
options.setBannedUsers(IgnoreList.ignoreList(serverAddress));
if (!checkMatchOptions(options)) { if (!checkMatchOptions(options)) {
return; return;
} }

View file

@ -1,8 +1,11 @@
package mage.client.preference; 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.BackingStoreException;
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
import mage.client.MageFrame;
// TODO: Move all preference related logic from MageFrame and PreferencesDialog to this class. // TODO: Move all preference related logic from MageFrame and PreferencesDialog to this class.
public class MagePreferences { public class MagePreferences {
@ -14,6 +17,8 @@ public class MagePreferences {
private static final String KEY_EMAIL = "email"; private static final String KEY_EMAIL = "email";
private static final String KEY_AUTO_CONNECT = "autoConnect"; private static final String KEY_AUTO_CONNECT = "autoConnect";
private static final String NODE_KEY_IGNORE_LIST = "ignoreListString";
private static Preferences prefs() { private static Preferences prefs() {
// TODO: Move MageFrame.prefs to this class. // TODO: Move MageFrame.prefs to this class.
return MageFrame.getPreferences(); return MageFrame.getPreferences();
@ -98,4 +103,36 @@ public class MagePreferences {
public static void setAutoConnect(boolean autoConnect) { public static void setAutoConnect(boolean autoConnect) {
prefs().putBoolean(KEY_AUTO_CONNECT, 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<String> 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);
}
} }

View file

@ -34,6 +34,7 @@ import javax.swing.JOptionPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import mage.cards.decks.Deck; import mage.cards.decks.Deck;
import mage.client.MageFrame; import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.chat.ChatPanelBasic; import mage.client.chat.ChatPanelBasic;
import mage.client.constants.Constants.DeckEditorMode; import mage.client.constants.Constants.DeckEditorMode;
import mage.client.dialog.PreferencesDialog; import mage.client.dialog.PreferencesDialog;
@ -42,6 +43,7 @@ import mage.client.game.GamePanel;
import mage.client.plugins.impl.Plugins; import mage.client.plugins.impl.Plugins;
import mage.client.util.DeckUtil; import mage.client.util.DeckUtil;
import mage.client.util.GameManager; import mage.client.util.GameManager;
import mage.client.util.IgnoreList;
import mage.client.util.audio.AudioManager; import mage.client.util.audio.AudioManager;
import mage.client.util.object.SaveObjectUtil; import mage.client.util.object.SaveObjectUtil;
import mage.interfaces.callback.CallbackClient; import mage.interfaces.callback.CallbackClient;
@ -110,6 +112,15 @@ public class CallbackClientImpl implements CallbackClient {
break; break;
case "chatMessage": { case "chatMessage": {
ChatMessage message = (ChatMessage) callback.getData(); 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()); ChatPanelBasic panel = MageFrame.getChat(callback.getObjectId());
if (panel != null) { if (panel != null) {
// play the sound related to the message // 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 .") usedPanel.receiveMessage("", new StringBuilder("Download card images by using the \"Images\" menu to the top right .")
.append("<br/>Download icons and symbols by using the \"Symbols\" menu to the top right.") .append("<br/>Download icons and symbols by using the \"Symbols\" menu to the top right.")
.append("<br/>\\list - Show a list of available chat commands.") .append("<br/>\\list - Show a list of available chat commands.")
.append("<br/>").append(IgnoreList.usage())
.append("<br/>Type <font color=green>\\w yourUserName profanity 0 (or 1 or 2)</font> to turn off/on the profanity filter").toString(), .append("<br/>Type <font color=green>\\w yourUserName profanity 0 (or 1 or 2)</font> to turn off/on the profanity filter").toString(),
null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE); null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE);
break; break;

View file

@ -140,4 +140,10 @@ public class TablesPane extends MagePane {
public void deactivated() { public void deactivated() {
tablesPanel.stopTasks(); tablesPanel.stopTasks();
} }
public void setTableFilter() {
if (tablesPanel != null) {
tablesPanel.setTableFilter();
}
}
} }

View file

@ -51,6 +51,7 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -85,6 +86,7 @@ import mage.client.dialog.TableWaitingDialog;
import static mage.client.table.TablesPanel.PASSWORDED; import static mage.client.table.TablesPanel.PASSWORDED;
import mage.client.util.ButtonColumn; import mage.client.util.ButtonColumn;
import mage.client.util.GUISizeHelper; import mage.client.util.GUISizeHelper;
import mage.client.util.IgnoreList;
import mage.client.util.MageTableRowSorter; import mage.client.util.MageTableRowSorter;
import mage.client.util.gui.GuiDisplayUtil; import mage.client.util.gui.GuiDisplayUtil;
import mage.client.util.gui.TableUtil; import mage.client.util.gui.TableUtil;
@ -550,7 +552,7 @@ public class TablesPanel extends javax.swing.JPanel {
return chatPanelMain.getUserChatPanel(); return chatPanelMain.getUserChatPanel();
} }
private void setTableFilter() { public void setTableFilter() {
// state // state
List<RowFilter<Object, Object>> stateFilterList = new ArrayList<>(); List<RowFilter<Object, Object>> stateFilterList = new ArrayList<>();
if (btnStateWaiting.isSelected()) { if (btnStateWaiting.isSelected()) {
@ -630,6 +632,20 @@ public class TablesPanel extends javax.swing.JPanel {
passwordFilterList.add(RowFilter.regexFilter("^\\*\\*\\*$", TableTableModel.COLUMN_PASSWORD)); passwordFilterList.add(RowFilter.regexFilter("^\\*\\*\\*$", TableTableModel.COLUMN_PASSWORD));
} }
// Hide games of ignored players
List<RowFilter<Object, Object>> ignoreListFilterList = new ArrayList<>();
String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
final Set<String> ignoreListCopy = IgnoreList.ignoreList(serverAddress);
if (ignoreListCopy.size() > 0) {
ignoreListFilterList.add(new RowFilter<Object, Object>() {
@Override
public boolean include(Entry<? extends Object, ? extends Object> entry) {
final String owner = entry.getStringValue(TableTableModel.COLUMN_OWNER);
return !ignoreListCopy.contains(owner);
}
});
}
if (stateFilterList.isEmpty() || typeFilterList.isEmpty() || formatFilterList.isEmpty() if (stateFilterList.isEmpty() || typeFilterList.isEmpty() || formatFilterList.isEmpty()
|| skillFilterList.isEmpty() || ratingFilterList.isEmpty() || skillFilterList.isEmpty() || ratingFilterList.isEmpty()
|| passwordFilterList.isEmpty()) { // no selection || passwordFilterList.isEmpty()) { // no selection
@ -673,6 +689,12 @@ public class TablesPanel extends javax.swing.JPanel {
filterList.addAll(passwordFilterList); filterList.addAll(passwordFilterList);
} }
if (ignoreListFilterList.size() > 1) {
filterList.add(RowFilter.orFilter(ignoreListFilterList));
} else if (ignoreListFilterList.size() == 1) {
filterList.addAll(ignoreListFilterList);
}
if (filterList.size() == 1) { if (filterList.size() == 1) {
activeTablesSorter.setRowFilter(filterList.get(0)); activeTablesSorter.setRowFilter(filterList.get(0));
} else { } else {
@ -1177,6 +1199,8 @@ public class TablesPanel extends javax.swing.JPanel {
options.setSkillLevel(SkillLevel.CASUAL); options.setSkillLevel(SkillLevel.CASUAL);
options.setRollbackTurnsAllowed(true); options.setRollbackTurnsAllowed(true);
options.setQuitRatio(100); options.setQuitRatio(100);
String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
options.setBannedUsers(IgnoreList.ignoreList(serverAddress));
table = SessionHandler.createTable(roomId, options); table = SessionHandler.createTable(roomId, options);
SessionHandler.joinTable(roomId, table.getTableId(), "Human", "Human", 1, DeckImporterUtil.importDeck("test.dck"), ""); SessionHandler.joinTable(roomId, table.getTableId(), "Human", "Human", 1, DeckImporterUtil.importDeck("test.dck"), "");

View file

@ -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 = "<br/><font color=yellow>\\ignore - shows current ignore list on this server."
+ "<br/>\\ignore [username] - add a username to your ignore list on this server."
+ "<br/>\\unignore [username] - remove a username from your ignore list on this server.</font>";
public static final int MAX_IGNORE_LIST_SIZE = 50;
public static Set<ChatMessage.MessageType> IGNORED_MESSAGE_TYPES =
ImmutableSet.of(ChatMessage.MessageType.TALK,
ChatMessage.MessageType.WHISPER_FROM);
public static String usage() {
return USAGE;
}
public static Set<String> 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 "<font color=yellow>Current ignore list on " + serverAddress + ": "
+ Arrays.toString(list)
+ "</font>";
}
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);
}
}

View file

@ -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));
}
}

View file

@ -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("<font color=yellow>Current ignore list on test.com.xx: []</font>"));
}
@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("<font color=yellow>Current ignore list on test.com.xx: [kranken, test]</font>"));
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("<font color=yellow>Current ignore list on test.com.xx: []</font>"));
assertEquals(r1, r2);
assertEquals(r2, "<font color=yellow>Current ignore list on test.com.xx: []</font>");
}
@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("<font color=yellow>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]</font>"));
}
@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");
}
}

View file

@ -244,6 +244,10 @@ public class SessionImpl implements Session {
}); });
} }
public Optional<String> getServerHostname() {
return isConnected() ? Optional.of(connection.getHost()) : Optional.<String>empty();
}
@Override @Override
public boolean stopConnecting() { public boolean stopConnecting() {
canceled = true; canceled = true;
@ -960,6 +964,8 @@ public class SessionImpl implements Session {
return false; return false;
} }
@Override @Override
public boolean joinGame(UUID gameId) { public boolean joinGame(UUID gameId) {
try { try {

View file

@ -29,6 +29,8 @@ package mage.remote.interfaces;
import mage.remote.Connection; import mage.remote.Connection;
import java.util.Optional;
/** /**
* @author noxx * @author noxx
*/ */
@ -52,6 +54,8 @@ public interface Connect {
boolean isConnected(); boolean isConnected();
Optional<String> getServerHostname();
boolean disconnectUser(String userSessionId); boolean disconnectUser(String userSessionId);
boolean endUserSession(String userSessionId); boolean endUserSession(String userSessionId);

View file

@ -49,7 +49,7 @@ public class ChatMessage implements Serializable {
} }
public enum MessageType { public enum MessageType {
USER_INFO, STATUS, GAME, TALK, WHISPER USER_INFO, STATUS, GAME, TALK, WHISPER_FROM, WHISPER_TO
} }
public enum SoundToPlay { public enum SoundToPlay {

View file

@ -190,7 +190,10 @@ public class ChatManager {
+ "<br/>\\me - shows the history of the current player" + "<br/>\\me - shows the history of the current player"
+ "<br/>\\list or \\l - Show a list of commands" + "<br/>\\list or \\l - Show a list of commands"
+ "<br/>\\whisper or \\w [player name] [text] - whisper to the player with the given name" + "<br/>\\whisper or \\w [player name] [text] - whisper to the player with the given name"
+ "<br/>[Card Name] - Show a highlighted card name"; + "<br/>[Card Name] - Show a highlighted card name"
+ "<br/>\\ignore - shows current ignore list on this server."
+ "<br/>\\ignore [username] - add a username to your ignore list on this server."
+ "<br/>\\unignore [username] - remove a username from your ignore list on this server.";
private boolean performUserCommand(User user, String message, UUID chatId, boolean doError) { private boolean performUserCommand(User user, String message, UUID chatId, boolean doError) {
String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH); String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH);

View file

@ -127,10 +127,10 @@ public class ChatSession {
public boolean broadcastWhisperToUser(User fromUser, User toUser, String message) { public boolean broadcastWhisperToUser(User fromUser, User toUser, String message) {
if (clients.containsKey(toUser.getId())) { if (clients.containsKey(toUser.getId())) {
toUser.fireCallback(new ClientCallback("chatMessage", chatId, 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())) { if (clients.containsKey(fromUser.getId())) {
fromUser.fireCallback(new ClientCallback("chatMessage", chatId, 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; return true;
} }
} }

View file

@ -99,7 +99,7 @@ public class TableController {
} else { } else {
controllerName = "System"; controllerName = "System";
} }
table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), 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()); chatId = ChatManager.getInstance().createChatSession("Match Table " + table.getId());
init(); init();
} }
@ -118,7 +118,7 @@ public class TableController {
} else { } else {
controllerName = "System"; controllerName = "System";
} }
table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), 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()); chatId = ChatManager.getInstance().createChatSession("Tourn. table " + table.getId());
} }

View file

@ -30,7 +30,9 @@ package mage.game;
import java.io.Serializable; import java.io.Serializable;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.cards.decks.DeckValidator; import mage.cards.decks.DeckValidator;
import mage.constants.TableState; import mage.constants.TableState;
@ -63,6 +65,7 @@ public class Table implements Serializable {
private Match match; private Match match;
private Tournament tournament; private Tournament tournament;
private TableRecorder recorder; private TableRecorder recorder;
private Set<String> bannedUsernames;
@FunctionalInterface @FunctionalInterface
public interface TableRecorder { public interface TableRecorder {
@ -71,21 +74,21 @@ public class Table implements Serializable {
protected TableEventSource tableEventSource = new TableEventSource(); protected TableEventSource tableEventSource = new TableEventSource();
public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<String> playerTypes, TableRecorder recorder, Tournament tournament) { public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<String> playerTypes, TableRecorder recorder, Tournament tournament, Set<String> bannedUsernames) {
this(roomId, gameType, name, controllerName, validator, playerTypes, recorder); this(roomId, gameType, name, controllerName, validator, playerTypes, recorder, bannedUsernames);
this.tournament = tournament; this.tournament = tournament;
this.isTournament = true; this.isTournament = true;
setState(TableState.WAITING); setState(TableState.WAITING);
} }
public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<String> playerTypes, TableRecorder recorder, Match match) { public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<String> playerTypes, TableRecorder recorder, Match match, Set<String> bannedUsernames) {
this(roomId, gameType, name, controllerName, validator, playerTypes, recorder); this(roomId, gameType, name, controllerName, validator, playerTypes, recorder, bannedUsernames);
this.match = match; this.match = match;
this.isTournament = false; this.isTournament = false;
setState(TableState.WAITING); setState(TableState.WAITING);
} }
protected Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<String> playerTypes, TableRecorder recorder) { protected Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<String> playerTypes, TableRecorder recorder, Set<String> bannedUsernames) {
tableId = UUID.randomUUID(); tableId = UUID.randomUUID();
this.roomId = roomId; this.roomId = roomId;
this.numSeats = playerTypes.size(); this.numSeats = playerTypes.size();
@ -96,6 +99,7 @@ public class Table implements Serializable {
createSeats(playerTypes); createSeats(playerTypes);
this.validator = validator; this.validator = validator;
this.recorder = recorder; this.recorder = recorder;
this.bannedUsernames = new HashSet<>(bannedUsernames);
} }
private void createSeats(List<String> playerTypes) { private void createSeats(List<String> playerTypes) {
@ -308,6 +312,10 @@ public class Table implements Serializable {
} }
} }
public boolean userIsBanned(String username) {
return bannedUsernames.contains(username);
}
public TableProto toProto() { public TableProto toProto() {
TableProto.Builder builder = TableProto.newBuilder(); TableProto.Builder builder = TableProto.newBuilder();
if (this.isTournament()) { if (this.isTournament()) {

View file

@ -30,7 +30,9 @@ package mage.game.match;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import mage.constants.MatchTimeLimit; import mage.constants.MatchTimeLimit;
import mage.constants.MultiplayerAttackOption; import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence; import mage.constants.RangeOfInfluence;
@ -61,6 +63,7 @@ public class MatchOptions implements Serializable {
protected int edhPowerLevel; protected int edhPowerLevel;
protected boolean rated; protected boolean rated;
protected int numSeatsForMatch; protected int numSeatsForMatch;
protected Set<String> bannedUsers = new HashSet<>();
/** /**
* Time each player has during the game to play using his\her priority. * 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; this.rated = rated;
} }
public Set<String> getBannedUsers() {
return bannedUsers;
}
public void setBannedUsers(Set<String> bannedUsers) {
this.bannedUsers = bannedUsers;
}
public ResultProtos.MatchOptionsProto toProto() { public ResultProtos.MatchOptionsProto toProto() {
ResultProtos.MatchOptionsProto.Builder builder = ResultProtos.MatchOptionsProto.newBuilder() ResultProtos.MatchOptionsProto.Builder builder = ResultProtos.MatchOptionsProto.newBuilder()
.setName(this.getName()) .setName(this.getName())

View file

@ -3067,7 +3067,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public boolean canJoinTable(Table table) { public boolean canJoinTable(Table table) {
return true; return !table.userIsBanned(name);
} }
@Override @Override