Merge branch 'master' into master
44
.forgejo/workflows/release.yml
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
|
||||
concurrency:
|
||||
group: "release"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
example-docker-compose:
|
||||
runs-on: node-debian
|
||||
container:
|
||||
image: maven:3-eclipse-temurin-11
|
||||
steps:
|
||||
- name: Install prerequisites
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get -y install git nodejs
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Build Mage
|
||||
run: |
|
||||
mvn -T 12 clean install -DskipTests
|
||||
|
||||
- name: Build Client
|
||||
run: |
|
||||
cd Mage.Client && mvn package assembly:single
|
||||
|
||||
- name: Build Server
|
||||
run: |
|
||||
cd Mage.Server && mvn package assembly:single
|
||||
|
||||
- uses: forgejo/upload-artifact@v4
|
||||
with:
|
||||
name: client.zip
|
||||
path: ./Mage.Client/target/mage-client.zip
|
||||
|
||||
- uses: forgejo/upload-artifact@v4
|
||||
with:
|
||||
name: server.zip
|
||||
path: ./Mage.Server/target/mage-server.zip
|
||||
|
||||
10
.github/dependabot.yml
vendored
|
|
@ -1,10 +0,0 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: 'github-actions'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
- package-ecosystem: 'maven'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
23
.github/labeler.yml
vendored
|
|
@ -1,23 +0,0 @@
|
|||
dev:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: [ '*', 'Utils/**', '/.github/**' ]
|
||||
|
||||
engine:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: [ 'Mage/**' ]
|
||||
|
||||
client:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: [ 'Mage.Client/**', 'Mage.Common/**', 'Mage.Plugins/**' ]
|
||||
|
||||
server:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: [ 'Mage.Server*/**' ]
|
||||
|
||||
tests:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: [ 'Mage.Verify/**', 'Mage.Tests/**', 'Mage.Reports/**' ]
|
||||
|
||||
cards:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: [ 'Mage.Sets/**' ]
|
||||
15
.github/workflows/labeler-auto.yml
vendored
|
|
@ -1,15 +0,0 @@
|
|||
name: "Pull Request Labeler (auto)"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: label-the-PR
|
||||
uses: actions/labeler@v5
|
||||
with:
|
||||
configuration-path: '.github/labeler.yml'
|
||||
24
.github/workflows/labeler-manual.yml
vendored
|
|
@ -1,24 +0,0 @@
|
|||
name: "Pull Request Labeler (manual)"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
oldPRs:
|
||||
# no multi lines support, so call by single PR only
|
||||
description: 'PR number to process'
|
||||
required: true
|
||||
type: string
|
||||
default: '123'
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: label-the-PR
|
||||
uses: actions/labeler@v5
|
||||
with:
|
||||
configuration-path: '.github/labeler.yml'
|
||||
pr-number: |
|
||||
${{ github.event.inputs.oldPRs }}
|
||||
21
.github/workflows/mtg-fetch-cards.yml
vendored
|
|
@ -1,21 +0,0 @@
|
|||
name: Mtg Card Fetch Bot
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
fetch-card-references:
|
||||
name: Fetch MTG Card
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: ldeluigi/mtg-fetch-action@v1
|
||||
1
.gitignore
vendored
|
|
@ -61,3 +61,4 @@ Utils/*implemented.txt
|
|||
# build tools
|
||||
mage-bundle.zip
|
||||
.env
|
||||
.classpath
|
||||
|
|
|
|||
36
Dockerfile
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
FROM eclipse-temurin:11
|
||||
|
||||
# Set XMage config defaults
|
||||
ENV LANG=C.UTF-8 \
|
||||
XMAGE_DOCKER_SERVER_ADDRESS="0.0.0.0" \
|
||||
XMAGE_DOCKER_PORT="17171" \
|
||||
XMAGE_DOCKER_SEONDARY_BIND_PORT="17179" \
|
||||
XMAGE_DOCKER_MAX_SECONDS_IDLE="600" \
|
||||
XMAGE_DOCKER_AUTHENTICATION_ACTIVATED="false" \
|
||||
XMAGE_DOCKER_SERVER_NAME="mage-server" \
|
||||
XMAGE_DOCKER_MAILGUN_API_KEY="" \
|
||||
XMAGE_DOCKER_MAILGUN_DOMAIN="" \
|
||||
XMAGE_DOCKER_MAIL_SMTP_HOST="" \
|
||||
XMAGE_DOCKER_MAIL_SMTP_PORT="" \
|
||||
XMAGE_DOCKER_MAIL_USER="" \
|
||||
XMAGE_DOCKER_MAIL_PASSWORD="" \
|
||||
XMAGE_DOCKER_MAIL_FROM_ADDRESS="" \
|
||||
XMAGE_DOCKER_MAX_GAME_THREADS="10" \
|
||||
XMAGE_DOCKER_MAX_AI_OPPONENTS="15" \
|
||||
XMAGE_DOCKER_JAVA_OPTS="-Xmx1024m -XX:MaxPermSize=384m -Dlog4j.configuration=file:./config/log4j.properties"
|
||||
# Install dependencies
|
||||
RUN set -ex && \
|
||||
apt update && \
|
||||
apt install -y curl ca-certificates bash jq unzip
|
||||
|
||||
# Download latest xmage
|
||||
WORKDIR /xmage
|
||||
|
||||
RUN <<EOF
|
||||
wget $(curl -Ls -o /dev/null -w %{url_effective} "https://git.cef.icu/Failure/foul-magics/actions/runs/latest" | sed 's/$/\/artifacts\/server.zip/')
|
||||
unzip server.zip
|
||||
unzip mage-server.zip
|
||||
rm server.zip mage-server.zip
|
||||
EOF
|
||||
|
||||
CMD ["./dockerRun.sh"]
|
||||
|
|
@ -90,7 +90,7 @@ import java.util.stream.Collectors;
|
|||
*/
|
||||
public class MageFrame extends javax.swing.JFrame implements MageClient {
|
||||
|
||||
private static final String TITLE_NAME = "XMage";
|
||||
private static final String TITLE_NAME = "XMage (Foul Magics)";
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(MageFrame.class);
|
||||
private static final String LITE_MODE_ARG = "-lite";
|
||||
|
|
@ -297,14 +297,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
|||
errorDialog.setLocation(100, 100);
|
||||
desktopPane.add(errorDialog, errorDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
|
||||
|
||||
try {
|
||||
this.whatsNewDialog = new WhatsNewDialog();
|
||||
} catch (Throwable e) {
|
||||
// example: JavaFX is not supported on old MacOS with OpenJDK
|
||||
// https://bugs.openjdk.java.net/browse/JDK-8202132
|
||||
LOGGER.error("JavaFX is not supported by your system. What's new page will be disabled.", e);
|
||||
this.whatsNewDialog = null;
|
||||
}
|
||||
|
||||
PING_SENDER_EXECUTOR.scheduleAtFixedRate(SessionHandler::ping, TablesPanel.PING_SERVER_SECS, TablesPanel.PING_SERVER_SECS, TimeUnit.SECONDS);
|
||||
|
||||
|
|
@ -385,11 +377,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
|||
|
||||
setWindowTitle(); // make sure title is actual on startup
|
||||
});
|
||||
|
||||
// run what's new checks (loading in background)
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
showWhatsNewDialog(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public enum MageTray {
|
|||
private Image flashedImage;
|
||||
private TrayIcon trayIcon;
|
||||
|
||||
private int state = 0;
|
||||
private int state = 3;
|
||||
|
||||
public void install() {
|
||||
if (!SystemTray.isSupported()) {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,15 @@ package mage.client.constants;
|
|||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import javafx.util.Pair;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -14,6 +20,36 @@ public final class Constants {
|
|||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static final ImmutableList<Pair<String, String[]>> foulMagicsSets = ImmutableList.of(
|
||||
new Pair<String, String[]>("Set 2 - Phyrexians, Eldrazi, Asians - Oh my!", new String[] {
|
||||
"* March of the Machine Block",
|
||||
"* Phyrexia: All Will Be One Block",
|
||||
"* The Brothers' War Block",
|
||||
"* Dominaria United Block",
|
||||
"* Kamigawa: Neon Dynasty Block",
|
||||
"* Theros Beyond Death Block",
|
||||
"* Strixhaven: School of Mages Block",
|
||||
"* The Lost Caverns of Ixalan Block",
|
||||
"* Ikoria: Lair of Behemoths Block",
|
||||
"* Adventures in the Forgotten Realms Block",
|
||||
"Modern Horizons 3",
|
||||
"The Lord of the Rings: Tales of Middle-earth",
|
||||
"Double Masters 2022",
|
||||
"Rise of the Eldrazi",
|
||||
"Modern Horizons 2"
|
||||
}),
|
||||
new Pair<String, String[]>("Set 1 - In Da Beegeening", new String[] {
|
||||
"* Foundations Block",
|
||||
"* Guilds of Ravnica Block",
|
||||
"* Return to Ravnica Block",
|
||||
}),
|
||||
new Pair<String, String[]>("Set 0.5 - Foundationally Gaming", new String[] {
|
||||
"* Foundations Block",
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
|
||||
public static final int FRAME_MAX_HEIGHT = 367;
|
||||
public static final int FRAME_MAX_WIDTH = 256;
|
||||
public static final int ART_MAX_HEIGHT = 168;
|
||||
|
|
@ -144,5 +180,6 @@ public final class Constants {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ public class DeckGeneratorDialog {
|
|||
c.ipadx = 30;
|
||||
c.insets = new Insets(5, 10, 0, 10);
|
||||
c.weightx = 0.90;
|
||||
cbDeckSize = new JComboBox<>(new String[]{"40", "60"});
|
||||
cbDeckSize = new JComboBox<>(new String[]{"40", "60", "100"});
|
||||
cbDeckSize.setSelectedIndex(0);
|
||||
cbDeckSize.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
mainPanel.add(cbDeckSize, c);
|
||||
|
|
|
|||
|
|
@ -222,6 +222,46 @@
|
|||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnExpansionSearchActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="cbFoulMagicPresets">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[120, 20]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[120, 20]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[120, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbFoulMagicPresetSelected"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="FoulMagicPreset"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="btnFoulMagicPreset">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/buttons/brick.png"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Set to Foul Magic preset"/>
|
||||
<Property name="alignmentX" type="float" value="1.0"/>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[23, 23]"/>
|
||||
</Property>
|
||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFoulMagicPresetSet"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JToolBar$Separator" name="jSeparator2">
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="chkPennyDreadful">
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import mage.cards.decks.PennyDreadfulLegalityUtil;
|
|||
import mage.cards.repository.*;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.cards.*;
|
||||
import mage.client.constants.Constants;
|
||||
import mage.client.constants.Constants.SortBy;
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
import mage.client.deckeditor.table.TableModel;
|
||||
|
|
@ -31,6 +32,8 @@ import mage.view.CardsView;
|
|||
import org.apache.log4j.Logger;
|
||||
import org.mage.card.arcane.ManaSymbolsCellRenderer;
|
||||
|
||||
import javafx.util.Pair;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import java.awt.*;
|
||||
|
|
@ -237,26 +240,44 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
|
||||
if (limited) {
|
||||
List<Predicate<MageObject>> predicates = new ArrayList<>();
|
||||
List<Predicate<MageObject>> exclusion = new ArrayList<>();
|
||||
|
||||
if (this.tbGreen.isSelected()) {
|
||||
predicates.add(new ColorPredicate(ObjectColor.GREEN));
|
||||
} else {
|
||||
exclusion.add(new ColorPredicate(ObjectColor.GREEN));
|
||||
}
|
||||
if (this.tbRed.isSelected()) {
|
||||
predicates.add(new ColorPredicate(ObjectColor.RED));
|
||||
} else {
|
||||
exclusion.add(new ColorPredicate(ObjectColor.RED));
|
||||
}
|
||||
if (this.tbBlack.isSelected()) {
|
||||
predicates.add(new ColorPredicate(ObjectColor.BLACK));
|
||||
} else {
|
||||
exclusion.add(new ColorPredicate(ObjectColor.BLACK));
|
||||
}
|
||||
if (this.tbBlue.isSelected()) {
|
||||
predicates.add(new ColorPredicate(ObjectColor.BLUE));
|
||||
} else {
|
||||
exclusion.add(new ColorPredicate(ObjectColor.BLUE));
|
||||
}
|
||||
if (this.tbWhite.isSelected()) {
|
||||
predicates.add(new ColorPredicate(ObjectColor.WHITE));
|
||||
} else {
|
||||
exclusion.add(new ColorPredicate(ObjectColor.WHITE));
|
||||
}
|
||||
|
||||
if (this.tbColorless.isSelected()) {
|
||||
predicates.add(ColorlessPredicate.instance);
|
||||
} else {
|
||||
exclusion.add(ColorlessPredicate.instance);
|
||||
}
|
||||
if (this.tbLimitColors.isSelected()) {
|
||||
filter.add(Predicates.and(Predicates.not(Predicates.or(exclusion)), Predicates.or(predicates)));
|
||||
} else {
|
||||
filter.add(Predicates.or(predicates));
|
||||
}
|
||||
filter.add(Predicates.or(predicates));
|
||||
|
||||
predicates.clear();
|
||||
if (this.tbLand.isSelected()) {
|
||||
|
|
@ -346,6 +367,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
criteria.red(this.tbRed.isSelected());
|
||||
criteria.white(this.tbWhite.isSelected());
|
||||
criteria.colorless(this.tbColorless.isSelected());
|
||||
criteria.limitColors(this.tbLimitColors.isSelected());
|
||||
|
||||
// if you add new type filter then sync it with CardType
|
||||
if (this.tbLand.isSelected()) {
|
||||
|
|
@ -559,9 +581,12 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
tbBlack = new javax.swing.JToggleButton();
|
||||
tbWhite = new javax.swing.JToggleButton();
|
||||
tbColorless = new javax.swing.JToggleButton();
|
||||
tbLimitColors = new javax.swing.JToggleButton();
|
||||
jSeparator1 = new javax.swing.JToolBar.Separator();
|
||||
cbExpansionSet = new javax.swing.JComboBox<>();
|
||||
btnExpansionSearch = new javax.swing.JButton();
|
||||
cbFoulMagicPresets = new javax.swing.JComboBox<>();
|
||||
btnFoulMagicPreset = new javax.swing.JButton();
|
||||
jSeparator2 = new javax.swing.JToolBar.Separator();
|
||||
chkPennyDreadful = new javax.swing.JCheckBox();
|
||||
btnBooster = new javax.swing.JButton();
|
||||
|
|
@ -701,6 +726,23 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
}
|
||||
});
|
||||
tbColor.add(tbColorless);
|
||||
|
||||
tbLimitColors.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/lock.png"))); // NOI18N
|
||||
tbLimitColors.setSelected(false);
|
||||
tbLimitColors.setToolTipText("Limit results to ONLY these colors");
|
||||
tbLimitColors.setActionCommand("LimitColors");
|
||||
tbLimitColors.setFocusable(false);
|
||||
tbLimitColors.setPreferredSize(new java.awt.Dimension(28, 28));
|
||||
tbLimitColors.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||
tbLimitColors.setSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/lock.png"))); // NOI18N
|
||||
tbLimitColors.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||
tbLimitColors.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
tbLimitColorsActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
tbColor.add(tbLimitColors);
|
||||
|
||||
tbColor.add(jSeparator1);
|
||||
|
||||
reloadSetsCombobox();
|
||||
|
|
@ -741,6 +783,31 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
}
|
||||
});
|
||||
tbColor.add(btnExpansionSearch);
|
||||
|
||||
List<String> setNames = new LinkedList<String>();
|
||||
for (Pair<String, String[]> pair : Constants.foulMagicsSets) {
|
||||
setNames.add(pair.getKey());
|
||||
}
|
||||
|
||||
DefaultComboBoxModel presetModel = new DefaultComboBoxModel<>(setNames.toArray());
|
||||
cbFoulMagicPresets.setModel(presetModel);
|
||||
|
||||
tbColor.add(cbFoulMagicPresets);
|
||||
|
||||
btnFoulMagicPreset.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/brick.png"))); // NOI18N
|
||||
btnFoulMagicPreset.setToolTipText("Set to Foul Magic preset");
|
||||
btnFoulMagicPreset.setAlignmentX(1.0F);
|
||||
btnFoulMagicPreset.setFocusable(false);
|
||||
btnFoulMagicPreset.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||
btnFoulMagicPreset.setPreferredSize(new java.awt.Dimension(24, 24));
|
||||
btnFoulMagicPreset.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||
btnFoulMagicPreset.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
btnFoulMagicPresetSet(evt);
|
||||
}
|
||||
});
|
||||
tbColor.add(btnFoulMagicPreset);
|
||||
|
||||
tbColor.add(jSeparator2);
|
||||
|
||||
chkPennyDreadful.setText("Penny Dreadful Only");
|
||||
|
|
@ -1421,7 +1488,11 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
private void tbColorlessActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbColorlessActionPerformed
|
||||
filterCardsColor(evt.getModifiers(), evt.getActionCommand());
|
||||
}//GEN-LAST:event_tbColorlessActionPerformed
|
||||
|
||||
|
||||
private void tbLimitColorsActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbColorlessActionPerformed
|
||||
filterCards();
|
||||
}
|
||||
|
||||
private void tbCreaturesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbCreaturesActionPerformed
|
||||
filterCardsType(evt.getModifiers(), evt.getActionCommand());
|
||||
}//GEN-LAST:event_tbCreaturesActionPerformed
|
||||
|
|
@ -1465,6 +1536,33 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
private void chkUniqueActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkRulesActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_chkRulesActionPerformed
|
||||
|
||||
private void btnFoulMagicPresetSet(java.awt.event.ActionEvent evt) {
|
||||
reloadSetsCombobox();
|
||||
if (cbExpansionSet.getItemAt(0).startsWith(MULTI_SETS_SELECTION_TEXT)) {
|
||||
cbExpansionSet.removeItemAt(0);
|
||||
}
|
||||
|
||||
listCodeSelected.uncheckAll();
|
||||
String[] selectedFormats = Constants.foulMagicsSets.get(this.cbFoulMagicPresets.getSelectedIndex()).getValue();
|
||||
if (selectedFormats.length == 1) {
|
||||
this.cbExpansionSet.setSelectedItem(selectedFormats[0]);
|
||||
filterCards();
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> formats = ConstructedFormats.getTypes(false);
|
||||
for (int i = 0; i < formats.size(); i++) {
|
||||
if (Arrays.stream(selectedFormats).anyMatch(formats.get(i)::equals)) {
|
||||
listCodeSelected.setChecked(i - 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
String message = String.format("%s: %s", MULTI_SETS_SELECTION_TEXT, "[Foul Magics]");
|
||||
cbExpansionSet.insertItemAt(message, 0);
|
||||
cbExpansionSet.setSelectedIndex(0);
|
||||
filterCards();
|
||||
}
|
||||
|
||||
private void btnExpansionSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExpansionSearchActionPerformed
|
||||
// search and check multiple items
|
||||
|
|
@ -1505,6 +1603,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
isSetsFilterLoading = false;
|
||||
}
|
||||
|
||||
|
||||
// update data
|
||||
filterCards();
|
||||
});
|
||||
|
|
@ -1575,12 +1674,14 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
private javax.swing.JButton btnBooster;
|
||||
private javax.swing.JButton btnClear;
|
||||
private javax.swing.JButton btnExpansionSearch;
|
||||
private javax.swing.JButton btnFoulMagicPreset;
|
||||
private javax.swing.JLabel cardCount;
|
||||
private javax.swing.JLabel cardCountLabel;
|
||||
private javax.swing.JPanel cardSelectorBottomPanel;
|
||||
private javax.swing.JScrollPane cardSelectorScrollPane;
|
||||
private javax.swing.JComboBox<String> cbExpansionSet;
|
||||
private javax.swing.JComboBox<SortBy> cbSortBy;
|
||||
private javax.swing.JComboBox<SortBy> cbFoulMagicPresets;
|
||||
private javax.swing.JCheckBox chkNames;
|
||||
private javax.swing.JCheckBox chkPennyDreadful;
|
||||
private javax.swing.JCheckBox chkPiles;
|
||||
|
|
@ -1607,6 +1708,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
private javax.swing.JToggleButton tbBlue;
|
||||
private javax.swing.JToolBar tbColor;
|
||||
private javax.swing.JToggleButton tbColorless;
|
||||
private javax.swing.JToggleButton tbLimitColors;
|
||||
private javax.swing.JToggleButton tbCommon;
|
||||
private javax.swing.JToggleButton tbCreatures;
|
||||
private javax.swing.JToggleButton tbEnchantments;
|
||||
|
|
|
|||
|
|
@ -329,6 +329,7 @@ public class ConnectDialog extends MageDialog {
|
|||
});
|
||||
|
||||
btnFindBeta.setText("BETA");
|
||||
btnFindBeta.setEnabled(false);
|
||||
btnFindBeta.setToolTipText("Connect to BETA server, AI disabled (use any username without registration)");
|
||||
btnFindBeta.setAlignmentY(0.0F);
|
||||
btnFindBeta.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ public class DownloadImagesDialog extends MageDialog {
|
|||
comboSets = new javax.swing.JComboBox<>();
|
||||
fillerMode1 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767));
|
||||
buttonSearchSet = new javax.swing.JButton();
|
||||
|
||||
panelRedownload = new javax.swing.JPanel();
|
||||
checkboxRedownload = new javax.swing.JCheckBox();
|
||||
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 3), new java.awt.Dimension(32767, 5));
|
||||
|
|
@ -354,8 +355,9 @@ public class DownloadImagesDialog extends MageDialog {
|
|||
buttonSearchSetActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
panelModeSelect.add(buttonSearchSet);
|
||||
|
||||
|
||||
panelModeInner.add(panelModeSelect);
|
||||
|
||||
panelMode.add(panelModeInner);
|
||||
|
|
@ -426,7 +428,7 @@ public class DownloadImagesDialog extends MageDialog {
|
|||
private void buttonSearchSetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonSearchSetActionPerformed
|
||||
FastSearchUtil.showFastSearchForStringComboBox(comboSets, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE, 400, 500);
|
||||
}//GEN-LAST:event_buttonSearchSetActionPerformed
|
||||
|
||||
|
||||
private void buttonStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonStopActionPerformed
|
||||
// TODO implement stop feature for cancel button
|
||||
}//GEN-LAST:event_buttonStopActionPerformed
|
||||
|
|
|
|||
BIN
Mage.Client/src/main/resources/buttons/brick.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
Mage.Client/src/main/resources/buttons/lock.png
Normal file
|
After Width: | Height: | Size: 304 B |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 595 B After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 831 B After Width: | Height: | Size: 5 KiB |
|
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 6.3 KiB |
|
|
@ -47,7 +47,7 @@
|
|||
socketWriteTimeout="10000"
|
||||
maxGameThreads="10"
|
||||
maxSecondsIdle="300"
|
||||
minUserNameLength="3"
|
||||
minUserNameLength="1"
|
||||
maxUserNameLength="14"
|
||||
invalidUserNamePattern="[^a-z0-9_]"
|
||||
minPasswordLength="8"
|
||||
|
|
@ -63,6 +63,8 @@
|
|||
mailUser=""
|
||||
mailPassword=""
|
||||
mailFromAddress=""
|
||||
httpAuth="false"
|
||||
authUrl=""
|
||||
/>
|
||||
<playerTypes>
|
||||
<playerType name="Human" jar="mage-player-human.jar" className="mage.player.human.HumanPlayer"/>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@
|
|||
mailUser=""
|
||||
mailPassword=""
|
||||
mailFromAddress=""
|
||||
httpAuth="false"
|
||||
authUrl=""
|
||||
/>
|
||||
<playerTypes>
|
||||
<playerType name="Human" jar="mage-player-human-${project.version}.jar" className="mage.player.human.HumanPlayer"/>
|
||||
|
|
@ -1,36 +1,36 @@
|
|||
#SAMPLE SERVER CONFIG (you must enable it by command line)
|
||||
|
||||
#default log level and active appenders (dest for logs)
|
||||
log4j.rootLogger=info, console, logfile
|
||||
|
||||
#custom log level for java classes
|
||||
log4j.logger.com.j256.ormlite=warn
|
||||
#log4j.logger.mage.player.ai=warn
|
||||
|
||||
#console log
|
||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.console.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %-90m =>[%t] %C{1}.%M %n
|
||||
log4j.appender.console.Threshold=info
|
||||
|
||||
#file log - without rolling
|
||||
log4j.appender.logfile=org.apache.log4j.FileAppender
|
||||
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.logfile.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %-90m =>[%t] %C{1}.%M %n
|
||||
log4j.appender.logfile.File=mageserver.log
|
||||
|
||||
#file log - rolling by index
|
||||
log4j.appender.logfileByIndex=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.logfileByIndex.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.logfileByIndex.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %-90m =>[%t] %C{1}.%M %n
|
||||
log4j.appender.logfileByIndex.File=mageserver.log
|
||||
log4j.appender.logfileByIndex.MaxFileSize=10MB
|
||||
log4j.appender.logfileByIndex.MaxBackupIndex=5
|
||||
log4j.appender.logfileByIndex.append=true
|
||||
|
||||
#file log - rolling by dayly
|
||||
log4j.appender.logfileByDayly=org.apache.log4j.DailyRollingFileAppender
|
||||
log4j.appender.logfileByDayly.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.logfileByDayly.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %-90m =>[%t] %C{1}.%M %n
|
||||
log4j.appender.logfileByDayly.File=mageserver.log
|
||||
#SAMPLE SERVER CONFIG (you must enable it by command line)
|
||||
|
||||
#default log level and active appenders (dest for logs)
|
||||
log4j.rootLogger=info, console, logfile
|
||||
|
||||
#custom log level for java classes
|
||||
log4j.logger.com.j256.ormlite=warn
|
||||
#log4j.logger.mage.player.ai=warn
|
||||
|
||||
#console log
|
||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.console.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %-90m =>[%t] %C{1}.%M %n
|
||||
log4j.appender.console.Threshold=info
|
||||
|
||||
#file log - without rolling
|
||||
log4j.appender.logfile=org.apache.log4j.FileAppender
|
||||
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.logfile.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %-90m =>[%t] %C{1}.%M %n
|
||||
log4j.appender.logfile.File=mageserver.log
|
||||
|
||||
#file log - rolling by index
|
||||
log4j.appender.logfileByIndex=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.logfileByIndex.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.logfileByIndex.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %-90m =>[%t] %C{1}.%M %n
|
||||
log4j.appender.logfileByIndex.File=mageserver.log
|
||||
log4j.appender.logfileByIndex.MaxFileSize=10MB
|
||||
log4j.appender.logfileByIndex.MaxBackupIndex=5
|
||||
log4j.appender.logfileByIndex.append=true
|
||||
|
||||
#file log - rolling by dayly
|
||||
log4j.appender.logfileByDayly=org.apache.log4j.DailyRollingFileAppender
|
||||
log4j.appender.logfileByDayly.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.logfileByDayly.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %-90m =>[%t] %C{1}.%M %n
|
||||
log4j.appender.logfileByDayly.File=mageserver.log
|
||||
log4j.appender.logfileByDayly.DatePattern='.'yyyy-MM-dd
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
grant {
|
||||
permission java.security.AllPermission;
|
||||
grant {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
|
@ -64,6 +64,7 @@ public class AuthorizedUser {
|
|||
public boolean doCredentialsMatch(String name, String password) {
|
||||
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(this.hashAlgorithm);
|
||||
matcher.setHashIterations(this.hashIterations);
|
||||
|
||||
AuthenticationToken token = new UsernamePasswordToken(name, password);
|
||||
AuthenticationInfo info = new SimpleAuthenticationInfo(this.name,
|
||||
ByteSource.Util.bytes(Base64.decode(this.password)),
|
||||
|
|
|
|||
|
|
@ -368,9 +368,10 @@ public final class Main {
|
|||
if (throwable instanceof ClientDisconnectedException) {
|
||||
// client called a disconnect command (full disconnect without tables keep)
|
||||
// no need to keep session
|
||||
// the above i think is a lie
|
||||
logger.info("CLIENT DISCONNECTED - " + sessionInfo);
|
||||
logger.debug("- cause: client called disconnect command");
|
||||
managerFactory.sessionManager().disconnect(client.getSessionId(), DisconnectReason.DisconnectedByUser, true);
|
||||
managerFactory.sessionManager().disconnect(client.getSessionId(), DisconnectReason.LostConnection, true);
|
||||
} else if (throwable == null) {
|
||||
// lease timeout (ping), so server lost connection with a client
|
||||
// must keep tables
|
||||
|
|
|
|||
|
|
@ -18,6 +18,17 @@ import org.jboss.remoting.callback.Callback;
|
|||
import org.jboss.remoting.callback.HandleCallbackException;
|
||||
import org.jboss.remoting.callback.InvokerCallbackHandler;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
|
@ -152,8 +163,8 @@ public class Session {
|
|||
if (userName.length() > config.getMaxUserNameLength()) {
|
||||
return "User name may not be longer than " + config.getMaxUserNameLength() + " characters";
|
||||
}
|
||||
if (userName.length() <= 3) {
|
||||
return "User name is too short (3 characters or fewer)";
|
||||
if (userName.length() <= 1) {
|
||||
return "User name is too short (1 characters or fewer)";
|
||||
}
|
||||
if (userName.length() >= 500) {
|
||||
return "User name is too long (500 characters or more)";
|
||||
|
|
@ -242,6 +253,7 @@ public class Session {
|
|||
|
||||
// find auth user
|
||||
AuthorizedUser authorizedUser = null;
|
||||
|
||||
if (managerFactory.configSettings().isAuthenticationActivated()) {
|
||||
authorizedUser = AuthorizedUserRepository.getInstance().getByName(userName);
|
||||
String errorMsg = "Wrong username or password. You must register your account first.";
|
||||
|
|
@ -267,6 +279,51 @@ public class Session {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (managerFactory.configSettings().isHttpAuth()) {
|
||||
try {
|
||||
JsonObject body = new JsonObject();
|
||||
body.addProperty("token", password);
|
||||
body.addProperty("username", userName);
|
||||
|
||||
String json = body.toString();
|
||||
|
||||
URL url = new URL(managerFactory.configSettings().getAuthUrl());
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Content-Length", Integer.toString(json.length()));
|
||||
conn.setRequestProperty("User-Agent", "Tainted-Mage/1.0");
|
||||
|
||||
conn.setDoOutput(true);
|
||||
|
||||
|
||||
OutputStream os = conn.getOutputStream();
|
||||
os.write(json.getBytes());
|
||||
os.flush();
|
||||
os.close();
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
|
||||
String resp = in.readLine();
|
||||
in.close();
|
||||
JsonElement response = JsonParser.parseString(resp);
|
||||
if (response.isJsonObject() && response.getAsJsonObject().has("success") && response.getAsJsonObject().get("success").getAsBoolean()) {
|
||||
// s'all good, man
|
||||
} else {
|
||||
return "Failed to authenticate";
|
||||
}
|
||||
} else {
|
||||
return "Failed to authenticate: " + Integer.toString(responseCode);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return "Error with external authentication. Please try again later.";
|
||||
}
|
||||
}
|
||||
|
||||
// create new user instance (auth or anon)
|
||||
boolean isReconnection = false;
|
||||
|
|
|
|||
|
|
@ -69,4 +69,8 @@ public interface ConfigSettings {
|
|||
List<Plugin> getDraftCubes();
|
||||
|
||||
List<Plugin> getDeckTypes();
|
||||
|
||||
boolean isHttpAuth();
|
||||
|
||||
String getAuthUrl();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ public enum UserStatsRepository {
|
|||
|
||||
TableUtils.createTableIfNotExists(connectionSource, UserStats.class);
|
||||
statsDao = DaoManager.createDao(connectionSource, UserStats.class);
|
||||
statsDao.executeRaw("PRAGMA journal_mode=WAL;");
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(UserStatsRepository.class).error("Error creating user_stats repository - ", ex);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,18 +19,21 @@
|
|||
<xs:attribute name="serverAddress" type="xs:string" use="required"/>
|
||||
<xs:attribute name="serverName" type="xs:string" use="required"/>
|
||||
<xs:attribute name="port" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="secondaryBindPort" type="xs:integer" use="required"/>
|
||||
<xs:attribute name="backlogSize" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="numAcceptThreads" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="maxPoolSize" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="leasePeriod" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="secondaryBindPort" type="xs:integer" use="required"/>
|
||||
<xs:attribute name="backlogSize" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="numAcceptThreads" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="maxPoolSize" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="leasePeriod" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="maxGameThreads" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="maxSecondsIdle" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="minUserNameLength" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="maxUserNameLength" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="userNamePattern" type="xs:string" use="required"/>
|
||||
<xs:attribute name="maxAiOpponents" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="saveGameActivated" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="minUserNameLength" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="maxUserNameLength" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="userNamePattern" type="xs:string" use="required"/>
|
||||
<xs:attribute name="maxAiOpponents" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="saveGameActivated" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="httpAuth" type="xs:boolean" use="optional" />
|
||||
<xs:attribute name="authUrl" type="xs:string" use="optional"/>
|
||||
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
|
|
|
|||
|
|
@ -142,5 +142,13 @@ public class ConfigWrapper implements ConfigSettings {
|
|||
public List<Plugin> getDeckTypes() {
|
||||
return config.getDeckTypes().getDeckType();
|
||||
}
|
||||
|
||||
public boolean isHttpAuth() {
|
||||
return config.getServer().isHttpAuth();
|
||||
}
|
||||
|
||||
public String getAuthUrl() {
|
||||
return config.getServer().getAuthUrl();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@
|
|||
<xs:attribute name="mailUser" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="mailPassword" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="mailFromAddress" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="httpAuth" type="xs:boolean" use="optional" />
|
||||
<xs:attribute name="authUrl" type="xs:string" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,13 @@ package mage.cards.repository;
|
|||
import com.j256.ormlite.stmt.QueryBuilder;
|
||||
import com.j256.ormlite.stmt.SelectArg;
|
||||
import com.j256.ormlite.stmt.Where;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.predicate.Predicate;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -39,6 +42,7 @@ public class CardCriteria {
|
|||
private boolean red;
|
||||
private boolean white;
|
||||
private boolean colorless;
|
||||
private boolean limitColors;
|
||||
private Integer manaValue;
|
||||
private String sortBy;
|
||||
private Long start;
|
||||
|
|
@ -68,6 +72,12 @@ public class CardCriteria {
|
|||
this.minCardNumber = Integer.MIN_VALUE;
|
||||
this.maxCardNumber = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public CardCriteria limitColors(boolean limitColors) {
|
||||
this.limitColors = limitColors;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CardCriteria black(boolean black) {
|
||||
this.black = black;
|
||||
|
|
@ -311,35 +321,56 @@ public class CardCriteria {
|
|||
clausesCount++;
|
||||
}
|
||||
|
||||
List<String> exclusion = new ArrayList<>();
|
||||
|
||||
int colorClauses = 0;
|
||||
if (black) {
|
||||
where.eq("black", true);
|
||||
colorClauses++;
|
||||
} else {
|
||||
exclusion.add("black");
|
||||
}
|
||||
if (blue) {
|
||||
where.eq("blue", true);
|
||||
colorClauses++;
|
||||
} else {
|
||||
exclusion.add("blue");
|
||||
}
|
||||
if (green) {
|
||||
where.eq("green", true);
|
||||
colorClauses++;
|
||||
} else {
|
||||
exclusion.add("green");
|
||||
}
|
||||
if (red) {
|
||||
where.eq("red", true);
|
||||
colorClauses++;
|
||||
} else {
|
||||
exclusion.add("red");
|
||||
}
|
||||
if (white) {
|
||||
where.eq("white", true);
|
||||
colorClauses++;
|
||||
} else {
|
||||
exclusion.add("white");
|
||||
}
|
||||
if (colorless) {
|
||||
where.eq("black", false).eq("blue", false).eq("green", false).eq("red", false).eq("white", false);
|
||||
where.and(5);
|
||||
colorClauses++;
|
||||
}
|
||||
|
||||
if (colorClauses > 0) {
|
||||
where.or(colorClauses);
|
||||
clausesCount++;
|
||||
|
||||
if (this.limitColors) {
|
||||
for (String color : exclusion) {
|
||||
where.not();
|
||||
where.eq(color, true);
|
||||
clausesCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minCardNumber != Integer.MIN_VALUE) {
|
||||
|
|
|
|||